cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7xx - Bug in SPI Driver HAL in larger transmission (32 bytes transmission in one call)

smati2
Associate II

Hi all. I am having an issue with HAL_SPI_TransmitReceive routine under STM32H743. I am using STM32CubeIDE ver 1.10.1. In our setup for STM32H743, it is bare metal (no RTOS). The SPI is in Slave mode. In particular, I am using SPI4 as follows:

Mode: Slave

PE11 = SPI4_NSS

PE12 = SPI4_SCK

PE13 = SPI4_MISO

PE14 = SPI4_MOSI

Data Size = 8 Bits with first bit as MSB bit

Note that the Master is transmitting at 3M baud.

I am using HAL_SPI_TransmitReceive function. It all works fine until the need for receiving 32 bytes in one call as indicated below:

HAL_SPI_TransmitReceive(&hspi4, aTxBuff, aRxBuff, MAX_NUMBYTES_TO_WRITE_EACH_TIME, 5000)

where MAX_NUMBYTES_TO_WRITE_EACH_TIME = 32

I get about half of them and the rest are all zero and the call gets stuck in HAL_SPI_TransmitReceive and never returns.

Note: I saw a post (https://community.st.com/s/question/0D53W00000MfuaASAR/stm32h7xx-serious-bug-in-spi-driver-hal-version-130-170-and-180?t=1677157489831) where another member (@Dub Bartolec) was having a similar problem. The member had discovered a bug on this routine and had noticed it existed in version 1.3.0, 1.7.0 and 1.8.0 in CubeMX. Having seen that post, I got the latest version (ver 1.11.0 ) from ST GitHub (https://github.com/STMicroelectronics/STM32CubeH7/tree/master/Drivers) and replaced my stm32h7xx_hal_spi.c and stm32h7xx_hal_spi.h with that version. It now actually receives the entire 32 bytes and the bytes are valid. However, it does not come out of the HAL_SPI_TransmitReceive routine. The transmitter thinks it needs to send more but TXP is not set so it gets stuck in that loop. I am doing 8 bytes transfers.

Please assist as we are stuck and the rest of the process cannot continue until I get over this communication issue.

Many thanks in advance.

23 REPLIES 23

> invalidateCache .. is wrong?

Did my article showed that one must somehow adjust the address or size parameter? No! Then why are you doing it?

> ? the other block

My article shows that there are two invalidation operations necessary for each buffer. If you would have read my article, you would know it!

> the buffer is probably not aligned properly

Your screenshots doesn't show whether the buffer is aligned. Buffer, not some readjusted addresses passed to the invalidation function!

What's the point of saying "I did", when your code is just a copy-paste from ST's broken examples and ignores literally everything that my article explains and shows in a code example?

smati2
Associate II

Hi @julien B 

Thank you for your suggestions. Though it does not appear that Master is removing the NSS early, I tried to do the NSS = SPI_NSS_SOFT, but had the same result. It basically moves on for a while and then the glitch happens.

As for other tasks, on this particular case, there isn't anything else.

I have tried the default configuration, but no real remedy. Now here's what I have done that has made significant changes:

On the short transfers, I am using the HAL_SPI_TransmitReceive call. However, on the larger transfers (32 bytes transfer size), I am doing HAL_SPI_TransmitReceive_DMA and that appears to work all the way through. In fact, I am doing a custom bootloader and with the above the update of over 600K byte transfers completes and data is valid. In fact, the issue that I had mentioned where data was valid but the status return was 0x80 does not appear to happen any more :)

However, to speed up the process, I would like to bump up the transfer size to potentially 256 or more. Yet, as the first attempt at transfer size of 64 bytes, it has a hiccup. The process goes for a while and then runs into an issue, which appears to be interrupt not firing! So, it hangs waiting for the completion interrupt after the HAL_SPI_TransmitReceive_DMA call. What's difficult to troubleshoot is that the process goes say about 15K bytes of transfer with all the transfer size of 64 bytes on each transfer before the hiccup happens. What's interesting though is that all the time that is is working well, the MISO is transmitting 0xA5 (which is what I do desire to send on MISO) while reading the MOSI bytes. However, upon the hiccup, it appears to have 7 or 8 bytes of 0xA5 sent on MISO, but the remaining bytes of that 64 byte transfer are some unexpected data or at 0xFF (MISO staying high). This may not be related, but nevertheless, could be a clue to the issue. Here are Logic Analyzer captures:

0693W00000aJ9YJQA0.png 

0693W00000aJ9YTQA0.pngFYI, in above, every toggle on "SEC_DEBUG1" is after the interrupt and toggled in the callback (HAL_SPI_TxRxCpltCallback) routine. As you can see the last transfers (256 bytes, which is split into four 64 bytes) are not getting the interrupt. Moreover, on a good transfer, all the MISO bytes are 0xA5 (see below):

0693W00000aJ9Z7QAK.png  

However, at the end where it starts having the issue, I only see 8 bytes of 0xA5 from MISO and then the rest are not what I am expecting and EOT interrupt does not fire... (see below):

0693W00000aJ9ZRQA0.png 

------------------------------------------------------------------------------------------------------------------

Here are the snippet of the code at the hiccup point waiting for interrupt call back routine to set the EOT completion and the related define and variable info:

0693W00000aJ9OYQA0.png 

0693W00000aJ9OeQAK.png 

0693W00000aJ9P2QAK.png 

Note: In above image, if resolution is small, I have also attached the image (SPI_DMA transfer hiccup.jpg).

Hope you or someone can assist. Thank you.

Hi @AScha.3

On the image you shared in reading the bytes (if inbuf_A_ready ==1), for last parameter of SCB_InvalidateDCache_by_Addr, you are doing sizeof(ESPinbuf)/2. Why are you doing div by 2 and not size of (ESPinbuf)? You are also copying the same size via memcpy Are you perhaps doing this operation twice? Can you not do it just in one operation and not divide it by 2?

FYI, I am not seeing this divide by 2 in the example (SPI_FullDuplex_ComDMA) from ST (STM32CubeH7) for the SPI DMA operation.

Thx.

hi @smati2​ , jepp size/2 . because sense of circular buffer is using it for more or less continuous data flow, so you need half-full and full signals (-> callbacks) to know , when 1. or 2, half of buffer is filled up ; then to use it, clear cache for this 1/2 size of buffer and copy to...use it. (maybe here clear cache again, to be shure the cache having no "new idea", what to to here). next will be the other half , triggering callback when ready; and so on...

in my case its even a little more difficult: the data is coming from a ESP8266 (spi master at 24Mbit) and i send him signal "DRQ" , when i want data, and then he sending some bursts of 64Bytes or so, until 2KB half-buffer filled , -> callback, i remove "DRQ", but the ESP sending more, until he stops after 100us later or so. this data going to the next half-buffer, so i need to be shure, this is already copied and free to use (at least the first 100 bytes or so); but it is working now without problems (data dropouts), just needed some try and error about the best buffer size, to get all this timing fit the "difficult" response of ESP data sending.

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