Skip to main content
ohmjke
Associate
August 29, 2019
Question

STM32F412 SPI DMA data bit-shifted

  • August 29, 2019
  • 7 replies
  • 6204 views

Hi.

First of all, the essence of my problem is already described here - https://community.st.com/s/question/0D50X00009XkiXu/spi-dma-data-corruption?t=1567119350874

In my case bug happens randomly and not very often. It could be one corrupted transaction among hundreds-thousands.

For example, how it is should work:0690X000009akJJQAY.png

First byte always is 0xAA.

Here is an example of corruption:

0690X000009akJTQAY.png

You can see that CLK signal has already started, but data on MOSI is delayed by 5 bits (not constant, can be 4, 3...).

My code: https://pastebin.com/X3CfdH4q

And settings: https://pastebin.com/GKWTC1QH

This topic has been closed for replies.

7 replies

waclawek.jan
Super User
August 30, 2019

Read out and check or post content of SPI registers.

JW

ohmjke
ohmjkeAuthor
Associate
August 30, 2019

I have checked content before this calls:

SPI_I2S_DMACmd(spi, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);

DMA_Cmd(dma_rx_stream, ENABLE);

DMA_Cmd(dma_tx_stream, ENABLE);

And after end of transaction (DMA_IT_TCIF2 bit is set).

0690X000009anC6QAI.png

Data in DR register "after" - 0xE1.

Content of RX memory buffer (should be AA 48 11 89 ..... FF FF FF FF):

0690X000009anH1QAI.png

How entire transaction looks:

0690X000009anL8QAI.png

The beginning of it (in this case I send all 0xFF bytes):

0690X000009anMzQAI.png

And the end:

0690X000009anN4QAI.png

waclawek.jan
Super User
August 30, 2019

Looks OK.

Does the transfer *before* the "failed" one exhibit any irregularity, e.g. incorrect/incomplete last byte transferred, or any outstanding clocks?

JW

ohmjke
ohmjkeAuthor
Associate
September 1, 2019

It seemed that you misunderstood me (or I don't understand you now).

There is no "before" and "after" transfers.

It is one transfer, I just read out SPI regs before DMA request and after end of the transfer (just in case).

Content of registers looks fine to me too.

waclawek.jan
Super User
September 1, 2019

> There is no "before" and "after" transfers.

You reset the whole mcu between transfers?

You've been talking about hundreds-thousands transactions. I don't believe you've performed hundreds-thousands system resets and observed single transfers between them.

JW

ohmjke
ohmjkeAuthor
Associate
September 5, 2019

Yes, you are right. I didn't reset mcu.

The last transfer before corrupted one was fine, so as next after it.

S.Ma
Principal
September 1, 2019

When using DMA on SPI, you need to be careful in the timing and events. If here we are talking about SPI Master, my advice are:

  • DMA TX main purpose is to generate the SCK clocks (and push out data). It should not have an interrupt nor callback
  • SPI should be in bi-directional mode (the other ones have time contrains)
  • DMA RX should be the one triggering the transfer complete and the next possible block transfer.
  • Always set DMA RX before TX (which kicks in the clocks)

If some of these points are not covered, dig more in your code, or try modify the source accordingly.

ohmjke
ohmjkeAuthor
Associate
September 5, 2019

Yes, in my case mcu works as master.

  1. TX stream do not have neither enabled interrupt nor used callback.
  2. Yes, we use "SPI_Direction_2Lines_FullDuplex".
  3. DMA_IT_TC interrupt enabled for RX stream. DMA and SPI will disable after this interrupt is happened.
  4. Already done.
waclawek.jan
Super User
September 6, 2019

> The last transfer before corrupted one was fine,

How do you know? Post scope/LA pictures.

JW

ohmjke
ohmjkeAuthor
Associate
September 9, 2019

Here is "prev" transfer:

0690X00000AQvttQAD.png

And Saleae Logic scope file (wrong transfer marked by timing markers):

waclawek.jan
Super User
September 9, 2019

Sorry I don't have the Saleae analyzer and don't intend to install the program. Can you please cut out the "previous" and "corrupt" transfer and place them next to each other?

[EDIT] Okay maybe it's not that necessary. Try to answer the following question first, and then perhaps mitigate it - if the signals are floating, try to set pullups/pulldowns as appropriate, especially to SCK [/EDIT]

Also, what is the SPI_ENABLE signal? And why are the SPI signals changing after the transfer ended?

Thanks,

JW

waclawek.jan
Super User
September 10, 2019

> After end of the transfer I execute disable and deinit SPI (including clock disable - RCC_APB2PeriphClockCmd) and change MISO/MOSI/SCK pins to INput mode with pull-down.

Okay, so don't do this. Leave the SPI on. And, as as you CPOL so that SCK is high on idle, don't use an pulldown, us a pullup to avoid any transition on SCK.

I'd say, the exact sequence how you re-enable the SPI includes a period, where the SPI is slave and its clock is floating, resulting in the internal clock-counter to be shifted out of 0 and remaining so even if switched to master. The bunch of pulses on MISO in the "corrupted transfer" at the moment when the _ENABLE signal goes low is IMO not a coincidence.

The SPI state machine is relatively fragile. SPI_CR1.SPE is always the last bit to be set.

I don't Cube.

JW

ohmjke
ohmjkeAuthor
Associate
September 12, 2019

Thank you for your advice, I'll try with corrected init sequence.

By the way - I have disabled DMA and still got the same error.

waclawek.jan
Super User
September 12, 2019

> By the way - I have disabled DMA and still got the same error.

I'd expect that, the problem appears to be entirely in the SPI and the way how it counts bits.

JW