Best protocol between two MCUs on the same board - Page 1
Forum section: electronics / general

author: okw
author_rank: Frequent Contributor
timestamp: April 09, 2021, 09:24:10 am
content: Hello! I'm putting together a board with two MCUs (nRF9160 and nRF52832) which should exchange simple messages between each other, and firmware over the air (coming from the 91 to 52). I'm using Zephyr RTOS and was thinking UART between them. The 91 can have up to 4 individual UART channels, but the 52 can only have 1. And the 52 needs one UART for other things, so the question is, what is the best alternative? I was thinking an UART to SPI bridge chip, but if I can do it all in software that would be best.

author: DavidAlfa
author_rank: Super Contributor
timestamp: April 09, 2021, 09:36:18 am
content: Can't you use SPI in both?

author: Siwastaja
author_rank: Super Contributor
timestamp: April 09, 2021, 04:19:06 pm
content: My usual favorite is SPI because microcontrollers tend to have excess SPI peripherals available to spend, and if DMA is available, it can offload the CPU completely and automagically keep memory regions (basically structs containing anything you want) in sync - just be aware of atomicity issues, add some kind of incrementing counter to verify that the transactions are going on, and if possible/required, a CRC won't hurt.SPI offers hardware packet delimitation (although sometimes MCUs fail to implement that properly) to any arbitrary packet length. UART is otherwise fine but hardware-delimited to only 8 bits of data which very seldom is enough so you need to come up with a delimitation layer on top. Which can be simple, for example a start/sync pattern, then payload length field, then payload, finally CRC, but it's still some work.Those two would be the typical sane choices. If you don't have peripherals free to implement either, then some simple bit-banged GPIO protocol usually does the trick, assuming you don't have massive amounts of data. Manchester coding allows simple self-clocking one-wire protocol robust against significant clock differences, and can be transformer or capacitor coupled.

author: TomS_
author_rank: Frequent Contributor
timestamp: April 11, 2021, 02:28:56 pm
content: I suppose theres a bigger question, and avoiding XY problems: why two MCUs? What about the application means it wont fit onto one?An RTOS gives you a lot of opportunity to process high priority stuff much closer to real time while deferring truly low priority stuff to later.Closer to answering the question at hand, UART can be good if you want asynchronous communication - either end can send data to the other when ever it needs to. You cant have that with SPI unless you dynamically reconfigure each end between master/slave, but even then you can only transmit in one direction at a time unless you come up with some funky scheme to start transmitting in the other direction part way through the master sending stuff to the other end or something like that... Sounds like a nightmare to me.UART can be bit banged quite easily using a timer and some interrupts (to avoid busy looping), so if one of the UART requirements is for low speed, infrequent data, then that could be an option on the 52.

author: artag
author_rank: Super Contributor
timestamp: April 11, 2021, 06:00:30 pm
content: SPI can send in both directions at the same time (see various SPI peripherals that both accept a command and return the last result simultaneously), so if your DMA bandwidth and power consumption permits you can just send both ways constantly as, Siwastaja implies in his answer.

author: Siwastaja
author_rank: Super Contributor
timestamp: April 11, 2021, 06:05:54 pm
content: Of course, SPI "naturally" fits better when structured, fixed-length data is exchanged and this exchange is initiated by always the same device ("master"). But this isn't the only use case.SPI is fine for "asynchronous" style (in higher-level sense), one just needs to be master and constantly initiating transfers, which is trivial with DMA, or can be done in an ISR. The slave can just send what and when it wants to, indicating there is something worth processing with a flag.But if what you need is asynchronous two separate links (in opposite direction) of byte streams, then UART is the obvious choice and involves less work.Multi-MCU solutions are often fine. I don't have any problem with them. Some do have bad experience, I don't understand why despite numerous attempt to try to read their explanations with open mind. Obviously, if something is truly not needed, then don't do it. I'm assuming here that multi-MCU solution is being considered as a result of finding doing something on one MCU problematic.

author: Siwastaja
author_rank: Super Contributor
timestamp: April 11, 2021, 06:18:51 pm
content: To recap the options:* GPIOQuite obvious, if you want to communicate something that is just a single command, a sync signal, enable signal, etc., why not just use binary input/output. Could come from a logic gate, or a push-button - why not MCU-to-MCU. Or is this too obvious/trivial?When larger amount of data than a few bits are needed - for example, ADC measurement values, setpoints, audio, image data, waveforms, commands to do something, then we'll need a generic digital communication bus that can transfer arbitrary amount of data:* UARTGreat for asynchronous commands / response streams. Big minus: does not implement packet delimitation on hardware. The communication unit is typically 8 bits. You have to write delimitation where message begins and where it ends.* SPIGreat for exchanging memory regions, for example, giving setpoints and receiving measurements. Big plus: hardware delimitation of packets. Big minus: many MCU peripherals are broken, buggy or hard-to-use so said plus may be impossible to fully utilize.You can use UART for what SPI is best for, or vice versa, it's just that you need to write a bit more code on top of the low-level protocol.* Bit-banged custom on GPIOIf low data rates are OK, bitbanging on ISR is trivial. Now you can do anything, like use Manchester encoding to make a signal that can pass through a transformer or coupling capacitor.

