SPI DMA transfer issue on STM32H743
I am reaching out to seek your expertise regarding the DMA transfer issue on SPI that I encountered while using the STM32H743 microcontroller.
When an EXTI LINE 0 event (data ready) occurs, attached to the code is a program in which 30 bytes of 0xFF bytes are transmitted to the DMA Tx buffer, and then 30 bytes are read through the DMA Rx buffer.
The problem is that data is not received properly in the DMA receive buffer. Data continues to circulate at the 7th and 21st indices of the receiving buffer. Except for the two indexes, the remaining buffer space is not filled with anything.
I placed the DMA Rx and Tx buffer to D2 RAM and disabled the data cache of the region. And, Even if I add some delay time before starting the DMA read in Line 7 of EXTI0_IRQHandler(), the data transfer problem still occurs.
However, it seems that the DMA transfer is working normally after stopping and resuming by the breakpoint on Line 7 of EXTI0_IRQHandler().
Please give me advice on which part I should look into more.
Disable D2 RAM region as non cacheable
MPU_Region_InitTypeDef MPU_RegionTypeDef;
HAL_MPU_Disable();
MPU_RegionTypeDef.Enable = MPU_REGION_ENABLE;
MPU_RegionTypeDef.Number = MPU_REGION_NUMBER1;
MPU_RegionTypeDef.BaseAddress = 0x30020000UL;
MPU_RegionTypeDef.Size = MPU_REGION_SIZE_128KB;
MPU_RegionTypeDef.SubRegionDisable = 0x0;
MPU_RegionTypeDef.TypeExtField = MPU_TEX_LEVEL0;
MPU_RegionTypeDef.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_RegionTypeDef.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_RegionTypeDef.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_RegionTypeDef.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_RegionTypeDef.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_RegionTypeDef);
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
Place the RX buffer and TX buffer in D2 RAM region
#if defined (__ICCARM__)
#define DMA_BUFFER \
_Pragma("location=\".D2_dma_buffer\"")
#else
#define DMA_BUFFER \
__attribute__((section(".D2_dma_buffer")))
#endif
#define BUFFER_SIZE 30
DMA_BUFFER uint8_t TxBuffer;
DMA_BUFFER uint8_t RxBuffer[BUFFER_SIZE];
Configure EXTI for Data ready event
EXTI_InitTypeDef.Line_0_31 = LL_EXTI_LINE_0;
EXTI_InitTypeDef.Line_32_63 = LL_EXTI_LINE_NONE;
EXTI_InitTypeDef.Line_64_95 = LL_EXTI_LINE_NONE;
EXTI_InitTypeDef.LineCommand = ENABLE;
EXTI_InitTypeDef.Mode = LL_EXTI_MODE_IT;
EXTI_InitTypeDef.Trigger = LL_EXTI_TRIGGER_FALLING;
LL_EXTI_Init(&EXTI_InitTypeDef);
Configure SPI
SPI_InitTypeDef.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitTypeDef.Mode = LL_SPI_MODE_MASTER;
SPI_InitTypeDef.DataWidth = LL_SPI_DATAWIDTH_8BIT;
SPI_InitTypeDef.ClockPolarity = LL_SPI_POLARITY_LOW;
SPI_InitTypeDef.ClockPhase = LL_SPI_PHASE_2EDGE;
SPI_InitTypeDef.NSS = LL_SPI_NSS_SOFT;
SPI_InitTypeDef.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;
SPI_InitTypeDef.BitOrder = LL_SPI_MSB_FIRST;
SPI_InitTypeDef.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SPI_InitTypeDef.CRCPoly = 0x7;
LL_SPI_Init(SPI3, &SPI_InitTypeDef);
LL_SPI_SetStandard(SPI3, LL_SPI_PROTOCOL_MOTOROLA);
LL_SPI_DisableNSSPulseMgt(SPI3);
LL_SPI_ClearFlag_EOT(SPI3);
LL_SPI_ClearFlag_TXTF(SPI3);
Configure DMA
DMA_InitTypeDef.PeriphOrM2MSrcAddress = (u32)(LL_SPI_DMA_GetRxRegAddr(SPI3));
DMA_InitTypeDef.MemoryOrM2MDstAddress = (u32)(&RxBuffer);
DMA_InitTypeDef.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
DMA_InitTypeDef.Mode = LL_DMA_MODE_CIRCULAR;
DMA_InitTypeDef.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
DMA_InitTypeDef.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
DMA_InitTypeDef.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE;
DMA_InitTypeDef.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
DMA_InitTypeDef.NbData = BUFFER_SIZE;
DMA_InitTypeDef.PeriphRequest = LL_DMAMUX1_REQ_SPI3_RX;
DMA_InitTypeDef.Priority = LL_DMA_PRIORITY_HIGH;
DMA_InitTypeDef.FIFOMode = LL_DMA_FIFOMODE_DISABLE;
DMA_InitTypeDef.FIFOThreshold = LL_DMA_FIFOTHRESHOLD_1_4;
DMA_InitTypeDef.MemBurst = LL_DMA_MBURST_SINGLE;
DMA_InitTypeDef.PeriphBurst = LL_DMA_PBURST_SINGLE;
LL_DMA_Init(DMA1, LL_DMA_STREAM_3, &DMA_InitTypeDef);
LL_DMA_DisableDoubleBufferMode(DMA1, LL_DMA_STREAM_3);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_3);
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);
DMA_InitTypeDef.PeriphOrM2MSrcAddress = (u32)(LL_SPI_DMA_GetTxRegAddr(SPI3));
DMA_InitTypeDef.MemoryOrM2MDstAddress = (u32)(&TxBuffer);
DMA_InitTypeDef.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
DMA_InitTypeDef.Mode = LL_DMA_MODE_NORMAL;
DMA_InitTypeDef.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
DMA_InitTypeDef.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_NOINCREMENT;
DMA_InitTypeDef.PeriphRequest = LL_DMAMUX1_REQ_SPI3_TX;
DMA_InitTypeDef.Priority = LL_DMA_PRIORITY_HIGH;
LL_DMA_Init(DMA1, LL_DMA_STREAM_4, &DMA_InitTypeDef);
LL_DMA_DisableDoubleBufferMode(DMA1, LL_DMA_STREAM_4);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_STREAM_4);
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_4);
NVIC_SetPriority(DMA1_Stream3_IRQn, 9);
NVIC_EnableIRQ(DMA1_Stream3_IRQn);
ISR for EXTI0 Data ready event
void EXTI0_IRQHandler(void)
{
if (LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0) != RESET)
{
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0);
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_3, (uint32_t)&RxBuffer);
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_3, (uint32_t)(LL_SPI_DMA_GetRxRegAddr(SPI3)));
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_3, BUFFER_SIZE);
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_4, BUFFER_SIZE);
LL_SPI_EnableDMAReq_RX(SPI3);
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_3);
LL_SPI_SetTransferSize(SPI3, BUFFER_SIZE);
LL_SPI_Enable(SPI3);
LL_SPI_StartMasterTransfer(SPI3);
LL_SPI_EnableDMAReq_TX(SPI3);
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_4);
}
ISR for DMA1 Rx Stream3
void DMA1_Stream3_IRQHandler(void)
{
if (LL_DMA_IsActiveFlag_TC3(DMA1) != RESET)
{
LL_DMA_ClearFlag_TC3(DMA1);
LL_SPI_DisableDMAReq_RX(SPI3);
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);
LL_SPI_DisableDMAReq_TX(SPI3);
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_4);
ClearDMAFlag(DMA1, LL_DMA_STREAM_3);
ClearDMAFlag(DMA1, LL_DMA_STREAM_4);
LL_SPI_ClearFlag_EOT(SPI3);
LL_SPI_ClearFlag_TXTF(SPI3);
LL_SPI_Disable(SPI3);
}
}