2
\$\begingroup\$

I want to use the SPI protocol to communicate between an STM32 and Arduino.

So I made up some message structure where the first byte is the 'command' byte, and data bytes following. The number of data bytes depends on the command byte (so not all messages have the same length).

Now I have a few basic questions regarding defining those messages:

  1. Can I assume SPI is kind of 100% reliable? (meaning no bytes are lost, the Arduino/STM32 will be within max 10 cm/4 inches difference) ? (if yes, the following questions might be less critical). I don't need a super fast speed.

  2. Is it a good way to have messages of different length? Rationale: When the command byte is not read correct, the number of data bytes is incorrect, and all consequent bytes will not result in valid messages.

  3. To prevent this, should I add some 'end bytes'? Or is there a better way to solve the problem of misreading (e.g. the command byte)? And if the end bytes would be e.g. 255, should I make sure 255 is not used in the command or data bytes?

Or maybe in other words:

What should I change to a simple message structure Command byte - Data byte(s) where the data bytes are varying on the command byte, in case the command byte is received incorrectly?

\$\endgroup\$
  • 1
    \$\begingroup\$ Synchronous protocols are great for control of fixed-function devices, not so grand when the slave is a programmable device, because you add a hard real-time requirement even if the behavior only has soft real-time requirements. \$\endgroup\$ – Ben Voigt Jun 1 at 17:55
1
\$\begingroup\$

I use SPI to communicate between two STM32's in some of the products I design, it works well, but there are some gotchas.

Can I assume SPI is kind of 100% reliable? (meaning no bytes are lost, the Arduino/STM32 will be within max 10 cm/4 inches difference) ? (if yes, the following questions might be less critical). I don't need a super fast speed.

SPI is not 100% reliable, it is susceptible to noise, especially common mode noise. This means having a solid ground between devices. If this is a board-wire-board bus then it could also be more susceptible to noise. If you have switching power loads, this also may crate noise.

Speed and error rate go hand in hand, in general higher speeds are more susceptible to noise and the error rate goes up. The problem is in rise times (mostly from capacitance) of the bus. The higher the speed, the more likely rise times and ringing will become problematic.

I would think if your running less than ~5MHz you should be fine. Use good EMC/EMI control, check the rise times of the SCLK and give the clock time to settle, this should minimize error rate.

Is it a good way to have messages of different length? Rationale: When the command byte is not read correct, the number of data bytes is incorrect, and all consequent bytes will not result in valid messages.

This is all dependent on the software you want to write, I prefer fixed bytes. The most likely error is probably going to be from a bit flip, not a missed clock (if your running the bus slow enough).

Another thing to consider is to add interrupt lines to the spi bus for hardware flow control if you are rolling your own software. This makes it easier to tell which processor is talking, I'll usually a CS line from the master to slave, but also one from the slave to master, so you don't have to poll all the time, just handle the interrupt if the slave wants to talk (not needed if you have communication that is one way only).

To prevent this, should I add some 'end bytes'? Or is there a better way to solve the problem of misreading (e.g. the command byte)? And if the end bytes would be e.g. 255, should I make sure 255 is not used in the command or data bytes?strong text

Hardware flow control is best, if you need reliability then use a CRC byte/scheme to make sure the message has been sent correctly. Use the CS line to figure out when the message is over.

\$\endgroup\$
  • \$\begingroup\$ Thanks for all this info, I would have to look into EMC/EMI. I probably will use a package length byte in the message and CRC (based on what you say). I have only one processor talking to the other, but I guess I can use the CS line to define when a command starts (?). \$\endgroup\$ – Michel Keijzers Jun 1 at 18:06
  • 1
    \$\begingroup\$ Yeah, that is one way to do it on a micro, you can use the CS line for an interrupt on the slave side. The other way to do it is poll the CS line. Once you see the CS line go low, you look the the clock and record the data coming in. \$\endgroup\$ – Voltage Spike Jun 1 at 18:20
  • \$\begingroup\$ Thanks, I guess I rather use an interrupt (having the MCU doing its normal work as much as possible). \$\endgroup\$ – Michel Keijzers Jun 1 at 18:25
1
\$\begingroup\$

That is an interesting question! First of all many chips don't have any error detection, or if they do, it is very simple, such as SPI flash memories expecting complete bytes so if clock pulses are not divisible by 8 then it won't execute the command. SPI flash memories are also a bit different from normal SPI chips that flash memories are command-based while a chip like RTC would be register-based. And hardware chips are a bit different than microcontrollers, as usually chips like SPI flashes start executing the write command when chip select goes high, while microcontrollers rarely have any hardware in the SPI module to detect edges of chip select. So microcontrollers would need extra handling for detecting it.

1) You can expect it to be 100% reliable. Most SPI comms are inside a device, between chips or at most between two boards. Rarely a checksum or CRC is used, but hey of course you can implement this as a sanity check.

2) It is perfectly fine to have messages of different lengths. Each command could have a certain length, or if transferring variable amounts, then the variable amount could be in the message header, so you know at least after how many bytes to stop or wait for CRC/checksum.

3) Any byte could potentially be in the message, so this one is complex. One way to delimit the messages by expecting a command byte when chip select gets active and only executing the command when chip select rises. Or if the SPI bytes are just stream of bytes, you might packetize them somehow, like ignore everything unless a magic value packet header is seen which tells how many bytes it contains and after packet again ignore everything until header is seen. Or do some other kind of encoding, like use only hexadecimal ASCII letters, start with a symbol like ( and end with ), otherwise ignore everything.

One more thing that is different between a MCU slave and hardware slave. Whatever SPI clock you use, the master MCU must pause between bytes so that receiving MCU processes the receive interrupt, or it will miss bytes. This is not a problem if slave uses DMA receive, but receiving with DMA does bring other issues like how do you know which byte was last.

\$\endgroup\$
  • \$\begingroup\$ Thanks for this useful information, and indeed, putting the length inside the message helps (I now have it 'fixed' in the command, but later I might have variable amounts. Also thanks for the last paragraph, I don't think I want to use DMA for this. \$\endgroup\$ – Michel Keijzers Jun 1 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.