2025-02-11 01:07 AM - edited 2025-02-11 01:08 AM
When using DMA to do a SPI transmit, I found a strange behavior. The problem is, that the communication to the DAC works for a few seconds, depending on the used frequency. After the few seconds only 1 byte instead of 3 bytes are sent and the NSS Pin (Hardware regulated) stays low. You can even see these two data items to transfer in S1NDTR (NDT). I used the approximately same code with Software NSS without any problem.
I also get a DMA FIFO Error (FEIF) directly after starting the DMA stream, even when using DMA circular mode. Not every time but over 50% of the times when the communication is working I get the FEIF. When the communication is not working anymore, I do not get the FEIF anymore.
I found these factors influencing the error:
- Using DMA normal mode/ circular mode -> no difference
- Enabling DMA FIFO -> no difference
- Increase frequency of sending values to the DAC: communication breaks very fast
- Decrease frequency of sending values to the DAC: communication does not break
- Changing Priorities -> no difference
This is my SPI configuration:
/* SPI1 parameter configuration*/
SPI_InitStruct.TransferDirection = LL_SPI_SIMPLEX_TX;
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_2EDGE;
SPI_InitStruct.NSS = LL_SPI_NSS_HARD_OUTPUT;
SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV4;
SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SPI_InitStruct.CRCPoly = 0x0;
LL_SPI_Init(SPI1, &SPI_InitStruct);
LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
LL_SPI_DisableNSSPulseMgt(SPI1);
This is my corresponding DMA config:
167: Dma.SPI1_TX.1.Direction=DMA_MEMORY_TO_PERIPH
168: Dma.SPI1_TX.1.EventEnable=DISABLE
169: Dma.SPI1_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE
170: Dma.SPI1_TX.1.Instance=DMA2_Stream1
171: Dma.SPI1_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE
172: Dma.SPI1_TX.1.MemInc=DMA_MINC_ENABLE
173: Dma.SPI1_TX.1.Mode=DMA_CIRCULAR
174: Dma.SPI1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
175: Dma.SPI1_TX.1.PeriphInc=DMA_PINC_DISABLE
176: Dma.SPI1_TX.1.Polarity=HAL_DMAMUX_REQ_GEN_RISING
177: Dma.SPI1_TX.1.Priority=DMA_PRIORITY_HIGH
178: Dma.SPI1_TX.1.RequestNumber=1
179: Dma.SPI1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
180: Dma.SPI1_TX.1.SignalID=NONE
181: Dma.SPI1_TX.1.SyncEnable=DISABLE
182: Dma.SPI1_TX.1.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
183: Dma.SPI1_TX.1.SyncRequestNumber=1
184: Dma.SPI1_TX.1.SyncSignalID=NONE
This is the code I am using for sending the values to the DAC (shortened it to just the important parts):
dma_buffer_dac1[0] = (COMMAND_SOFTWARE_RESET >> 16);
dma_buffer_dac1[1] = 0;
dma_buffer_dac1[2] = 0 ;
LL_SPI_StartMasterTransfer(DACX->spi); // sets CSTART bit of SPI
LL_DMA_EnableStream(DACX->xdma_tx); // sets EN bit of DMA
while (DACX1_DMA_TX_CHECK_TC_ACTIVE == 0) {} // wait until DMA transfer complete
//Reset transmission flags
LL_DMA_ClearFlag_TC1(DACX1_DMA);
LL_DMA_ClearFlag_HT1(DACX1_DMA);
LL_DMA_ClearFlag_FE1(DACX1_DMA);
while (!LL_SPI_IsActiveFlag_EOT(DACX1.spi){} // wait for SPI End of Transfer
LL_SPI_ClearFlag_EOT(DACX1.spi);
Can anyone help my why the communication breaks?
I am not sure if the FEIF is the problem here, but I am also interested why the FEIF error is showing up?
2025-02-11 06:02 AM
Here are the possibilities:
What else is going on in your program that is using the DMA, particular at same/higher priority levels?
What are the values of the DMA registers when the error occurs?
2025-02-11 07:03 AM
It is bad practice to use DMA for small data amount. On STM32H7A3, it doesn't even run for me on data size less than 8 units. Try to increase buffer size or use interrupt mode for such small buffers.
2025-02-11 07:34 AM - edited 2025-02-11 07:35 AM
At same or higher priority levels there are only other DMA streams running, BDMA interrrupts and the SAI interrupt.
I was now able to find out, that the FEIF should not be the problem of my communication. When I compare the working code for low frequencies with the code for high frequencies the only difference is the transfer error which starts to happen when the communication breaks. I build up a some counters which count up when an interrupt flag raises.
Before the communication breaks:
- transfer_complete_count = half_transfer_count = FEIF_count
- transfer_error_count = 0
- directmode_error_count = 0
When the communication breaks:
- only transfer_error and transfer_complete flags happen
So in the end:
- transfer_complete_count = half_transfer_count + transfer_error_count
I have also attached the values of the DMA2 Stream1 register at the moment my communication breaks (first transfer_error).
2025-02-11 09:49 AM
> 169: Dma.SPI1_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE
You're not using the FIFO, so the FEIF flag is irrelevant here. Not the cause of a problem.
Your DMA stream is disabled, so that's why the SPI isn't clocking in new data. As for why, I'm sure it's a code bug but I don't think it's within the code presented. If things break consistently, should be able to debug and hit pause when it's "broken" and examine why. In the case of what you've presented, it's because DMA stream isn't enabled.
I don't see code where TSIZE is set, so probably EOT isn't happening.