author: nctnico
author_rank: Super Contributor
timestamp: April 11, 2021, 08:40:54 pm
content: Quote from: Siwastaja on April 11, 2021, 06:05:54 pmThe biggest problem is that some people severely underestimate the potential pitfalls which come with having two asynchronous processes and dealing with communication errors. Sooner or later there will be a moment where communication between processors fails (no matter how well the hardware is designed) and there has to be a way for the software to recover from such an event. Keeping everything in 1 processor makes the software much simpler. I'm not saying it is impossible but not everyone is like Evel Knievel who can jump across a ravine on a motor cycle.

author: NorthGuy
author_rank: Super Contributor
timestamp: April 11, 2021, 11:12:35 pm
content: Quote from: Siwastaja on April 11, 2021, 06:05:54 pmWell. In the majority of the cases, single-CPU solution is simpler (and consequently cheaper, faster, and more reliable), and that is the reason to prefer it. What not to understand?It certainly doesn't mean that single-CPU solution must always be used, or that single-CPU solution is always simpler than a multi-CPU ones. Sometimes, using multiple CPUs may make the design simpler. It's impossible to discuss without knowing the project with all the underlying details. But when discussing inter-CPU communications, it is always a good idea to first consider if such communications are needed and if it is possible to get rid of them altogether. That's true about every element of design. Just get rid of what you don't need, and what's left is simple, small, and beautiful.Quote from: Siwastaja on April 11, 2021, 06:05:54 pmOf course. When people find something problematic then, instead of solving the problem, they often try to push it away by some sort of external means - second CPU, more resources, RTOS etc. All those things are Ok if they serve a purpose, but when they're summoned because of inability or unwillingness to solve the problem they simply add unnecessary complexity to the system.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: April 11, 2021, 11:39:29 pm
content: Debugging can also be a PITA with multiple MCUs, though it the tasks are well partitioned and interface well defined ( including all plausible error situations), it can be a good solution where there are other constraints - e.g. interrupt latency or hard timing.If nothing else the process of firmware updates needs significantly more thought.

author: ledtester
author_rank: Super Contributor
timestamp: April 12, 2021, 12:13:21 am
content: Adafruit is advocating using a ATSAMD09 as a programmable I2C peripheral expander...https://www.adafruit.com/product/3657Trivial usage example:https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout/arduino-wiring-testVideo demo of using their samd09 chip handling multiple rotary encoders + neopixels via I2C:https://youtu.be/XsmcJjLWNRQ

author: brucehoult
author_rank: Super Contributor
timestamp: April 12, 2021, 03:26:20 am
content: Quote from: TomS_ on April 11, 2021, 02:28:56 pmI'm guessing it's something to do with the fact the nRF9160 has LTE and GPS while the nRF52832 does BlueTooth.The former has a 64 MHz M33 with 256 KB RAM and 1 MB flash and appears to be completely dedicated to running the application, not doing the radio stuff.The latter has a 64 MHz M4F with 1/8th or 1/16th the RAM and 1/2 or 1/4 the flash.So I guess you'd want to use the nRF9160 as the main CPU. Both have SPI so if that's not otherwise spoken-for BOOM there you go.

author: brucehoult
author_rank: Super Contributor
timestamp: April 12, 2021, 03:33:28 am
content: Quote from: NorthGuy on April 11, 2021, 11:12:35 pmMultiple packages certainly introduces a whole lot of new problems and failure modes. Multiple CPUs on the same chip can be considerably simpler to manage, especially if they share coherent memory or have built in hardware communications queues between them (e.g. the new RPi MCU).

author: fchk
author_rank: Frequent Contributor
timestamp: April 12, 2021, 10:49:18 am
content: Quote from: okw on April 09, 2021, 09:24:10 amI'd suggest a small FPGA (Lattice has a bunch of these, e.g. ICE40/50 or MachXO_/2/3) with two SPI interfaces and an number of fixed size message buffers (eg. 8 or 16 bytes). After one uC has sent a message into the FPGA, an interrupt is sent to the other uC in order to signal a waiting message. Reading the message will clear the interrupt. Depending on the capacity of the FPGA multiple messages could be stored for each direction.Most uCs only have good spi master capabilites, and the FPGA would take care for the rest.fchk

author: DavidAlfa
author_rank: Super Contributor
timestamp: April 12, 2021, 03:24:08 pm
content: FPGA for that is overkillJust make a solid protocol using spi

author: fchk
author_rank: Frequent Contributor
timestamp: April 12, 2021, 04:50:55 pm
content: Quote from: DavidAlfa on April 12, 2021, 03:24:08 pmYou may think of FPGA as a big chip with 200+ pins in a large TQFP or BGA package costing 50+€. Yes, there are many FPGAs of this kind. But there are also small ones measuring only 3*3mm with 16 or 24 pins costing only a few €. These are meant for such glue logic between chips.fchk

author: nctnico
author_rank: Super Contributor
timestamp: April 12, 2021, 07:22:42 pm
content: Quote from: fchk on April 12, 2021, 04:50:55 pmEven then there has to be some kind of interface on the microcontroller to communicate with the FPGA / CPLD. This is a path of quickly diminishing returns because bit-banging manchester (used that myself) between two microcontroller directly is simpler compared to the added complexity of using an FPGA / CPLD. In the end an FPGA needs to be programmed which in turn adds an extra layer with functional uncertainties whichmay need(will have) to be debugged. Remember that when debugging a system with multiple layers you will have to go through each layer to figure out why something isn't working. This is also where my love for text based protocols comes from; text is human readable so tapping in at any point along the way and just dumping the protocol one way or another shows you exactly what is going on.