Over the recent weeks I've been working on a new protocol for embedded devices. I call it "Simple Token Bus" or STB for short. It's a neat little protocol for which I have a rudimentary implementation on an Arduino.
I had several constraints during the design, largely due to my own needs. First, the protocol would have to be as simple as possible to parse both in memory and CPU. For this reason the protocol has only one variable length section; data payload. Everything can be parsed as a static struct in memory without issues.
Second, the protocol will have to support devices autoconfiguring themselves by randomly selecting an address. This is similar to IPv6 but I don't need as many devices. The address is 24bit, which allows you to get about 4 thousand devices on the same network without colliding addresses.
Third, the protocol must support multi-master operation. This eases the deployment of larger networks where multiple larger devices might interact with endpoints. Think of smart lamps in your home being controlled by both a smartphone and your router separately. Clients cannot send data on their own to a master since only the master is allowed to make requests on the bus.
Similar to I2C, two wires are used for transmission; Data and Clock. There is a small timing constraint; the clock can't switch faster than 33kHz (between each Clock Flank atleast 30 µs must pass). This isn't a bad limitation since STB isn't intended for high speed transfers. If you need faster I do have a second limit specified at 0.1µs, which enables up to 10 MHZ at the clock, this high speed mode can be signaled by a flag but it is not allowed for any control packets.
On the data layer, the packet size is defined as well as a short parity.
[ 1 bit ] ICDS Bit [ 11 bit ] Data Packet Size [ 4 bit ] Parity [ ] Remaining Packet
Data Packet Size field indicates how many bytes of payload we send with the packet. The
ICDS Bit field is always
1. This allows devices to detect when a packet starts reliably.
The data layer is only responsible for tracking when a data packet is being sent and how long it will last.
There is nothing interesting happening on the data layer beyond that.
Above the data link layer is the routing layer protocol. This part of the STB packet determines the destination address the packet will go to, the command being sent as well as a few flags. At the end is a CRC32 of the entire packet. Likely, this is the most compute intensive part of the packet and I might use a CRC16 instead.
[ 16 bit ] Data Layer Frame [ 24 bit ] Receiver Address [ 4 bit ] Command [ 4 bit ] Flags [ ] Payload [ 32 bit ] CRC32
The receiver address is fairly straightfoward, the two reserved values are 0x000000 and 0xFFFFFF. 0xFFFFFF is not allowed and not a valid receiver. 0x000000 is the currently active master, this enables devices to hardcode large parts of the packet (in fact, simple ACK and NACK packets can be entirely hardcoded).
The flags allow the clients and masters to communicate some optimizations, like Big-Endian CRC, high speed mode, fragmenting data over multiple packets and padding out the data payload to align with 64bit.
The command field can contain one of 16 commands, 4 of which have undefined implementation (3 for custom commands and 1 reserved). STB has three main ways for devices to communicate; Read/Write, Mailboxes and Interrupts.
Read/Write allows devices to exchange raw, completely unformatted data, this can be used in a variety of ways but it's basically an IP stack but slower and with less features.
Mailboxes behave similar to I2C, there is a fixed number of mailboxes and a master can read or write from any of them. Additionally the master can send an inquiry which allows a client to quickly iterate any mailboxes with new data. An inquiry is a very short request, so this is faster than iterating over I2C registers and reduces load on all devices, leaving the bus free for more data.
Interrupts allow a device to signal very important events are being happened [sic]. Usually a device will send this in response to a normal packet instead of an ACK followed by the normal ACK.
In the last few paragraphs I'll detail what a token bus is. Unlike I2C, STB doesn't have a fixed master device and unlike Ethernet there is no collision detection or avoidance (if that happens, bad things are happened [sic] and should stop).
A token bus is a bus on which a device has a token. This token authorizes the device to use the bus. The device can give the token to another device.
STB behaves like that. When the bus comes online, a sort of election selects a master device that will be the first one to own the bus. With a special command the device can scan for other master devices on the bus and pass them the token. The downside of this is that the bus must be cooperative. There is a protocol for replacing the bus master if the current on crashes, but it only works by detecting the clock being offline (which is why I would recommend you bitbang the clock and don't simply set PWM to avoid sending clock when you don't mean to).
This all is mostly a braindump to reiterate on all the things I've worked on and thought about, you can send me some suggestions via mail (just use the imprint mail) if you think I missed something.