cancel
Showing results for 
Search instead for 
Did you mean: 

SPI-receiver gets out of sync?

HMüll.4
Senior

Hi,

I'm using a STM32H523CC to receive 24 bit data frames via SPI. The SPI acts as receiver-only and is configured as follows:

Clipboard01.png

Within my application I do not make use of the HAL-functions but have overwritten the SPI2_IRQHandler(). There I continuously read the data from the SPI RXDR register as soon as the SPI_FLAG_RXP is set. When some overflow/error-flags are set, they are cleared:

void SPI2_IRQHandler(void)
{
#ifdef USE_IRQ
   const uint32_t trigger2=SPI2->SR;
   if ((trigger2 & (SPI_FLAG_MODF | SPI_FLAG_OVR | SPI_FLAG_FRE | SPI_FLAG_UDR|SPI_FLAG_RXP)) != 0UL)
   {
      if ((trigger2 & SPI_FLAG_RXP) != 0UL)
       handleRxc(); // reads from SPI2->RXDR

      /* SPI Overrun error interrupt occurred ----------------------------------*/
      if ((trigger2 & SPI_FLAG_OVR) != 0UL)
      {
         __HAL_SPI_CLEAR_OVRFLAG(&hspi2);
      }

      /* SPI Mode Fault error interrupt occurred -------------------------------*/
      if ((trigger2 & SPI_FLAG_MODF) != 0UL)
      {
         __HAL_SPI_CLEAR_MODFFLAG(&hspi2);
      }

      /* SPI Frame error interrupt occurred ------------------------------------*/
      if ((trigger2 & SPI_FLAG_FRE) != 0UL)
      {
         __HAL_SPI_CLEAR_FREFLAG(&hspi2);
      }

      /* SPI Underrun error interrupt occurred ------------------------------------*/
      if ((trigger2 & SPI_FLAG_UDR) != 0UL)
      {
         __HAL_SPI_CLEAR_UDRFLAG(&hspi2);
      }
   }

The sender is submitting a permanent stream of data with 100000 frames per second (means 300000 bytes per second). This works fine and smooth in DEBUG and RELEASE build except for one situation:

When I power both, the sender and my STM32H523CC-based receiver at the same time, the SPI-reception gets out of sync. As I'm not connected with the debugger in this situation, I can not see what data are received exactly, but from what the result looks like, I have the feeling, the received data are shifted by one or two bytes so that my 24 bit frames are mixed/shifted into each other.

So my question: when I work with the NSS-signal, shouldn't this ensure some synchronisation? Means shouldn't the MCU recognise the start of a frame by NSS going to LOW and when NSS goes back to HIGH, shouldn't it end the frame here and make the received (partial) data available in RXDR while reception starts from the beginning?

Or asked in other way: assumed, NSS goes to LOW, then for some reason only 16 bits are received when NSS goes to HIGH, shouldn't the next time NSS goes to LOW the received data be part of the next frame? I would expect in this case the first 8 bits of the next frame are NOT made part of the previous one?

So how can I ensure the synchronisation to real 24 bits in one received frame works properly?

Thanks!

 

1 ACCEPTED SOLUTION

Accepted Solutions

Hi HMüll.4, TDK

I have a similar problem.

In My case I see one unexpected Byte after receiving the first RX Interrupt (normally the unexpected Byte is 0x00 but some times its 0x01).

In my case this is because the STM32H730 is running before the MCU, where I have the SPI Master, this results in MOSI, MISO, SCK and NSS low until the Master SPI interface is running.

So the STM32H730 will clock in 1 Bit when the SCK line go's High with NSS still low. It seems that this bit is remaining in the RX Shift-register until the STM32H730 receives the next 8 Bit's of Data (I have set the Data frame size to 16 Bit) and the RX Interrupt is fired. So when reading the RX register I get the (unexpected) Bit in the high Byte and the high Byte of my expected data in the low Byte of the Word I'm extracting from the RX register. From this point on my data is shifted by 1 Byte for ever.

I think that this is by design and cannot be avoided. The only way to correct this is to handle the received data as a Byte array and detect this on the protocol level.

View solution in original post

6 REPLIES 6
TDK
Super User

Yes, if NSS is used and goes high between words, the master and slave will sync. Is that happening? Can you show a trace of the SPI signal?

Sending in a stream of known data and then printing out the received data and comparing the two would yield some insights. It sounds like you're not quite sure what is going on.

Instead of silently ignoring errors, you should be setting a flag and indicate in some manner that they are happening.

If you feel a post has answered your question, please click "Accept as Solution".
HMüll.4
Senior

OK, I dug a bit deeper into it. In fact, the SPI definitely gets out of sync for some reason. This does not happen byte-wise as assumed before, but the received data can be shifted by any amount of bits. Once I'm in this situation, the NSS-signal does NOT re-sync it, it seems the shift-register of the SPI is moved to RXDR only when 24 bits are received but never when NSS goes to HIGH/toggles.

Furthermore I found that I can re-sync the SPI when I disable it and re-enable it. Here the point in time, when this happens, does not seem to make a difference, so even when this is done in the middle of a frame, everything works well afterwards. This in fact is surprising as I would have expected the same synchronisation problem here.

 

 

Update: this is what my SPI data transfers look like

DS0018.PNG

Until now I could not find out what specific situation causes the SPI receiver getting out of sync...

 

 

TDK
Super User

I'm still of the opinion that NSS synchronizes the stream. You provide no evidence for it getting out of sync.

If it does behave as you say, it should be easy to reproduce the behavior in self-contained program at much lower clock rates and capture the signal on a scope.

If you feel a post has answered your question, please click "Accept as Solution".

Hi HMüll.4, TDK

I have a similar problem.

In My case I see one unexpected Byte after receiving the first RX Interrupt (normally the unexpected Byte is 0x00 but some times its 0x01).

In my case this is because the STM32H730 is running before the MCU, where I have the SPI Master, this results in MOSI, MISO, SCK and NSS low until the Master SPI interface is running.

So the STM32H730 will clock in 1 Bit when the SCK line go's High with NSS still low. It seems that this bit is remaining in the RX Shift-register until the STM32H730 receives the next 8 Bit's of Data (I have set the Data frame size to 16 Bit) and the RX Interrupt is fired. So when reading the RX register I get the (unexpected) Bit in the high Byte and the high Byte of my expected data in the low Byte of the Word I'm extracting from the RX register. From this point on my data is shifted by 1 Byte for ever.

I think that this is by design and cannot be avoided. The only way to correct this is to handle the received data as a Byte array and detect this on the protocol level.


@MHoll.2 wrote:

In my case this is because the STM32H730 is running before the MCU, where I have the SPI Master, this results in MOSI, MISO, SCK and NSS low until the Master SPI interface is running.

This sounds exactly like my problem.

 

I think that this is by design and cannot be avoided. The only way to correct this is to handle the received data as a Byte array and detect this on the protocol level.


in my case, when I detect some *** data, it can be fixed by disabling and re-enabling the SPI. This of course works only because it does not matter here when some/the first bytes get lost.