UART · Module 9
Framing Errors
A framing error is one sampled bit at one instant. It proves the line was not at mark where the receiver expected mark — and nothing about why, which is what makes the diagnosis interesting.
Module 6 built a receiver that emits rx_frame_err_o, and Chapter 6.4 established the register discipline that keeps that flag attached to the frame it describes. What neither chapter did was say what the flag means.
It is worth being precise, because the usual gloss — "a framing error means the baud rate is wrong" — is a guess dressed as a definition. The actual content of the flag is much narrower:
At the receiver's configured stop-sample position, the synchronised line was not at the mark level.
That is one bit, observed at one instant, measured against one expectation. Everything else — the baud rate, the far end's configuration, noise, a disconnected wire — is inference from that single observation, and this chapter is largely about how much inference the observation actually supports.
1. The Assumption Being Violated
From Chapter 3.1 and Chapter 3.4, a well-formed frame ends with the line held at mark for at least the configured stop duration. The receiver, having anchored its timing to the accepted start edge, schedules one sample inside that interval — 9.5 UI from the candidate in 8N1, 10.5 UI in 8E1 (Chapter 6.3 §7).
expected at the stop sample: MARK (1)
observed: SPACE (0) -> framing errorThe check is a comparison against a constant, and its entire information content is the level of one sample. The receiver does not measure the stop interval's width, does not compare it against the bit period, and does not look at the line before or after that instant.
That is a deliberate architecture, not a limitation to be fixed. Measuring the stop interval's duration would require a second timing reference, and the receiver has only the one it derived from the start edge — the reference whose accuracy is in question whenever a framing error occurs.
2. Event and Verdict Are Different Signals
Two things are wanted from the check, and conflating them is the most common structural mistake:
frame_error_o — the verdict | frame_error_evt_o — the event | |
|---|---|---|
| Shape | a level | a one-cycle pulse |
| Means | this frame's stop sample failed | a stop sample failed on this clock |
| Valid | from the stop sample until the next frame starts | for exactly one cycle |
| Cleared by | the next accepted start | nothing — it is an edge |
| Consumed by | the byte's status, alongside the data | the sticky aggregator of Chapter 9.6 |
The verdict answers a question about a byte. The event answers a question about a moment. A sticky flag built by ORing the verdict would stay set for as long as the verdict is held, which is most of a frame time — so it would be indistinguishable from a flag that was never cleared. Built from the event, it accumulates discrete occurrences, which is what a diagnostic register should count.
Chapter 3.4 published the verdict half of this and explicitly deferred the rest here:
How the flag is latched, presented and cleared is Module 9's.
3. The RTL
// ---------------------------------------------------------------------------
// 9.1 — framing verdict. Chapter 3.4 published the per-frame clear; this adds
// the event pulse and the explicit lifetime Module 9 owns.
// ---------------------------------------------------------------------------
module uart_frame_check
import uart_line_pkg::*;
(
input logic clk,
input logic rst_n,
input logic frame_start_i, // a start has been ACCEPTED (Chapter 5.2)
input logic sample_stop_i, // the stop position, one cycle (Module 5)
input logic rx_sampled_i, // the synchronised line at that instant
output logic frame_error_o, // per-frame verdict, valid after the stop sample
output logic frame_error_evt_o // ONE cycle, on the stop sample, when low
);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
frame_error_o <= 1'b0;
frame_error_evt_o <= 1'b0;
end else begin
frame_error_evt_o <= 1'b0; // default: one-cycle pulse
if (frame_start_i) begin
frame_error_o <= 1'b0; // new frame, new verdict
end else if (sample_stop_i) begin
frame_error_o <= (rx_sampled_i != UART_MARK);
frame_error_evt_o <= (rx_sampled_i != UART_MARK);
end
end
end
endmoduleThe hardware is two flip-flops and a comparator. frame_error_o holds the verdict; frame_error_evt_o is default-assigned low every cycle so it can only ever be a one-cycle pulse — the same pattern the receiver used for sample_now in Chapter 6.3. The comparison against UART_MARK is a single inverter once synthesis resolves the constant.
frame_start_i clears the verdict, not the event. Each frame gets its own verdict, so a framing error reports on the frame that just ended rather than persisting from an earlier one. The event has no lifetime to clear.
Reset leaves the verdict clear. A receiver out of reset has not yet judged any frame, and reporting an error it never observed would be worse than reporting nothing.
Valid stop versus framing error
11 cycles4. What the Error Is Consistent With
The observation is "not mark at one instant". Several very different physical situations produce it, and the flag alone cannot separate them.
| Cause | Why the stop sample is low | Distinguishing evidence |
|---|---|---|
| Rate mismatch | the sample has drifted out of the stop interval into the next frame's start bit | errors rise with frame length; measure the far end's actual bit period |
| Wrong frame configuration | the far end sends fewer intervals than expected, so the stop sample lands on data | errors are configuration-dependent, not rate-dependent; the payload is also wrong |
| Noise at that instant | a transient crossed the threshold during the sample | intermittent, uncorrelated with frame length, and the payload is usually right |
| Line held low | the wire is stuck, or the far end is transmitting a break | every frame fails and the line never returns to mark — Chapter 9.4 |
| Mid-frame attach | the receiver anchored to a data edge, so its "stop" is arbitrary | first frame after connection or reset — Chapter 9.5 |
5. Back-to-Back Frames Are Not a Framing Error
A legitimate next frame begins its start bit immediately after the stop interval ends — Chapter 7.4 showed a transmitter doing exactly that with no idle gap, and Chapter 6.5 §6 showed the receiver handling it at full rate.
That means the line goes low very shortly after the stop sample, and a check written carelessly can see it:
// WRONG — samples the line after the stop interval rather than inside it,
// so a back-to-back frame's start bit is misread as a failed stop.
if (stop_interval_ended_i) frame_error <= ~rx_sampled_i;The correct check samples at the stop interval's centre, which is half a bit period before the interval ends and a full bit period before the next start bit could begin. The receiver's own schedule already puts it there, and this is one more reason the sampling position is defined as a centre rather than a boundary (Chapter 2.5).
The practical symptom of getting it wrong is distinctive: framing errors that appear only under sustained traffic and vanish when the link is idle between frames. A link that works at low throughput and fails at high throughput, with correct payload throughout, points here rather than at the rate.
6. Verification
Every negative test needs a positive control. A framing checker that asserts on everything passes all negative testing. From this module's simulation:
| Stimulus | Expected | Result |
|---|---|---|
| valid stop sampled mark | no error | pass |
| stop sampled space | error raised, event pulsed, sticky set | pass |
| line low away from the stop sample, mark at it | no error | pass |
| clean frame following a failed one | verdict clears, sticky persists | pass |
The third row is the one that catches a checker watching the wrong window, and the fourth separates the verdict's lifetime from the sticky flag's — a distinction Chapter 9.6 develops.
// Assertion — the verdict changes only at a stop sample or a frame start.
// It is a per-frame value, so nothing else may disturb it.
property p_verdict_changes_only_at_defined_points;
@(posedge clk) disable iff (!rst_n)
$changed(frame_error_o) |-> $past(sample_stop_i) || $past(frame_start_i);
endproperty
assert property (p_verdict_changes_only_at_defined_points);
// Assertion — a low stop sample always produces the event.
property p_low_stop_implies_event;
@(posedge clk) disable iff (!rst_n)
(sample_stop_i && !rx_sampled_i) |=> frame_error_evt_o;
endproperty
assert property (p_low_stop_implies_event);
// Assertion — and a mark stop sample never does.
property p_mark_stop_no_event;
@(posedge clk) disable iff (!rst_n)
(sample_stop_i && rx_sampled_i) |=> !frame_error_evt_o;
endproperty
assert property (p_mark_stop_no_event);
// Assertion — the event is never longer than one cycle.
property p_event_is_a_pulse;
@(posedge clk) disable iff (!rst_n)
frame_error_evt_o |=> !frame_error_evt_o;
endproperty
assert property (p_event_is_a_pulse);The third property is the positive control expressed formally, and it is the one most often omitted — a checker that fires on every stop sample satisfies the second property perfectly.
7. Debugging
8. What This Means on an FPGA
Probe the stop sample, not just the flag. Bringing out sample_stop_i alongside rx_sync_q on a logic analyser shows the level at the instant the receiver judged it, which answers the question the flag only summarises. A capture showing the stop sample landing near a transition rather than in the middle of a stable interval is direct evidence of drift.
The check costs nothing and belongs in every receiver. Two flip-flops. There is no design in which omitting the framing check is a sensible saving, and a receiver without one silently accepts frames whose alignment has already failed.
Count events, do not just observe the flag. An event counter — even four bits — turns "we see framing errors sometimes" into a rate that can be correlated with traffic, temperature and configuration. Chapter 9.6 builds the sticky flag; a counter alongside it is often more useful for bring-up than the flag itself.
Expect the first frame after connection to fail. A receiver attaching to an already-active line has no way to know it joined mid-frame — Chapter 6.2 §7 demonstrated a fabricated byte arising exactly this way. One framing error at start-up is normal; Chapter 9.5 shows what suppressing it costs.
9. Understanding Check
10. Summary
A framing error is one sampled bit at one instant: at the configured stop-sample position, the line was not at mark. The receiver does not measure the stop interval's width, because that would require a second timing reference it does not have.
The verdict and the event are different signals. The verdict is a level describing one frame, cleared by the next accepted start; the event is a one-cycle pulse describing a moment, and it is what a sticky flag should accumulate. Building the sticky flag from the verdict makes a single error indistinguishable from a flag never cleared.
The observation is consistent with rate mismatch, wrong configuration, noise, a line held low, or a mid-frame attach — and the flag alone separates none of them. It does not mean the baud rate is wrong, and equally, a clean error log does not mean the rate is right: the failure is a cliff, so a link can be several percent off and perfectly clean.
The distinguishing evidence is frame length: a rate mismatch fails longer configurations first, because the displacement grows with the interval index.
Back-to-back frames are not framing errors — but a check that samples at the stop interval's end rather than its centre will report them as such, producing errors that appear only under sustained traffic with correct payload throughout.
Verified in simulation with a positive control for every negative case, including a disturbance placed away from the stop sample that must not raise the flag.
11. What Comes Next
A framing error says the frame's shape was wrong. It says nothing about whether the bits inside it were right.
Chapter 9.2 takes the other check the receiver performs. It shows exactly which corruptions parity detects and which it provably cannot — by exhaustive enumeration rather than assertion — and establishes the distinction that matters most for anyone relying on it: a parity check that passes does not mean the data is correct, only that a specific relation holds.
Browse the full path on the UART tutorials index. For the stop interval this chapter validates, read back to Chapter 3.4; for the drift that displaces its sample, Chapter 5.5.
Continue learning
Related tutorials
- Related topic
Parity Check, Stop-Bit Validation and Error Status
The receiver decides whether a frame was good, then faces the harder question: which frame does each status flag describe? Getting that wrong lets an incoming frame rewrite the status of a byte the consumer has not yet read.
- Related topic
Parity Errors and the Limits of Detection
Parity detects every odd-weight corruption and provably misses every even-weight one — shown by exhaustive enumeration. A check that passes says a relation holds, not that the data is correct.
- Related topic
Overrun, Underrun and Data Loss
Overrun is a protocol-level consequence of a full holding register; transmit starvation is an architecture-dependent system event. Both lose information an error flag records but cannot recover.
- Related topic
Break Conditions: Generation and Detection
A start bit is also low, so a break cannot be detected by looking at the line. It is the one UART condition defined by duration — which means a counter, a derived threshold, and a saturation policy.
Where this fits
Part of the UART curriculum.
