Articles

UART Packet Framing: Recover After a Dropped Byte

A UART receiver can deliver correctly timed bytes while the application loses its place in a packet. If one byte disappears from a fixed-length message, a parser that simply counts bytes can consume the start of the next message as the end of the damaged one.

The receiver needs a defined way to discard an incomplete candidate and find a fresh boundary. For a device team preparing a prototype for deployment, this belongs in the protocol specification and acceptance tests, before recovery depends on restarting the product.

Separate UART errors from packet errors

UART character framing and application packet framing solve different problems. In Microchip’s ATmega328PB receiver documentation, the frame-error flag reports an incorrect stop bit; a separate overrun flag reports loss caused by a full hardware receive buffer. Check the equivalent behavior in your MCU’s documentation.

A byte lost later in a software queue does not necessarily produce either hardware flag. Keep hardware error counters, software overflow counters and parser rejection counters separate. If the driver reports a receive discontinuity, invalidate the current candidate and resume boundary searching, following the device-specific procedure for clearing hardware errors.

Give each framing mechanism one job

A length field tells the receiver how much data to expect once it has found the correct header. It does not, by itself, identify that header after bytes disappear. The Protobuf streaming guidance recommends prefixing message sizes because its wire format is not self-delimiting. A length-prefixed stream still needs a recovery strategy when its transport can lose bytes.

Keep these responsibilities explicit:

  • Delimiter: marks a place where a new frame can start.
  • Escaping: prevents a delimiter value inside the body from looking like a boundary.
  • Length validation: checks that the decoded body has the specified size, within a fixed maximum.
  • Integrity check: detects covered corruption, subject to the chosen algorithm’s limits.
  • Timeout: releases an unfinished candidate when its permitted reception window expires.

RFC 1055’s SLIP description illustrates the distinction: it defines packet boundaries and escaping, but provides no error-detection mechanism of its own.

A small hypothetical packet format

Consider a binary-transparent UART link with software flow control disabled. Our example uses 0x7E before and after every frame. Inside those delimiters, 0x7E becomes 0x7D 0x5E, and 0x7D becomes 0x7D 0x5D. Escape the entire body, including the check bytes.

This borrows the octet-escaping pattern described in RFC 1662. It is a custom teaching example, not an implementation of PPP. Its decoded body contains:

  1. One version byte and one message-type byte.
  2. A two-byte, little-endian payload length, limited to 256 bytes.
  3. The payload.
  4. A two-byte CRC covering the header and payload before escaping.

For this example, specify CRC-16/IBM-SDLC completely: polynomial 0x1021, initial value 0xFFFF, reflected input and output, final XOR 0xFFFF, transmitted low byte first. Applying those parameters to ASCII 123456789 gives 0x906E, verified with the executable example fixture. A label such as “CRC-16” alone leaves too much room for incompatible implementations.

The maximum decoded body is 262 bytes. Since each body byte can expand to two wire bytes, a complete encoded frame requires at most 526 bytes, including its two delimiters. These are calculated limits for the hypothetical format, not product measurements.

Make the receiver discard deliberately

Use three states: waiting for a delimiter, collecting a candidate, and discarding until a delimiter. Check for a raw 0x7E before interpreting escape state. It closes the current candidate and establishes a fresh starting boundary. Consecutive delimiters represent empty candidates and can be ignored.

While collecting, decode only the two permitted escape sequences. An unsupported escape, too many encoded bytes or more than 262 decoded bytes moves the parser into discard mode. A delimiter arriving immediately after an escape rejects that candidate rather than becoming payload.

At the closing delimiter, require a supported version and message type, a permitted length, an exact decoded size of six bytes plus that length, and a matching CRC. Only then pass the payload onward. Keep candidate data away from command handlers until every check passes.

Hypothetical UART test: frame A loses one payload byte and fails its length check; the next complete frame B passes length and CRC checks.
Hypothetical receiver example. A dropped payload byte leaves frame A shorter than its declared length, so it is discarded. An intact opening delimiter starts frame B, which is accepted after length and CRC checks. Decoded body fields are shown; escaping is omitted.

In the illustrated hypothetical test, frame A declares three payload bytes, but one is removed before the parser receives it. Its decoded body is eight bytes instead of nine, so the closing delimiter triggers rejection. The next opening delimiter starts clean collection; intact frame B passes its size and CRC checks. Nothing from frame A reaches the application.

Bound waiting as well as memory

A maximum length prevents unbounded buffering. Add an encoded-body limit of 524 bytes so malformed input cannot keep consuming work inside one candidate. After rejection, scan for a delimiter without retaining the discarded bytes.

Also define a total candidate deadline, starting with the first body byte. An inter-byte timeout alone can be kept alive by a slow trickle. Choose both limits from the allowed sender pauses, transport buffering and receiver scheduling, and check elapsed time even when no new byte arrives.

For illustration, at 115200 baud with 8N1, each byte occupies ten bit periods. The maximum 526-byte frame takes about 45.7 milliseconds of continuous transmission. That calculation excludes gaps and processing delays, so it is a baseline for choosing a deadline, not a recommended timeout.

Recovery has a condition: after corruption stops, the receiver must encounter an intact opening delimiter followed by a complete valid frame within its limits. If delimiters are also lost, more data may be discarded. If the sender stops, the deadline clears the candidate; it cannot create a replacement packet.

Test the damaged stream and the next packet

Feed the parser reproducible byte streams independently of the UART driver. For each mutation, append a known valid frame and check both rejection behavior and subsequent delivery.

  • Delete a payload byte and verify the illustrated length rejection.
  • Change a payload byte without changing the length or CRC and verify CRC rejection for that fixture.
  • Split an escaped byte across two receive callbacks. It must decode normally.
  • Supply an invalid escape, oversized length, truncated body and unsupported message type.
  • Expire the total deadline during a slow trickle, then send a fresh frame.
  • Remove or insert delimiters and document which candidates are discarded. Do not assume every fault loses exactly one frame.

Run additional tests through the real driver for buffer wraparound, queue overflow and delayed servicing. Record the input, expected accepted payloads and rejection reason. A CRC does not guarantee detection of every possible corruption and provides no sender authentication. Sequence numbers, acknowledgments, duplicate suppression and safe retry rules are separate design decisions, particularly for commands that move machinery.

Include recovery in the product specification

A useful firmware acceptance criterion is concrete: after a specified stream fault, the device rejects the damaged candidate, stays within memory and timing limits, and accepts a subsequent valid packet under documented conditions.

Our Gomicron project spans mechanical design, PCB electronics, firmware and control, slicing software, prototyping and manufacturing. That work is relevant to the coordination required across a physical product. The UART format and tests here are hypothetical and are not claims about Gomicron’s protocol or test results.

Include interface recovery in the hardware and firmware development scope. The handover should contain the packet format, buffer and timing limits, replayable fault fixtures, and the exact accepted and rejected packet sequence expected for each fixture.

Technical sources checked on November 11, 2026. The packet format, calculated limits and receiver examples are educational, not Gomicron design details or hardware measurements.