Communication Stacks
Communication firmware turns bytes or frames into reliable product behavior. A good stack separates physical transport, framing, parsing, command handling, timeouts, and application policy.
Learning Objectives
By the end of this lesson, you should be able to structure a protocol stack, design receive buffers, handle framing and CRC errors, implement timeouts and retries, and test parsers with known vectors.
Stack Layers
Do not mix UART register handling with product commands. Each layer should have a narrow responsibility.
Framing and Buffers
A receiver needs to know where a message starts and ends. Use fixed length frames, length-prefixed frames, delimiter-based frames with escaping, or packet formats supplied by transports such as CAN, USB, BLE, or TCP. Length fields need bounds checks before memory is written.
#define RX_SIZE 128u
static uint8_t rx_buf[RX_SIZE];
static volatile uint16_t head;
static volatile uint16_t tail;
Capacity must cover worst-case burst while the parser is busy. Overflow should be counted and reported.
CRC, Timeout, and Retry
CRC detects accidental corruption. A CRC failure should drop the frame, increment diagnostics, and resynchronize safely. For request-response protocols, define response timeout, retry count, backoff, duplicate handling, and fault state.
Worked Example: Register Read
A register-read transaction includes device address, function, start register, count, CRC, and response length. Verification should include a valid frame, bad CRC, wrong address, timeout, short frame, count too large, and exception response.
Parser Rules
- Validate length before reading fields.
- Validate CRC before executing commands.
- Reject unsupported commands explicitly.
- Keep parser deterministic under random bytes.
- Do not allocate memory based on untrusted length without a cap.
Common Mistakes
- Blocking forever for a response.
- Assuming
read()returns a whole frame. - No buffer overflow counter.
- Parser accepts a command before CRC validation.
- Mixing endian conversion throughout application code.
Summary
Communication stacks need clean layers, bounded buffers, reliable framing, validation, timeouts, retries, and diagnostics. Treat the parser as a hostile-input boundary even on small embedded links.
Further Reading
- Modbus Application Protocol Specification.
- CAN in Automation protocol references.
- Memfault, "Interrupt-driven UART and Ring Buffers" articles.