cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 SPI receive always shifted 3-4 bytes

volker2
Associate II
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
19 REPLIES 19
sirpak
Associate II
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...

Posted on February 24, 2018 at 17:41

Disabling/enabling using SPI_CR1_SPE does not flush the FIFO to me. 

d4L die4lie
Associate
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...

anubisis
Associate

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!

S.Ma
Principal

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

HABOT
Associate III

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.

arturro
Associate

I have the same problem. As a solution, I tried to use EXTI interrupt for SS line. Inside the EXTI handler, I call HAL_SPI_Abort just before HAL_SPI_Receive_DMA. Sometimes it helps, but not always.

PJano.1
Associate II

same issues...

Nikolaj_TL
Associate III

I have the same issue on the SPI Slave RxBuffer. It is offset by 4-bytes.

Has anybody resolved the issue?

Yes but a general-case solution requires much more sophisticated synchronization between the SPI Master and Slave than just "Master-asserts-NSS-and-waits-a-while-before-sending".