# How do I organize robust communication between a PC and a microcontroller?

I have a Raspberry Pi and STM32F072. What I want to do is very simple: Generate lots of data on the Raspberry Pi and transfer it to the STM32.

There are several things that are important:

• The STM32 needs time to process data, so the Raspberry Pi should send data only when the STM32 is ready to process it.
• The communication needs to be robust. By that I mean guaranteed delivery and no errors (some kind of error correction must be present). Also I want to be confident that connection can stay alive indefinitely.
• Preferable at least 1 Mbit/s speed.

I considered using SPI, I²C, UART and USB, but they all share a common problem: They are all too low-level (level 1-2 of the OSI model) and lack any flow control (therefore aren't robust).

1. Are there any implementations of some preferably lightweight transport protocol on top these which can be is used?

2. If I have to implement such a transport protocol myself, which underlying protocol will be the simplest to use? Here are my thoughts; please correct me if I am wrong on any of these:

• UART is simple, but slow on Raspberry Pi. I think can use a USB-to-UART converter (e.g. ch340) to make it faster, but is it a good idea?
• SPI is fast and simple. There is a snag though: Raspberry Pi supports SPI only in master mode, which makes protocol slightly more complicated.
• I²C is probably fine, but it's not clear why it could be better than SPI in my case.
• USB is fast, has error correction and guaranteed delivery built-in, but it is very complex.
• To pick one you are going to need to be more specific about your requirements. What is the purpose of the data? What process or output of the STM32 is ultimately consuming it? Do you have requirements for latency or jitter? In the case of bad data, do you want to try to correct it at the risk of breaking timing, drop it, or use it and hope that following good data masks the impact? – Chris Stratton Mar 4 '17 at 18:00
• Flow control != robustness, I'd argue. and USB has flow control, and so do UART and I²C, but at a lower level. – Marcus Müller Mar 4 '17 at 18:07
• @ChrisStratton, Thanks for the questions. Ultimately STM32 will control a laser. Latency is a soft requirement: delays aren't good, but it's not a failure. In case of bad data I'd want to correct it even if it breaks timing. – D. Dmitriy Mar 4 '17 at 18:10
• You should add CAN to your list of possibilities, and maybe also UDP over ethernet. – electrogas Mar 4 '17 at 18:17
• By the way, "robustness" should be measured by something, for example, a bit error rate that you could tolerate. There, nowhere, not even within ICs, is the perfect channel, and there's always some probability that a bit might come out different than it was sent. An engineer's job is to keep that probability below a threshold the application can tolerate – but in your case, we don't know that threshold! – Marcus Müller Mar 4 '17 at 18:20

## 4 Answers

I think SPI would be my first choice. I2C and UART are way slower, USB is overkill. 1 MHz is not slow, but certainly doable for a short distance. You might need matched impedances on your lines, and a scope will be very handy for troubleshooting.

I'd assume that errors are rare. On top of SPI, you could implement a go-back protocol: send data as a big block with an ID and a checksum. With each SPI exchange, the ST returns the ID of the last succesfully received block. When that doesn't match what the RaPi hoped for, it must go back to transmitting the last not-yet-succesfully-received block.

When a block is not received OK, the RaPi will notice this with the transmission of the next block, so two blocks are lost. If this is deemed too much the TS could buffer one extra block, or the acknowledge could be piggybacked on a tail part (dummy bytes) of the block itself.

• a clear +1. Note that the STM32 of OP's choice isn't blazingly fast, but has a CRC unit which lends itself nicely to this application. If OP went for a (pin-compatible?) chip with higher CPU clock, FEC would be a serious option – with a theoretical max of 48 CPU cycles per bit, this would require quite a lot of luck to work out. – Marcus Müller Mar 4 '17 at 18:37
• Addressed that aspect in my answer (which acknowledges your answer) – Marcus Müller Mar 4 '17 at 19:24

You specified in the comments: "one bit every 4000 Tb", so that's an error rate of

(4000 T)-1 = ¼ · 10-12 = 2.5 · 10 -13

Long story short: That's about as good as what is recommended for 10GE networking equipment – the stuff you'll find in data centers. Not the cheap gigabit ethernet every laptop has.

Network transceivers use a whole bucket of measures to reduce bit errors, including coding and doing the appropriate error correction, equalization, and having the logic implemented in simulated and sometimes even formally verified hardware logic.

I doubt that anything you can do on a raspberry Pi is even close to that error probability. Developer experience says that doesn't even work on a higher level, since RAM errors are more likely than one in 4000 Tb; like, a lot more likely for the cheap RAM you'll use. Furthermore, by the choice of your MCU, an 48 MHz clocked Cortex-M0, you practically make it impossible to have any substantial Forward Error Correction (FEC) between Pi and MCU – with 48 CPU cycles per bit, including doing what you need to do with your laser, there's simply very likely not enough CPU headroom to do that.

So, I concur with Wouter, SPI with error-checking on top (the STM320 does have a CRC unit, but that's not enough for FEC) is very likely the protocol of choice. But without more complex channel codes and hardware support on both ends, it seems a bit unlikely you'll really achieve a bit error rate of 2.5 · 10 -13. Then again, I'd claim that this BER was grossly overestimated: If you have a a 1 Mb/s link, and transfer 4000 Tb, it will take you nearly 127 years.

• C'mon, this answer is not helpful. I maybe overestimated the required error rate, but did you really need to write a long post just to point out this arithmetic error? – D. Dmitriy Mar 4 '17 at 19:36
• Ah, you have to get the math right in the beginning, that is. [^_^] – Janka Mar 4 '17 at 19:37
• I've tried to put a lot more into that answer! For example, I really do think that you have an interesting application. Second, you need to carefully calculate the requirement for your application, that is the first step in engineering (always), and while doing so, a lot of things will become clear that might not even have anything to do with the problem at hand. Third, I mentioned mechanisms that mitigate errors in professional equipment, and you will probably want to look into these. So pleas don't be offended! – Marcus Müller Mar 4 '17 at 19:39
• (sorry, if I offended you with my comment, you definitely spend a lot of time helping me, and your feedback in comments was helpful. I'll try to estimate my error rate requirements more carefully.) – D. Dmitriy Mar 4 '17 at 19:40
• Don't worry :)! – Marcus Müller Mar 4 '17 at 19:46

USB<->UART converter may work just fine. It will allow you to have a long USB cable between the RPi and your device, and an actual UART link of a few centimeters, which will happily work at 1 or 2 Mbit/s with a very low error rate. You mention CH340 which supports 2 Mbit/s baudrate.

Of course, you'll still need to have some sort of protocol to ensure flow control and guaranteed delivery, and you don't even have to start from scratch, reusing e.g. XON/XOFF for software flow control and XMODEM for delivery notifications. Considering your UART link will be a few cm long, you can even implement hardware flow control if you have 2 extra pins on your MCU.

This way, you'll have working software on your RPi from the start (e.g. minicom), which will make debugging your system much easier, compared to the solution where you develop brand new software on both sides.

• It's a good answer, too bad that my question it too broad to have just one clear "winner". – D. Dmitriy Mar 6 '17 at 21:59

Preferable at least 1 Mbit/s speed.

SPI can easily do that.

As the speed goes up, you may consider DMA on the STM, or the use of parallel schemes.

At that point, data acquisition on the STM is likely the bottleneck.