2023-11-06 11:07 PM
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);
}
}
2023-11-07 07:35 AM
Hello @oseaw.1
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.
The reason behind this, the software must perform a cache invalidate before reading the updated data from SRAM2.
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().
When disabling the data cache, you must clean the entire cache to ensure that any dirty data is flushed.
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2023-11-07 09:28 PM
SCB_DisableDCache();
SCB_CleanDCache();
2023-11-08 12:44 AM
Hello again,
You need to clean and invalidate the cache lines (it should be aligned to the buffer size), you can simply use
SCB_InvalidateDCache_by_Addr ((uint32_t *)aRxBuffer, BUFFERSIZE);
Make sure that BufferSize parameter is the size of the DMA Rx buffer in bytes.
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2023-11-08 02:15 AM
SPI transmits and receives simultaneously. Before you start SPI TX (line 21), the TX and RX DMA must be already running!
2023-11-15 03:37 PM
Hello,
I was trying to invalidate and clean rxbuffer, and set bits tx and rx requests simultaneously.
But, It was not working. It seems that It's difficult to control dma in STM32H743.
SCB_InvalidateDCache_by_Addr((uint32_t *)RxBuffer, BUFFER_SIZE);
SET_BIT(SPI3_INST->CFG1, SPI_CFG1_TXDMAEN | SPI_CFG1_RXDMAEN);