Skip to main content
Visitor II
February 11, 2025
Solved

STM32h7 SPI DMA communication issues + FIFO Error (FEIF)

  • February 11, 2025
  • 2 replies
  • 2304 views

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?

    This topic has been closed for replies.
    Best answer by Heiko_SM

    > But in your screenshot, NDTR=3, so 0 bytes have been sent, not 1.

    You are right, the screenshot was not made at a good breakpoint. For other people having this issue was the case that only 1 byte have been sent and 2 bytes were still in queue.

     

    > A code bug can cause this. I don't think you've shown enough to spot the bug. Perhaps it's getting called while the transfer is already active.

    I was able to figure out the problem now. The settings of the code above were all working. In the init part, the SPI was enabled before enabling the DMAReq_TX (LL_SPI_EnableDMAReq_TX) and before setting the Transfer Size (LL_SPI_SetTransferSize).

    I am still wondering why it was even working with the wrong order for exaclty 87381 times and then breaking, but at least it is working now.

    2 replies

    Super User
    February 11, 2025

    Here are the possibilities:

    TDK_0-1739282416570.png

     

    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?

    Heiko_SMAuthor
    Visitor II
    February 11, 2025

    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).

    Super User
    February 11, 2025

    > 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.

    Explorer II
    February 11, 2025

    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.