Sync protocol for microcontrollers


Intro

I will be using this page to document the protocol I implement for syncing multiple Arduinos (first introduced at this link).  The protocol will very likely evolve as I get it working, but I will make an effort to keep this page up to date.

Hardware

The Arduinos to be synced will be connected as slaves to an RS485 bus.  An additional Arduino will be installed purely for synchronising everything, and this will be the master node of the RS485 bus.

Communication protocol

Only the master is allowed to initiate communications.  In other words, slaves are only allowed to respond to the master, and not to query the master, nor each other.

All communications — whether from the master or from the slaves — must be in the form of a “frame” structured as follows.

Structure of a message frame

Address byte

The first byte contains an address.  If sent by the master, then this is the address of the slave to which the message is directed.  If sent by a slave, then it is the address of that slave.  The least significant bit of this byte is used to set even parity, so the address is extracted by bit-shifting the byte towards the least significant bit.

Originally I had planned to do parity calculations on the address byte, but I will leave this out for now.  If I observe a significant error rate in addressing the individual microcontrollers, I will add this back.

Instruction/reply byte

In a message from the master, the second byte contains an instruction.  At the moment, only two instructions are envisaged:

  1. 0x05 (“ENQ”), which is asking the slave if it is still alive & healthy.  This instruction will only ever be sent as a unicast to a particular slave, not as a broadcast message since the resulting flood of required responses will be impossible to read.
  2. 0x11 (“DC1”), which tells the addressed slave that it should change its state to that encoded in the following byte.  This command may be broadcast or unicast.

In a message to the master, the second byte contains a reply to the instruction that initiated the communication.

  1. 0x06 (“ACK”), as a reply to “ENQ”, indicating that the slave considers itself to be happy and healthy.
  2. 0x15 (“NAK”), as a reply to “ENQ”, indicating that the slave considers itself to be untrustworthy.
  3. 0x11 (“DC1”), as a reply to “DC1”, indicating that the instruction to change the state was received correctly.  The next byte will contain the state that the slave is now in.

Data byte

In messages to or from the master, the third byte contains any data needed by the instruction or the reply.  In the case of the instruction “ENQ” from the master to a slave this byte is not used, but in all other cases it must be present.

  • For instruction “DC1” from the master to a slave, the data byte should contain the number corresponding to the state that the slave should now transition to.
  • For response “DC1”, “ACK”, or “NAK”, from a slave to the master, the data byte should contain the number corresponding to the state that the slave is now in.

Query — response

As is usual in a master-slave system, slaves can never initiate communications.  They have to wait for a unicast query before they have permission to speak, and then they can only answer the master’s query.

Broadcast messages

The rule here is pretty simple.  Messages sent to the broadcast address are not responded to.

Unicast messages

A slave receiving “ENQ” should reply “ACK” if it considers itself to be trustworthy and healthy.

A slave receiving “ENQ” should reply “NAK” if it considers itself to be untrustworthy.

A slave receiving “DC1” should, after attempting to set its state to that requested, reply with “DC1” and the state that it is currently in.  If all went according to plan, this should result in the message from the master and the message from the slave being identical.

Leave a comment