Skip to main content
sirpak
Associate III
February 23, 2018
Solved

SPI RX buffer shifted

  • February 23, 2018
  • 11 replies
  • 4675 views
Posted on February 23, 2018 at 18:10

Dear All,

I use SPI as a master with 2 lines full duplex with DMA on STM32F303RE with 8-bit data size.

Frames are made of variable number of Bytes. Normally SPI clocks out 3 Bytes of command on MOSI line + 4 Bytes of reception which contains the slave answer.

My TX buffer is something like this:

   (CMD)(ADD_H)(ADD_L)(4 Bytes don't care)

My RX buffer will be:

   (3 Bytes don't care, normally 0xFFFFFF)(0x21)(0x43)(0x65)(0x87)

The output on the oscilloscope is perfect, but after a 30 seconds of millions of good communication I find the Rx buffer shifted:

(0x43)(0x65)(0x87)(0xFFFFFF)(0x21) or

(0x65)(0x87)(0xFFFFFF)(0x21)(0x43) or

(0x87)(0xFFFFFF)(0x21)(0x43)(0x65) or

The shifted conditions is kept for some second, then it change. If I let it go, it keep on shifting, till goes back in phase.

Here is the configuration of SPI:

SPI_I2S_DeInit(SPI2);

SPI2->CR1 = SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_Mode_Master | SPI_BaudRatePrescaler_64 | SPI_FirstBit_MSB | SPI_NSS_Soft | SPI_Direction_2Lines_FullDuplex;

SPI2->CR2 = SPI_RxFIFOThreshold_QF | SPI_DataSize_8b | SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx;

Here the configuration of the two DMA channels (channel 4 RX and channel 5 TX):

// DMA channel Rx of SPI Configuration

DMA_DeInit(DMA1_Channel4);

DMA1_Channel4->CCR = DMA_DIR_PeripheralSRC | DMA_Mode_Normal | DMA_PeripheralInc_Disable | DMA_MemoryInc_Enable | DMA_PeripheralDataSize_Byte | DMA_MemoryDataSize_Byte | DMA_Priority_High | DMA_M2M_Disable;

DMA1_Channel4->CNDTR = 0;

DMA1_Channel4->CPAR = (uint32_t)&(SPI2->DR);

DMA1_Channel4->CMAR = (uint32_t)&RxBuffer[0];

// DMA channel Tx of SPI Configuration

DMA_DeInit(DMA1_Channel5);

DMA1_Channel5->CCR = DMA_DIR_PeripheralDST | DMA_Mode_Normal | DMA_PeripheralInc_Disable | DMA_MemoryInc_Enable | DMA_PeripheralDataSize_Byte | DMA_MemoryDataSize_Byte | DMA_Priority_Medium | DMA_M2M_Disable;

DMA1_Channel5->CNDTR = 0;

DMA1_Channel5->CPAR = (uint32_t)&(SPI2->DR);

DMA1_Channel5->CMAR = (uint32_t)&TxBuffer[0];

When I want to transmit and receive I created following function:

if((DMA1_Channel4->CNDTR != 0) || (DMA1_Channel5->CNDTR != 0))

   return 0;

if((SPI2->SR & (SPI_SR_FRLVL | SPI_SR_FTLVL | SPI_I2S_FLAG_RXNE | SPI_I2S_FLAG_BSY))

   return 0;

// Disable the SPI (trying to flush it)

SPI2->CR1 &= ~SPI_CR1_SPE;

// Disable the DMA channels to configure the CNDTR

DMA1_Channel5->CCR &= ~DMA_CCR_EN;

DMA1_Channel4->CCR &= ~DMA_CCR_EN;

// Enable SPI

SPI2->CR1 |= SPI_CR1_SPE;

// Configure odd transfers

SPI2->CR2 &= ~SPI_LastDMATransfer_TxOddRxOdd;

if((Tx_Size + Rx_Size) % 2)

   SPI2->CR2 |= SPI_LastDMATransfer_TxOddRxOdd;

// NSS signal to 0

ESC_CS_ON;

// Number of Bytes to transmit and receive

DMA1_Channel4->CNDTR = Tx_Size + Rx_Size;

DMA1_Channel5->CNDTR = Tx_Size + Rx_Size;

// Enable reception

DMA1_Channel4->CCR |= DMA_CCR_EN;

// Ebable transmission

DMA1_Channel5->CCR |= DMA_CCR_EN;

Another function checks the transfers are completed and take the data from the buffer

if((DMA1->ISR & (DMA1_FLAG_TC4 | DMA1_FLAG_TC5)) != (DMA1_FLAG_TC4 | DMA1_FLAG_TC5))

   return 0;

if((DMA1_Channel4->CNDTR != 0) || (DMA1_Channel5->CNDTR != 0))

   return 0;

if(SPI2->SR & (SPI_SR_FRLVL | SPI_SR_FTLVL | SPI_I2S_FLAG_RXNE | SPI_I2S_FLAG_BSY))

   return 0;

SPI2->CR1 &= ~SPI_CR1_SPE;

memcpy(value, (u8*)RxBuffer + Tx_Size, Rx_Size);

return 1;

My impression is that even though the SPI is disabled and enabled to try to flush it and even

though

 I check that the RXFIFO is empty, there is something that remains there and corrupt the future transfers.

#dma #spi #spi-flushing #spi-shift
This topic has been closed for replies.
Best answer by Ed Raab
Posted on March 04, 2018 at 19:39

hallo,

i have a simular problem with SPI.

I have a STM32F746 as SPI master in polling mode with a full duplex connection to a STM32F103 worked as SPI-slave.  A communication block of 720 Bytes is repeatly transfered in 20ms with a speed of appr. 6MHz SPI-CLK.  

Sporadic there is an error on the communication like described above. There is a byte offset in the received bytes. The bytes in the receive buffer  (RxBuffer) have an offset of 1 or 2 or more bytes permanently. After the error occurs all following receptions have this offset in opposite to the bytes on the SPI-MISO-Pin, recepted with Oscilloscope.

I currently use the HAL-SPI-functions. In case of error the hspi->RxXferCount shows 2 or 4 but the hspi->TxXferCount shows 0. I have tested several workarounds to set up the SPI-Interface right but it doesnt work.

Until now only repowering of the F746 solves the problem.

Is there anybody to have a solution for this problem?

best regards

ed

11 replies

Ed Raab
Ed RaabBest answer
Associate
March 4, 2018
Posted on March 04, 2018 at 19:39

hallo,

i have a simular problem with SPI.

I have a STM32F746 as SPI master in polling mode with a full duplex connection to a STM32F103 worked as SPI-slave.  A communication block of 720 Bytes is repeatly transfered in 20ms with a speed of appr. 6MHz SPI-CLK.  

Sporadic there is an error on the communication like described above. There is a byte offset in the received bytes. The bytes in the receive buffer  (RxBuffer) have an offset of 1 or 2 or more bytes permanently. After the error occurs all following receptions have this offset in opposite to the bytes on the SPI-MISO-Pin, recepted with Oscilloscope.

I currently use the HAL-SPI-functions. In case of error the hspi->RxXferCount shows 2 or 4 but the hspi->TxXferCount shows 0. I have tested several workarounds to set up the SPI-Interface right but it doesnt work.

Until now only repowering of the F746 solves the problem.

Is there anybody to have a solution for this problem?

best regards

ed

sirpak
sirpakAuthor
Associate III
March 4, 2018
Posted on March 04, 2018 at 22:09

Hi Ed.

I think I managed to solve using USART working in SPI mode. I didn't complete the tests yet, but I haven't observed any byte shifts.

Best regards, 

M

Ed Raab
Associate
March 9, 2018
Posted on March 09, 2018 at 10:34

hallo,

changing to USART is not a good choice for me according to hardware-dependencies.

I am hopeful that a ST FAE will give a hint to solve this problem,

because with this error the whole SPI-Rx-function is not usable.  

best regards

Ed

C. Satterberg
Visitor II
October 30, 2018

Hello All,

Looks like I'm not the only one that has has this problem. Has anyone solved this since it was originally posted? Switching to UART is definitely not a satisfactory answer and something that definitely isn't an option for my design.

David Littell
Senior II
October 30, 2018

Try reading the SPI DR twice (16-bit reads) immediately prior to the SPI exchange.

C. Satterberg
Visitor II
October 30, 2018

Good suggestion, but it doesn't seem to make a difference. Looking at the SPI bus on a scope, it looks like the responses from the slave are shifted before entering the master. Looks more like a problem with the way that the master is sending data that somehow desynchronizes the slave. It's pretty baffling though. Like, it shouldn't be possible for a SPI master to clock out more or less than one byte of data if it's set up for that, right? You should never just get an extra bit or two for no reason.

Ed Raab
Associate
November 2, 2018

hallo,

my problem is to understand how affects an event all following receptions. My SPI-signal quality is good. But wether a wrong Byte-signal is detected according to noise or a single spike this may results in a wrong data reception only of this byte or bit but not all the following receptions. It seems to be that the SPI-reception logic ignores until now one or more of the first bytes. That is the first problem. The second problem is that a ReInit of the SPI-Interface doesnt correct the settings for reception.

best regard

Ed

Associate II
May 1, 2019

SPI works with DMA without a single byte shifting. Just needed to create the whole project in an orderly fashion. Set the clock first, make all free pins as analog, then save. After configure peripherals, enable DMA on SPI, turn on ISR for DMA and off for SPI.

Associate II
May 5, 2019

Hello all, good news! It seems the SPI byte shifting problem has been solved. The SPI DMA HAL in Slave Mode has been working for one day flawlessly. No byte shifting at all.

What did I do​?

I've created the whole project from the scratch by using CubeMX 5.1

After selecting the MCU from the list, ​CubeMX creates the project framework. Here are all the followed steps afterwards:

1) Go to project manager and define all the basic settings. Name for the project, application structure "Advanced", IDE, keep all default settings. Code Generator: copy only the necessary libraries, set all free pins as analog, keep all default settings.

2) Configure the clock and save the project.

3) Configure SPI (Master/Slave), activate DMA, turn on DMA interrupts, SPI interrupt off.

4) Save the project.

You​ need to move your custom files from the old project to the new one plus all the required configuration.

To​ make a test, the only method you need to call is:

HAL_SPI_TransmitReceive_DMA (in case of Full-Duplex)

This method makes all the necessary initialization inside.​

Guessing about why is it now working​, I believe that some resources need to be allocated first, maybe for the APB/AHB clocks, so the very first need to be the clock configuration.

After​ this I added the remaining peripherals I need for my project, and that is it.