cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F417 SPI interrupt timing issue

Marijn25
Associate

Hello,

We have run into some issues regarding SPI in interrupt mode, especially when building with optimizations turned on. We are running SPI at 21MHz.

The situation:

We transmit one byte using HAL_SPI_Transmit_IT. This immediately triggers a TXE interrupt which puts our one byte into the DR register to be send by the peripheral. The hal interrupt routing checks if any more bytes must be send before calling the user callback to let us know the transmit is finished. All good so far. 

We then want to receive 3 bytes using HAL_SPI_Receive_IT. The hal will start by sending out dummy bytes, again the TXE interrupt is called where a byte is put in the DR register. This IRQ returns and we wait for an interrupt for TXE letting the us know we can put the next byte in the DR register. During this second TXE IRQ the first byte is clocked out and now our receive buffer contains a byte, setting the RXNE flag. We finish putting the second transmit byte in the DR register and enter the RXNE IRQ. 

This is where it gets tricky, remember that we put the second byte in the DR register, that is being clocked out while we are handling the RXNE IRQ from the first byte. Depending on the timing/speed of the IRQ we might be fast enough to still catch the first byte before it is overwritten by the second. 

Proposed fix #1: Do not start sending out more bytes just because the TXE flag is set, the hal should check if the previous byte is successfully handled/read before the next transmit can start. (Described here as well)

The above situation should set the OVR bit to indicate to us that an overrun has been detected. However, as this post describes, the next TXE IRQ actually clears this flag, making the overrun virtually undetectable. The user callback is never called, as the hal rx counter will never reach the desired amount (3) as it only serviced 2 RXNE IRQs. 

Proposed fix #2: Check for the OVR flag before servicing TXE interrupts.

Summarized:

If the IRQs cannot be handled quickly enough (either because other interrupts are being handled or because the hal IRQs take way too long), an undetectable overrun can occur, leaving the hal SPI in a waiting state.  

Situation is summarized in the picture below.

 Untitled Diagram.drawio.png

I'd be happy to provide more details if required.

6 REPLIES 6
Bob S
Principal

What if you use a single HAL_SPI_TransmitReceive_IT() call to send 4 bytes (the last 3 are dummy) and receive 4 bytes (the first is dummy)?  This is presuming of course that you do not need to de-assert the chip select between the TX and RX operations.

gbm
Lead III

Use HAL_SPI_TransmitReceive_DMA().

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Good suggestion, however this would require me to have two large buffers if I want to receive a lot of data, because I would also need to transmit data in that case. I would like to prevent that.

The HAL DMA implementation has a lot of issues as well, I would like to avoid it.

Skip HAL then, use DMA with register-level programming of both SPI and DMA.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Exactly what I am going to do. I made this post because I was wondering if this was a known issue/if any workarounds can be applied. (or better yet, to encourage ST to fix the hal)