cancel
Showing results for 
Search instead for 
Did you mean: 

SPI3 hangs after some time

Tomas Hamouz
Associate III

I have troubles using SPI3 on STM32U575VG. After some time the transfer hangs and it is not possible to amend it until whole reset.
Configuration: Only transmit, is feeds LCD display, 240 lines, 54 bytes each.
APB3 clock 48 MHz. Manual CS handling, SCLK 1.5 MHz.
Everything looks ok, it works, but after some time and on some boards only it hangs. The problem appeared in the start of production.


Symptoms: after configuration and LL_SPI_Enable(), the DMA transfers 16 bytes to the FIFO. That's ok, DMA works. But after LL_SPI_StartMasterTransfer(), the transfer doesn't start.
Looking at the pins, SCLK remains low and MOSI contains some data, but very slow, one bit interval seems to be 8 ms.

Reset of the SPI doesn't help. Reinit of the whole MCU after STOP2 (without reset), including all clocks doesn't help. The only thing that works is the reset of the whole MCU.

I have no idea where to look at more. The SPI is not overclocked, it doesn't wait for any external signal. It happens sometimes after a few minutes, sometimes after hours. 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Tomas Hamouz
Associate III

Sorry for delay, out of service :(

System now seems to be working. The EOTIE bit in SPI_IER register enables interrupt not only on EOT, but also on SUSP and TXC flags. As I use TSIZE > 0, the TXC bit is copying EOT, including clear, so it isn't important in this case. The problematic flag is SUSP, it wasn't serviced in my INT handler, but enabled together with EOT. There was a handler for EOT only in my code, and when the SUSP flag was signaled, the endless interrupt could arose. 

Workflow was: if there was a timeout, stop the transfer correctly, i.e. raise SUSP request. But the endless interrupt didn't occur, because the rest of the FW was working. I caught it under the debugger only.

The effective code was

  if(was_timeout) {
    LL_SPI_SuspendMasterTransfer(SPI3);
  } 
  SPI3->IFCR = SPI_IFCR_EOTC | SPI_IFCR_TXTFC | SPI_IFCR_UDRC | SPI_IFCR_OVRC | SPI_IFCR_CRCEC
| SPI_IFCR_TIFREC | SPI_IFCR_MODFC | SPI_IFCR_SUSPC;
  (return from function)
  LL_SPI_DisableIT_EOT(SPI3); 
  LL_SPI_Disable(SPI3);

Now I am only guessing.
I suppose that the SUSP flag was cleared sooner than it managed to be set, and the device was then disabled without correct flag clear. This is the reason the whole SPI was stuck. 

I added: a)  wait for SUSP flag to be set   b) handler for SUSP interrupt   c) reset of DMA channel, and it is now working.

There is still one problem I don't understand, how can the cca 280us transfer using DMA break the 5ms timeout. I have to further analyze the code if the timeout isn't wrong evaluation only (the system runs under kind of RTOS).

TH

 

View solution in original post

9 REPLIES 9
Saket_Om
ST Employee

Hello @Tomas Hamouz 

You are not enabling the GPIO C clock in SPIDriver::InitGPIO().

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om
waclawek.jan
Super User

Any difference between SPI and relevant GPIO and RCC registers' content (I'd look also at PB3) between working and non-working cases?

JW

Pavel A.
Super User

Can it be a DMA fault with "halt on DMA error" enabled? This can explain why reset of the SPI does not help. It's the DMA.

 

I'm sorry, the posted code is not exactly real source, otherwise I had to post too much files with too much indirection, but the logic and statement order is maintained. GPIO clocks are enabled in standard system startup. I will add the clock enable,  just to be sure.
As I mentioned, the code works after startup, but sometime hangs. 

All SPI, relevant RCC (APB3 clock, SPI3 kernel clock) and GPIO registers checked and without any change and difference to working state. There is LPUART1 sitting also on the APB3 and working without change.

I'll try tomorrow morning.

But the DMA halt is in contrary with the fact that when the SPI is enabled, DMA fills the FIFO in SPI. At least the cached bytes should be sent, right?

MM..1
Chief III

Primary use LED on GPIO to measure valid clk. For example set blink on every 1sec, but by sw not by timer.

If MCU fallback to HSI maybe...

Next try debug issue = leave debuger connected to arrive problem.

waclawek.jan
Super User

This:

> Looking at the pins, SCLK remains low and MOSI contains some data, but very slow, one bit interval seems to be 8 ms.

is what puzzles me the most.

I suggested looking at PB3's GPIO registers settings, because it's SPI3_SCK, too; and would that be set to AF for SPI3, those signals would probably OR together, potentially resulting in a bogus SPI_SCK input to the SPI module. And, at least in the older STM32, SPI's shift registers are known to work out of the SCK's *input* even if it's master.

It sounds that you are able to debug a hung device. If it is so, I'd personally stop the processor and proceed by manipulating registers entirely manually in the debugger. I'd try first switching SCK and MOSI to Output in GPIO, wiggle (and observe); then I'd try to switch back to AF and try to get SPI3 transmitting anything, without DMA (maybe I'd try this to do manually in the non-hung state first, to have a "known-good" procedure at hand to be used in the hung state). If desperate, I'd may even try also getting it to be slave (by manipulating the internal SSI) while toggling SCK using GPIO_PUPDR, while observing MOSI behaviour and the SPI flags.

Another approach could be the divide-and-conquer method: I doubt the SPI3 in itself is the culprit, and suspect, it's something else in your program, which I suspect is extensive. So maybe trying to remove some parts of that program would also remove the problem, in which case that part of program may - or may not - be treated with suspicion.

JW

Tomas Hamouz
Associate III

Sorry for delay, out of service :(

System now seems to be working. The EOTIE bit in SPI_IER register enables interrupt not only on EOT, but also on SUSP and TXC flags. As I use TSIZE > 0, the TXC bit is copying EOT, including clear, so it isn't important in this case. The problematic flag is SUSP, it wasn't serviced in my INT handler, but enabled together with EOT. There was a handler for EOT only in my code, and when the SUSP flag was signaled, the endless interrupt could arose. 

Workflow was: if there was a timeout, stop the transfer correctly, i.e. raise SUSP request. But the endless interrupt didn't occur, because the rest of the FW was working. I caught it under the debugger only.

The effective code was

  if(was_timeout) {
    LL_SPI_SuspendMasterTransfer(SPI3);
  } 
  SPI3->IFCR = SPI_IFCR_EOTC | SPI_IFCR_TXTFC | SPI_IFCR_UDRC | SPI_IFCR_OVRC | SPI_IFCR_CRCEC
| SPI_IFCR_TIFREC | SPI_IFCR_MODFC | SPI_IFCR_SUSPC;
  (return from function)
  LL_SPI_DisableIT_EOT(SPI3); 
  LL_SPI_Disable(SPI3);

Now I am only guessing.
I suppose that the SUSP flag was cleared sooner than it managed to be set, and the device was then disabled without correct flag clear. This is the reason the whole SPI was stuck. 

I added: a)  wait for SUSP flag to be set   b) handler for SUSP interrupt   c) reset of DMA channel, and it is now working.

There is still one problem I don't understand, how can the cca 280us transfer using DMA break the 5ms timeout. I have to further analyze the code if the timeout isn't wrong evaluation only (the system runs under kind of RTOS).

TH