cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 DMA FIFO + SPI_TX = FIFO error, but work

DVahr.1
Associate II

Good afternoon! I am trying to establish the transmission of data via SPI to the display with DMA. The transmission is working, the display is completely painted over, but the FIFO error flag is set in the DMA registers.

MCU: STM32F401CEU6

 alignas(32) uint16_t buff[80 * 160];
 
    // SPI init
    SPI2->CR1 |= (0b000 << SPI_CR1_BR_Pos) |
                 SPI_CR1_MSTR |
                 SPI_CR1_SSI | SPI_CR1_SSM;
    SPI2->CR2 |= SPI_CR2_TXDMAEN;
    SPI2->CR1 |= SPI_CR1_SPE;
 
    // DMA init
    DMA1_Stream4->CR |= (0b01 << DMA_SxCR_DIR_Pos) |
                        (0 << DMA_SxCR_CHSEL_Pos) |
                        (0b11 << DMA_SxCR_MBURST_Pos) |
                        DMA_SxCR_MINC;
 
    DMA1_Stream4->PAR = (uint32_t)&SPI2->DR;
    DMA1_Stream4->M0AR = (uint32_t)getBuffer();
 
    DMA1_Stream4->FCR &= ~DMA_SxFCR_FTH;
    DMA1_Stream4->FCR |= DMA_SxFCR_DMDIS;
    __DMB();
    DMA1_Stream4->FCR |= (0b11 << DMA_SxFCR_FTH_Pos);
void ST7735s::stopScreenUpdate()
{
    DMA1_Stream4->CR &= ~DMA_SxCR_EN;
    while (DMA2_Stream4->CR & DMA_SxCR_EN)
        ;
    CS_Up();
}
 
 
void ST7735s::startScreenUpdate()
{
    stopScreenUpdate();
    sendCommand(ST77XX_RAMWR);
    CS_Down();
    DC_Up();
    DMA1->HIFCR = DMA_HIFCR_CFEIF4 | DMA_HIFCR_CHTIF4 | DMA_HIFCR_CTCIF4 | DMA_HIFCR_CTEIF4 | DMA_HIFCR_CDMEIF4;
    DMA1_Stream4->NDTR = WIDTH * HEIGHT * 2;
    DMA1_Stream4->CR |= DMA_SxCR_EN;
}

After transmission, the FIFO buffer operation error flag in DMA is set. The flag has to be reset manually + it's not normal somehow.

  • 80 pixels * 160 pixels * 2 bytes = 25,600 bytes. In total, if I understood the logic correctly, with a packet size of 16 chunks, with a chunk size = MSIZE = 1 byte, everything should work, because the configuration is allowed + 25,600 bytes exactly divided into transactions of 16 bytes.
  • I tried to change NDTR - divided by 16, but it didn't help, because it is necessary to specify exactly the number of bytes transmitted. With division by 16, only 1/16 of the display is filled.
  • There is no overwriting (ovverun) either - all pixels take their places
  • There are no SPI errors (Except overrun, since I only use sending)

The alignment was done with a margin. Tried before 4 - no result

1 ACCEPTED SOLUTION

Accepted Solutions

It's not about SPI_CR1.SPE, but about SPI_CR2.TXDMAEN, i.e. gate of signal (which here is equal to SPI_SR.TXE), which goes to DMA. It's set before DMA has chance to fill up its FIFO, that's why it throws the FIFO error.

I recommended to use 32-bit memory-side transfer not because of any error, but because it's more efficient.

JW

View solution in original post

4 REPLIES 4

See AN4031, chapter 4.3 Software sequence to enable DMA.

Also, it's better to use word-wide transfers on the memory side, (MSIZE=0b11) rather than bursts of byte transfers. The FIFO is there to unpack.

JW

DVahr.1
Associate II
void ST7735s::startScreenUpdate()
{
    stopScreenUpdate();
    sendCommand(ST77XX_RAMWR);
    CS_Down();
    DC_Up();
    SPI2->CR1 &= ~SPI_CR1_SPE;
    DMA1->HIFCR = DMA_HIFCR_CFEIF4 | DMA_HIFCR_CHTIF4 | DMA_HIFCR_CTCIF4 | DMA_HIFCR_CTEIF4 | DMA_HIFCR_CDMEIF4;
    DMA1_Stream4->NDTR = WIDTH * HEIGHT * 2;
    DMA1_Stream4->CR |= DMA_SxCR_EN;
    __NOP();
    /*
    NDTR = 25'599   // (-1)
    FS[2:0] = 0b011 // 3/4
    FEIF5 = 1       // error
    */
    SPI2->CR1 |= SPI_CR1_SPE;
}

Modified the function: now before launching

  • disabling SPI
  • enabling DMA
  • enabling SPI

But you can see in the debugger that after enabling DMA, the error flag is still set.

The transmission is working.

Also tried:

  • MSIZE[1:0] = 0b10 (32 bit)
  • MBURST[1:0] = 0b01 (incremental burst of 4 beats)

- also an error.

It's not about SPI_CR1.SPE, but about SPI_CR2.TXDMAEN, i.e. gate of signal (which here is equal to SPI_SR.TXE), which goes to DMA. It's set before DMA has chance to fill up its FIFO, that's why it throws the FIFO error.

I recommended to use 32-bit memory-side transfer not because of any error, but because it's more efficient.

JW

Thank you very much!