Loading header...

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

flowchart TB APP[Application commands] --> PROTO[Protocol objects] PROTO --> FRAME[Framing and CRC] FRAME --> TRANS[UART SPI CAN TCP transport] TRANS --> DRIVER[Driver and ISR DMA] DRIVER --> HW[Hardware]

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.

stateDiagram-v2 [*] --> Idle Idle --> Send: request Send --> Wait Wait --> Done: valid response Wait --> Send: timeout and retries left Wait --> Fault: retries exhausted

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.

Mind Map

mindmap root((Communication Stack)) Core concept Bytes become commands Layers isolate transport Validate before action Applications UART protocol CAN node Modbus device IoT gateway Calculations Buffer depth Timeout period Retry count CRC width Design rules Bound lengths Check CRC first Count overflow Separate endian code Practical checks Bad CRC test Short frame Timeout path Random input fuzz Common mistakes Blocking wait Whole frame assumption No resync Trusting length