cancel
Showing results for 
Search instead for 
Did you mean: 

SPI in noisy environment - Techniques to mitigate spikes on CLK

Arthur S
Associate II
Posted on May 09, 2018 at 15:02

Hi guys,

I'm using a STM32F303 micro controller in a noisy environment and there are some spikes on the SPI CLK line which mess up the functionality. The chip is used in slave mode and the SPI messages trigger a state machine. No CS line is employed, the slave is always listening. A spike on the clock line leads to a bitshift and thus false bit patterns or corrupted messages which leave my state machine corrupted. The clock is working at 1 MHz, data word length is 8 bit.

  • Is there a possibility to flush the fifo using a time out on the clock line? E.g. if the 8 clock ticks do not arrive after 10us flush the FIFO and reset the SPI state? I have not found any corresponding commands and deactivating and then again reactivating the SPI peripheral is too slow.
  • And as a more general question: How do I reset the SPI peripheral at all, without a timeout as described above? So how do I flush the FIFO and the registers holding the data? Is there a fast way doing that?

Im looking forward to your answers!

Best regards,

Arthur

SPI Init:

void MX_SPI2_Init(void)

{

  hspi2.Instance = SPI2;

  hspi2.Init.Mode = SPI_MODE_SLAVE;

  hspi2.Init.Direction = SPI_DIRECTION_2LINES;

  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;

  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;

  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;

  hspi2.Init.NSS = SPI_NSS_SOFT;

  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;

  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;

  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

  hspi2.Init.CRCPolynomial = 7;

  hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;

  hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;

  if (HAL_SPI_Init(&hspi2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

}

SPI messages are sent and received via this command:

HAL_SPI_TransmitReceive_IT(&hspi2, (uint8_t *) tx_status, (uint8_t *) rx_status, 1);

#reset #flush #stm32f3 #noise #spi
9 REPLIES 9
Arthur S
Associate II
Posted on May 23, 2018 at 13:25

Has nobody an answer for me?

AvaTar
Lead
Posted on May 23, 2018 at 14:20

A spike on the clock line leads to a bitshift and thus false bit patterns or corrupted messages which leave my state machine corrupted.

The SPI bus was designed as a flexible and simple on-board bus (on one PCB), with minimal costs (gates and chip area) and pin count. Like the I2C bus (Inter-IC Bus).

Electrical robustness comes at the cost of energy (higher currents/voltages) and gates (differential lines, level shifters, transceivers, etc.).

I would consider a more appropriate protocol.

I once participated in a project where SPI signals were transmitted over larger distances via optocouplers. Can't remember many details, except it was quite expensive, and died later for other reasons ...

T J
Lead
Posted on May 23, 2018 at 14:52

SPI is a machine, it will do what you tell it to do.

If you add another clock source, you are screwed.

how long is your cable ?

the max pin current for a modern processor is 25mA.

if you used most of that, your noise immunity would be better, but not 100%

eg, 15mA, 3.3v V=IR, V/I = R

3.3 / 0.015 = 220R

So put a pull up 220R at the other end of the clock source.

Your need short wires for SPI, don't go past DC motors,  Switch modes. or High voltage.

Arthur S
Associate II
Posted on May 24, 2018 at 13:06

Hi guys,

thank you for your answers. I'm using SPI over longer distances using differential drivers and optocouplers, similar to Application Note SLYT4441 from TI:

http://www.ti.com/lit/an/slyt441/slyt441.pdf

The bus has to be working in a noise environment, I cannot mitigate that. Additionally I know, when the spikes on the clock line happen, so all I need to do (at least that's what I think), is to flush the RCV FIFO or to reset the SPI peripheral after this moment in time.

I call the HAL_SPI_TransmitReceive_IT(&hspi2, (uint8_t *) tx_status, (uint8_t *) rx_status, 1); function after that moment, but the wrong information still gets clocked in. Then I tried just disabling the SPE (SPI enable) bit before this moment and setting it again afterwards: Then the SPI bus does not work any longer. Now I am using HAL_SPI_ABORT (which in my eyes seems to be huge and overloaded procedure) after this spike in order to get a clean, new starting point again - without effect.

Is there no simple procedure to tell the SPI peripheral to start anew, with both FIFOs empty? Going through the whole HAL_SPI_Deinit and then again HAL_SPI_Init(SPI_HandleTypeDef *hspi) cycle is too time consuming.

T J
Lead
Posted on May 24, 2018 at 13:36

0690X0000060KuQQAU.png
Posted on May 24, 2018 at 13:19

No, its a machine, 8 clock cycles out, per byte.

Your SPI transmitter is intact.

your receiver is confused

'Going through the whole HAL_SPI_Deinit and then again HAL_SPI_Init(SPI_HandleTypeDef *hspi) cycle is too time consuming.'

does that work ?

step through it, you will find the clearing counter mechanism if it exists.

You could use 2 diodes, if you want the slave to self detect and recover.

Posted on May 24, 2018 at 13:31

I would abandon the idea to use SPI, and switch to UART/USART instead, probably using RS485.

This has the advantage of a defined character transmission length/timing. You get an error flag if the transmission is corrupted.

You can transfer in packages with defined start characters, end characters, and perhaps pause intervals. This allows for an easier re-synchronization after transmission errors.

And you can include a checksum, and a re-transmission request, if you need complete and correct transfers.

Just a suggestion.

Posted on May 25, 2018 at 11:05

Thank you for the idea! In my eyes UART was pretty slow or too slow, but reading a bit about RS485 my knowledge seems to be outdated. As I built my bus similar to the application note cited above, it could be possible to switch to RS485 without too much changes. I have to take some time and look deeper into that.

Posted on May 25, 2018 at 11:30

It does not necessarily have to be UART.

But a defined (and time-limited/terminated) character transmission seems crucial in your environment.

And RS485 uses higher signal energy levels, which are less affected by EMI.

CAN would be another (more complex and expensive) candidate.