ArbyBot Development Log #3 - AMP Candidate 2
1,489 words Estimated 8 min read
Introduction
In this post, I propose the second design candidate for the Arby Message Protocol (AMP). The goal of this protocol is communicating the control of various Microcontroller Units (MCUs) aboard the ArbyBot, and enabling peer-to-peer communication between them. After publishing the proposed design of AMP Design Candidate 1, I decided that it would be desirable to upgrade from CAN 2.0B to CAN-FD.
CAN-FD allows support for frames with a payload capacity of up to 64 bytes, up from the 8 bytes provided by CAN 2.0B. The data-phase rate of CAN-FD is up to 8 Mbit/s as opposed to 1 Mbit/s offered by Classic CAN, depending on hardware and bus configuration. Larger frames reduce fragmentation for larger messages, increasing the overall data throughput. Faster data transfer is desired for communicating IP packets over the CAN bus.
CAN-FD supporting hardware has become prolific in recent years and can be found in the form of the MCP2518FD generic boards on Amazon, for as little as 15 EUR. With CAN-XL USB devices being 500 EUR, CAN-FD would be the limit. Additionally, my STM32 board: the Nucleo H743ZI2, has native CAN-FD support, with the help of a 5 EUR CAN transceiver.
To better utilise the larger frame sizes of CAN-FD, I also wanted to re-design AMP to enable flexible value data lengths and message batching.
Acronyms
Definitions employed are presented (Table 1).
| Acronym | Definition |
|---|---|
| ABC | ArbyBot CAN |
| AMP | Arby Message Protocol |
| CAN | Controller Area Network |
| CAN-FD | CAN Flexible Data Rate |
| CAN-XL | CAN Extra Long |
| CRC | Cyclic Redundancy Check |
| CRC-32 | 32-bit CRC |
| EUR | Official ISO 4217 currency code for the Euro (€) |
| HDLC | High-Level Data Link Control |
| ID | Identifier |
| IP | Internet Protocol |
| ISO | International Organization for Standardization |
| JSON | JavaScript Object Notation (RFC 8259) |
| MCU | Microcontroller Unit |
| PPS | Pulse Per Second |
| RFC | Request For Comments |
| RPC | Remote Procedure Call |
| SI | International System of Units |
| STM32 | STMicroelectronics 32-bit |
| USB | Universal Serial Bus |
| UTC | Coordinated Universal Time |
Table 1. Acronym Definitions
Conventions
Units of Measurement
The International System of Units (SI) is used for physical quantities. Unless explicitly stated otherwise, values use SI units without prefixes, for example:
- Metres for distance.
- Seconds for time.
- Radians for angles.
Any scaling or alternative unit must be documented in the variable or field definition.
Unit symbols are case-sensitive:
mdenotes metre.sdenotes second.msdenotes millisecond.
SI prefixes represent powers of ten, for example: kilo (k) means 1,000 and mega (M) means 1,000,000.
Data sizes use bytes (B), with decimal prefixes such as kB for 1,000 bytes, or binary prefixes such as KiB for 1,024 bytes. Data rates are expressed in bits per second (bit/s).
AMP Design Candidate 2
The purpose of the redesign for the second iteration of the proposed protocol is to efficiently use the available space of CAN-FD frames. The improvements include:
- Support batching messages (now called AMP Frames)
- Verification of data integrity with CRC-32.
An AMP Message occupies the combined payload of one or more ABC packets with protocol 0, sharing the same sender, target and message counter.
An AMP Frame is an individual data segment within an AMP Message, allowing the messages defined in Candidate 1 to be batched together.
Where necessary, the final ABC packet is zero-padded to the next supported CAN-FD payload length. Padding follows the AMP Message’s CRC-32 and is excluded from both Body Length and the CRC calculation. CAN-FD supported lengths are as follows: 0–8, 12, 16, 20, 24, 32, 48 or 64 bytes
The Message Structure
As with AMP Candidate 1, all multibyte numeric fields use big endian byte order. The structure of the AMP Message for AMP Design Candidate 2 is presented (Table 2).
| Position | Type | Size | Name | Description |
|---|---|---|---|---|
| 0 | uint16 |
2 bytes | Magic Word | The magic word, used as an additional safety measure to identify an AMP message start: Value = 488. |
| 2 | uint16 |
2 bytes | Body Length | The length of the remainder of the message in bytes, including the CRC-32. |
| 4 | Array of AMP frames | Body Length - 4 bytes | AMP Frame Segment | Sequential AMP frames. |
| 4 + Body Length - 4 | uint32 |
4 bytes | CRC-32 | A 32-bit Cyclic Redundancy Check (CRC-32/ISO-HDLC, RFC 1952) for the preceding bytes of the message. |
Table 2. The AMP Message (AMP Design Candidate 2).
The packet diagram of an AMP Message (Table 2), containing a 12 byte AMP Frame Segment, is presented (Figure 1). The diagram shows bit offsets, with each row representing four bytes.
---
title: AMP Message — Second Iteration
config:
packet:
bitsPerRow: 32
---
packet
accTitle: Second iteration AMP message layout
accDescr: A 20-byte AMP message consists of a two-byte magic word, a two-byte body length, a twelve-byte segment containing Heartbeat and PPS Synchronisation frames, and a four-byte CRC-32. Body Length is sixteen bytes, including the CRC.
0-15: "Magic Word = 488"
16-31: "Body Length = 16"
32-127: "AMP Frame Segment — 12 bytes"
128-159: "CRC-32 — 4 bytes"
Figure 1. An example AMP Message containing two AMP frames (AMP Design Candidate 2).
The Frame Structure
The Heartbeat AMP Frame is presented (Table 3). Positions in the AMP Frame tables are zero-based byte offsets from the start of each AMP Frame.
| Position | Type | Size | Name | Description |
|---|---|---|---|---|
| 0 | uint8 |
1 byte | Message Type | Heartbeat message type: 0. |
| 1 | uint32 |
4 bytes | Uptime | Seconds since startup. |
| 5 | bool |
1 byte | Time Valid | Indicates whether the system has established the current Unix time from a received timestamp, regardless of PPS synchronisation. |
| 6 | bool |
1 byte | PPS Lock | Indicates whether the system is currently synchronised to the PPS signal. |
Table 3. The Heartbeat AMP Frame (AMP Design Candidate 2).
The PPS Synchronisation Frame is presented (Table 4).
| Position | Type | Size | Name | Description |
|---|---|---|---|---|
| 0 | uint8 |
1 byte | Message Type | PPS synchronisation message type: 1. |
| 1 | uint32 |
4 bytes | Timestamp | Unix time, seconds since epoch (1970-01-01 00:00:00 UTC), corresponding to the preceding PPS pulse. |
Table 4. The PPS Synchronisation AMP Frame (AMP Design Candidate 2).
The Get AMP Frame is presented (Table 5).
| Position | Type | Size | Name | Description |
|---|---|---|---|---|
| 0 | uint8 |
1 byte | Message Type | Get message type: 2. |
| 1 | uint16 |
2 bytes | Key | Identifier of the value to retrieve. |
Table 5. The Get AMP Frame (AMP Design Candidate 2).
The Set Frame is presented (Table 6).
| Position | Type | Size | Name | Description |
|---|---|---|---|---|
| 0 | uint8 |
1 byte | Message Type | Set message type: 3. |
| 1 | uint16 |
2 bytes | Key | Identifier of the value to modify. |
| 3 | uint8 |
1 byte | Value Length | The length in bytes of the value to assign. |
| 4 | Defined by Key | Value Length | Value | The value to assign to the specified key. Its data type is determined by the key. |
Table 6. The Set AMP Frame (AMP Design Candidate 2).
The Emit Frame is presented (Table 7).
| Position | Type | Size | Name | Description |
|---|---|---|---|---|
| 0 | uint8 |
1 byte | Message Type | Emit message type: 4. |
| 1 | uint16 |
2 bytes | Key | Identifier of the value emitted. |
| 3 | uint8 |
1 byte | Value Length | The length in bytes of the emitted value. |
| 4 | uint8 |
1 byte | Timestamp Length | The length in bytes of the provided timestamp: 0, 4 or 8 bytes. |
| 5 | Defined by Key | Value Length | Value | The current value of the specified key. |
| 5 + Value Length | Defined by Timestamp Length | Timestamp Length | Timestamp | Time at which the value was read, measured since the Unix epoch (1970-01-01 00:00:00 UTC), in seconds for a 4-byte timestamp or nanoseconds for an 8-byte timestamp. |
Table 7. The Emit AMP Frame (AMP Design Candidate 2).
The modification to the Set frame is the inclusion of the Value Length field. Likewise, the modification to the Emit frame is the inclusion of a Value Length field and a Timestamp Length field. The Value Length field allows for a program not familiar with a specified key’s value format to skip an unrecognised key’s value and continue parsing subsequent AMP frames. The Value field occupies exactly Value Length bytes, rather than the fixed five-byte field used in Candidate 1. The Timestamp Length field allows a program to specify the size of the timestamp:
- a
0value would mean that the timestamp has been omitted, - a
4value would mean the timestamp value isuint32in seconds, - an
8value would mean the timestamp value isuint64in nanoseconds.
Conclusion
The design of AMP Candidate 2 improves on many aspects of candidate 1:
- The protocol supports batching multiple AMP Frames inside one AMP Message.
- The protocol supports variable-length values with explicit length fields.
- CRC-32 provides integrity checking, while a magic word helps identify AMP messages.
However, the design falls short in some aspects:
- A register of keys and value types must be included/pre-shared to be able to interpret the data, even if it can be skipped if not known to the receiver.
- Requests and responses have no explicit correlation identifier.
- Each Emit frame carries a single keyed value; complex data structures require a predefined encoding.
- Addressing is reliant on ABC device identifiers, and thus limited to 127 addresses.
For AMP Candidate 3, I would like to:
- Encode data types explicitly alongside values to enable automatic type discovery.
- Support additional (and optional) fields.
- Support complex data structures.
- Introduce a Remote Procedure Call (RPC) framework similar to JSON-RPC, replacing the earlier Get and Set commands and enabling the correlation of responses with their respective requests.
- Provide structured error responses.
- Support an alternative/global addressing system, limiting ABC addressing to the physical CAN network only.