2022-11-18 02:03 PM
I'm trying to get the SPI communications to a peripheral handled by the DMA. I have reviewed the STM32L0 reference manual, and LL libraries, as well as close examples. I am able to get Tx operation working properly. However, I cannot get Rx to work. The Rx variable always shows as empty.
I have been trying this operation in loopback mode, with an external connection between MISO and MOSI. Whatever I send should end up in the receiver variable location. However, this does not happen. Instead, the Rx data variable never changes.
Can I get some insight here?
while (1)
{
mdsendBuffer[0] = i;
Configure_DMA();
Activate_SPI();
WaitAndCheckEndOfTransfer();
}
void Configure_DMA(void)
{
/* DMA1 used for SPI1 Transmission
* DMA1 used for SPI1 Reception
*/
uint8_t temp = 0;
/* (1) Enable the clock of DMA1 and DMA1 */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
/* (2) Configure NVIC for DMA transfer complete/error interrupts */
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0); // NVIC_SetPriority(DMA1_Channel3_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
/* (3) Configure the DMA1_Channel2 functional parameters, the Receive Channel */
LL_DMA_ConfigTransfer(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_HIGH
| LL_DMA_MODE_NORMAL | LL_DMA_PERIPH_NOINCREMENT
| LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE
| LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2, LL_SPI_DMA_GetRegAddr(SPI1), (uint32_t)&mdrcvBuffer,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, sizeof(mdsendBuffer));
//LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMA_REQUEST_0); ////////////////
/* (4) Configure the DMA1_Channel3 functional parameters, the Transmit Channel */
LL_DMA_ConfigTransfer(DMA1, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_HIGH
| LL_DMA_MODE_NORMAL | LL_DMA_PERIPH_NOINCREMENT
| LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE
| LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_3, (uint32_t)&mdsendBuffer, LL_SPI_DMA_GetRegAddr(SPI1),
LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, sizeof(mdsendBuffer));
//LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_3, LL_DMA_REQUEST_0); /////////////////
/* (5) Enable DMA interrupts complete/error */
LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableIT_TC (DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableIT_TE (DMA1, LL_DMA_CHANNEL_2);
LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_3);
LL_DMA_EnableIT_TC (DMA1, LL_DMA_CHANNEL_3);
LL_DMA_EnableIT_TE (DMA1, LL_DMA_CHANNEL_3);
}
void Activate_SPI(void)
{
/* Enable SPI1 */
CS_MSA_ON;
LL_SPI_Enable(SPI1);
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
/* Enable DMA Channels */
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3);
}
static void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
LL_SPI_InitTypeDef SPI_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_5;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* SPI1 DMA Init */
/* SPI1_TX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_3, LL_DMA_REQUEST_1);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE);
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;
SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SPI_InitStruct.CRCPoly = 7;
LL_SPI_Init(SPI1, &SPI_InitStruct);
LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
/* USER CODE BEGIN SPI1_Init 2 */
GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
LL_SPI_Enable(SPI1);
LL_SPI_EnableDMAReq_RX(SPI1);
/* Enable DMA TX Interrupt */
LL_SPI_EnableDMAReq_TX(SPI1);
/* USER CODE END SPI1_Init 2 */
}
Solved! Go to Solution.
2022-11-21 04:08 PM
Discovered the problem: TIM2_UP conflicting with SPI1_RX in DMA Channel 2. Didn't notice the conflict as it extended over to the backside of the printout.
2022-11-18 03:52 PM
Polled SPI Rx works?
Read out and check/post content of SPI and DMA registers.
JW
2022-11-21 10:41 AM
DMA1 -> ISR register
DMA1 -> IFCR register
DMA1 -> CCR2 Register
DMA1 -> CNDTR2 Register
DMA1 -> CPAR2
DMA1 -> CMAR2
DMA1 -> CCR3
DMA1 -> CNDTR3
DMA1 -> CMAR3
2022-11-21 10:44 AM
SPI Registers
SPI1 -> CR1
SPI1 -> CR2
SPI1 -> SR
SPI1 -> DR
SPI1 -> CRCPR
SPI1 -> RXCRCR
SPI1 -> TXCRCR
SPI1 -> I2SCFGR
SPI1 -> I2SPR
2022-11-21 10:47 AM
Noticed Behavior:
So in short
2022-11-21 04:08 PM
Discovered the problem: TIM2_UP conflicting with SPI1_RX in DMA Channel 2. Didn't notice the conflict as it extended over to the backside of the printout.
2022-11-22 03:07 PM
Thanks for coming back with the solution. Please select your post as Best so that thread is marked as solved.
JW
2022-11-25 01:29 PM
Thanks JW.
I'm noticing that the SPI CS line stays low for about 72uS, when the communication only takes about 4uS.... The CS is managed in software. Right before setting the DMA to roll, I change the CS. Then, in the DMA RX full interrupt, I change the CS back.
Why does it take as long as it does? How can I make that time shorter? I would like to be able to do communications more often, if possible.