Skip to main content
Visitor II
January 15, 2017
Question

STM32 SPI receive always shifted 3-4 bytes

  • January 15, 2017
  • 14 replies
  • 6742 views
Posted on January 15, 2017 at 18:50

Hallo,  i use the HAL to program a little test software to transfer data via spi between

two STM32 Nucleo boards.

One board with a STM32L476 sends every 5 ms 74 bytes of data as a spi master with 625 kBit.

Chip select is used as GPIO output. clock is high if idle, CS is low active,

data valid with faling edge of clock.

A secon Nucleo64 should receive this 74 byte, configured as spi slave without NSS usage.

CS is used as an IRQ input with detection of the faling edge. DMA on den and receive, in normal mode.

I have programmed, that with the falling edge IRQ of the CS, the function

HAL_SPI_TransmitReceive_DMA() will be called. On the first NUCLEO i can adjust a time, so

that CS will be low a short time before the data was sent (I tried 50µs).The slave receives data, but the data was shifted. So the first 3 or 4 bytes in my

receive-array will be the last 3-4 bytes of the telegram before. And then the new data was

in the array.

I don't understand that behaviour. Controlled with the logic analyser everything is correct.

Do you know a solution for that?

Best regards

Volker
    This topic has been closed for replies.

    14 replies

    Visitor II
    January 15, 2017
    Posted on January 15, 2017 at 19:53

    Try to disable-enable the spi on both sides before toggling nss to flush the fifos: it could give some clues to the shifted bytes behaviour. Is it 8 or 16 bit transmission? How many bytes are exchanged? Is it 4 or 3 wired communication?

    volker2Author
    Visitor II
    January 15, 2017
    Posted on January 15, 2017 at 19:58

    74 Bytes are exchanged with a 8 Bit transmisson. It is a 4 wire connection. I don`t use nss and i use normal mode, not the fifos.

    How can i disable-enable the SPI with the HAL?

    Super User
    January 15, 2017
    Posted on January 15, 2017 at 21:35

    Do you have

    If you 'clear' the buffer in the receiver (e.g. set it to all 0) and then perform 1 transfer, what do you see in the receiver buffer?

    What is the state of relevant DMA buffers after the transfer?

    JW

    volker2Author
    Visitor II
    January 16, 2017
    Posted on January 16, 2017 at 07:33

    I think 'clear' the buffer is not the solution because the dma transfer thinks that for a complete receive of the 74 byte not all bytes are received. So how can i reset the dma transfer after a complete receive of 74 bytes, so the slave waits for the next correct transfer?

    I will check the DMA buffers and answer you this evening.

    ST Employee
    January 24, 2017
    Posted on January 24, 2017 at 15:06

    Hello,

    You are using a STM32 device with a SPI who include a FIFO.

    To be sure to not retrieve old data, please use 'HAL_SPIEx_FlushRxFifo' function before call a 'HAL_Receive' function. Thanks to this, the FIFO will be flushed (Rx side only), and you will retrieve correct data. (i.e. without shift).

    BRs,

    Julien.

    Visitor II
    March 29, 2017
    Posted on March 29, 2017 at 10:51

    Hi,

    I am having the same problem. I have an STM32F205VE and an STM32F746IG linked using SPI (three wire, software CS) and a GPIO handshake line. I am performing DMA transfers using the HAL_SPI_TransmitReceive_DMA() transfer function but I find that the data received on the master (the F205) is offset by the 3 bytes. The data received on the slave side is fine. I can understand how the rx fifo could cause this problem, but I cannot work out how to resolve it!

    The 

    HAL_SPIEx_FlushRxFifo() does not seem to exist in the HAL anymore. The only reference I can find for it in the whole library is in the stm32_hal_legacy.h file.

    What is the best to flush the fifos? I don't mind accessing the registers directly, I just need some guidance on which bits need to be set/reset to solve this problem. 

    Regards

    Tim

    Visitor II
    November 21, 2017
    Posted on November 21, 2017 at 16:56

    I'm having the same issue too with the STM32L4 configured as SPI slave. My Tx buffer contains {01, 02, 03, 04, 05, 06, 07} When I read 7 bytes repeatedly from the slave I get:

    01 02 03 04 05 06 07

    05 06 07 01 02 03 04

    05 06 07 01 02 03 04

    05 06 07 01 02 03 04

    ...

    Resetting the master doesn't change anything. Resetting the STM32 slave will send the correct first 7 bytes the first time and then repeat.

    Visitor II
    January 20, 2018
    Posted on January 20, 2018 at 05:30

    I am having the same problem. L4 nucleo. If i get < 3 bytes of data there is no shift. If i get more that 3 there is a shift. Start position is at index 3 or 4.

    I did confirm that data is fine in a wire using oscilloscope.

    Ok. I solved mine. I disabled only DMA channels when I didn't need them and no data should have arrived but it did (2 bytes with content of 0x00). Adding this code after TX part before RX part solved my issue:

        while (LL_SPI_GetTxFIFOLevel(SPI3) != LL_SPI_TX_FIFO_EMPTY) ;

        while (LL_SPI_IsActiveFlag_BSY(SPI3)) ;

        while (LL_SPI_GetRxFIFOLevel(SPI3) != LL_SPI_RX_FIFO_EMPTY)

        {

            LL_SPI_ReceiveData8(SPI3);

        }

    I need to change my SPI mode to TX or RX only instead of just enabling/disabling DMA channels.

    Visitor II
    February 20, 2018
    Posted on February 20, 2018 at 01:41

    Volker, did you manage to find a solution to this problem?

    Visitor II
    February 24, 2018
    Posted on February 24, 2018 at 17:37

    I have the same problem. Is anybody having a solution?

    The solution proposed by ST is not working to me, since the condition is based on the RX FIFO status

    SPI_FLAG_FRLVL

    which my code always see it free...

    Visitor II
    July 4, 2018
    Posted on July 04, 2018 at 09:24

    You'll be screwed if you need SPI protocol at SPI slave mode with RX and TX and with DMA and with unpredictable packets lengths....

    The only thing  can help is to set concrete packet length. But  before sending normal  packets, MASTER should send little bit bigger packet as a first packet after system is initiated... If normal packet length = 10 bytes, than first packet from Master should be 10+ x bytes. X depends on your set threshold of SPI FIFO and data settings. Anyway it helps only with slave tx dma, but if you have at same time rx dma, than your rx dma buffer will be unpredictable, there is a quite fishy solution on that with some garbage bytes, but it's a long story...

    Visitor II
    November 6, 2018

    Hello,

    I have kind of similar problem with receiving bytes via SPI and DMA. I am using MASTER MODE and communicating with SPI memory. The data sent by memory to the STM32L152 are correct (on logic analyzer), but STM receives bytes shifted by 3 bytes. I am now using low level drivers, in past I was using in this application HAL and it was working properly.

    Here is detailed description:

    For read data from memory:

    SPI_Receive_DMA(readData, 4);

    SPI_Transmit_DMA(readCmd, 4);

    where basically the contents of this functions is:

    void SPI_Receive_DMA(uint8_t *RxBuffer, uint32_t size) {

    ubReceptionComplete = 0;

    LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);

    LL_DMA_ConfigTransfer(DMA1, LL_DMA_CHANNEL_2,

    LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_NORMAL | LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT

    | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

    LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2, LL_SPI_DMA_GetRegAddr(SPI1), (uint32_t) RxBuffer, LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2));

    LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, size);

    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);

    }

    void SPI_Transmit_DMA(uint8_t *TxBuffer, uint32_t size) {

    ubTransmissionComplete = 0;

    LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_3);

    LL_DMA_ConfigTransfer(DMA1, LL_DMA_CHANNEL_3,

    LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_NORMAL | LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT

    | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

    LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_3, (uint32_t) TxBuffer, LL_SPI_DMA_GetRegAddr(SPI1), LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3));

    LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, size);

    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3);

    }

    With 4B buffer size, it should read 2 data bytes from SPI memory (first 2 bytes are blank, because of STM transmitting the read command to the SPI memory). The 2 data bytes in memory have values 0x19 and 0x1A.

    The STM reads this 4B from SPI/DMA: 0, 0, 0, 0x19

    but it should actually reads: 0, 0, 0x19, 0x1A (this is how the logic analyzer reads it).

    When I try for the second time to read the data from SPI memory, I got: 0x1A, 0, 0, 0x19

    But as I said before, with HAL drivers it works with no problems and now with LL it makes problems (and the SPI and DMA settings is the same). I am suspecting the access to the buffer via DMA (probably the address is somehow incremented from the beginning by +1), but I don't have no idea how to debug this.

    Also could be this a bug of LL drivers?

    Thank you for any help!

    Visitor II
    November 6, 2018

    On Tue, Nov 6, 2018, 13:27 ST Community wrote:

    Visitor II
    January 17, 2019

    I struggled with this problem for about two weeks, the only workaround I could find was building my own set of non-blocking libraries to handle SPI as Slave. Now it works perfectly by using interrupts. The core of the SPI PHY is a shift register. If you understand that concept, you can easily build your own libraries.