UART · Module 4
The UART Timing Budget: How Much Mismatch a Frame Survives
The familiar five percent is the exact output of one idealised model with five stated assumptions, all false in hardware. Putting the terms back shows the usable budget moving by a quarter of its value under ordinary implementation choices — which is why the number belongs to a design, not to UART.
Every chapter since Chapter 2.5 has produced a term and declined to add them up. This chapter adds them up.
The question it answers is the one engineers actually ask — how much clock mismatch can a UART link tolerate? — and the reason it has taken four modules to reach is that the question has no answer until a model is stated. Ask it of a specific design and it has a precise, computable answer. Ask it of UART and it does not.
This chapter does both. It derives the number that folklore quotes, exactly, from assumptions written down in full. Then it adds the terms those assumptions omitted and watches the usable budget fall — by enough to matter, in a direction that is always the same.
1. What the Budget Is
Chapter 2.5 established the geometry. A receiver aims at the centre of a bit cell, and the distance from there to either boundary is half a bit period. That half-bit is the entire resource:
available margin = 0.5 UI, one sideEverything that displaces the sampling instant from the true centre spends from it, and the frame fails at the first interval where the spend exceeds the available margin. Because one term — accumulated drift — grows with the interval index, the binding case is always the frame's last interval, at n = N_frame − 1.
The budget is therefore an inequality evaluated at that index:
0.5 > δ_origin + δ_sample + (N_frame − 1) x ε_rel + δ_reservewhere, using the notation of Chapter 4.1:
| Term | What it is | Owned by |
|---|---|---|
δ_origin | uncertainty in where the frame's origin was recorded | Chapter 2.3 |
δ_sample | granularity and width of the sampling decision | Module 5 |
ε_rel | relative rate mismatch between the endpoints | Chapter 2.4, 4.3, 4.4 |
N_frame | intervals per frame | Chapter 3.5 |
δ_reserve | margin deliberately left unspent | the designer |
2. The Idealised Bound, Derived
Set every implementation term to zero. State the assumptions explicitly, because they are the whole point:
ASSUMPTIONS OF THE IDEALISED MODEL
1. the origin is recorded exactly δ_origin = 0
2. sampling occurs at an exact instant, at the
exact centre of the cell δ_sample = 0
3. no margin is reserved δ_reserve = 0
4. the bit cell is stable across its full width
5. failure occurs exactly at 0.5 UI of displacementThe inequality collapses to:
0.5 > (N_frame − 1) x ε_rel
ε_rel,max = 0.5 / (N_frame − 1)Evaluated across the configurations from Chapter 3.5:
| Configuration | N_frame | worst n | ε_rel,max under the idealised model |
|---|---|---|---|
| 5N1 | 7 | 6 | 8.333% |
| 8N1 | 10 | 9 | 5.556% |
| 8E1 | 11 | 10 | 5.000% |
| 8N2 | 11 | 10 | 5.000% |
| 8E2 | 12 | 11 | 4.545% |
| 9E2 | 13 | 12 | 4.167% |
Notice already that the idealised bound is a function of N_frame. Even before any implementation term, the answer depends on the configuration — 8.333% at 5N1 and 4.167% at 9E2, a factor of two across ordinary choices. A single number for "UART" could not be right even in the idealisation.
3. Putting the Assumptions Back
Take a concrete design and compute each term. 100 MHz fabric clock, 115,200 baud, 8N1, far end specified at ±0.5%.
δ_origin — start-edge quantisation. Chapter 2.3 §8 established that the receiver records the origin at its next clock edge, so the recorded origin is late by up to one clock period:
δ_origin = T_clk / T_bit = (1/100,000,000) / (1/115,200) = 0.001152 UILocal divider error. Chapter 4.3 computed ε = +0.006400% for N_div = 868, accumulated over nine intervals:
0.000064 x 9 = 0.000576 UIFar-end frequency error. Specified at ±0.5%, accumulated over nine intervals:
0.005 x 9 = 0.045000 UISumming:
| Term | UI | Share of the 0.5 available |
|---|---|---|
δ_origin — start-edge quantisation | 0.001152 | 0.23% |
| local divider error × 9 | 0.000576 | 0.12% |
| far-end ±0.5% × 9 | 0.045000 | 9.00% |
| total spent | 0.046728 | 9.35% |
| remaining | 0.453272 | 90.65% |
The far end dominates by a factor of 26. The two terms this module spent three chapters computing — the divider's residual and the quantisation of the origin — together account for 0.35% of the budget, while the far end's crystal accounts for 9%.
That is the honest conclusion, and it is worth stating plainly: at ordinary rates, the divider is not the problem. Chapter 4.3 and Chapter 4.4 taught how to compute a term that usually turns out to be negligible — which is exactly the value of computing it rather than guessing.
Solving for the largest far-end error this design could survive:
ε_far,max = (0.5 − 0.001152 − 0.000576) / 9 = 5.5364%against the idealised 5.5556%. The implementation terms cost 0.02 percentage points. At this pairing the folklore number is very nearly right — which is precisely why it survives.
4. Where the Budget Actually Collapses
Change one thing and the picture is different. Take the same design at 1 Mbaud, where Chapter 4.2 showed 100 MHz divides exactly by 100, so the divider error is zero:
δ_origin = (1/100,000,000) / (1/1,000,000) = 0.010000 UI8.68 times larger, because δ_origin is a fixed absolute quantity — one clock period — measured against a bit period that is now 8.68 times shorter. The divider improved to perfection and the origin term grew by nearly an order of magnitude.
Now add the term Module 5 owns. A receiver that positions its sampling instant on a grid of sixteen positions per bit cannot place it closer than 1/16 UI to the true centre; one using eight positions cannot get closer than 1/8 UI. Module 5 decides which, and what else the strategy costs; here it enters as a value:
| Design | δ_origin | divider | far end ±0.5% | δ_sample | Total spent | ε_far,max |
|---|---|---|---|---|---|---|
| 115,200, no sampling term | 0.001152 | 0.000576 | 0.045 | — | 0.046728 | 5.5364% |
| 1 Mbaud, no sampling term | 0.010000 | 0 | 0.045 | — | 0.055000 | 5.4444% |
| 1 Mbaud, 1/16 UI sampling | 0.010000 | 0 | 0.045 | 0.0625 | 0.117500 | 4.7500% |
| 1 Mbaud, 1/8 UI sampling | 0.010000 | 0 | 0.045 | 0.1250 | 0.180000 | 4.0556% |
From 5.44% to 4.06% — a 26% reduction — with no change to the protocol, the configuration or the far end. Only the implementation changed.
5. What Failure Looks Like
The inequality predicts not just whether a frame fails but where. At ε_rel = 6% — above the 8N1 idealised bound of 5.556% — the displacement crosses half a bit during the frame:
0.06 UI per interval — inside at n=8, outside at n=9
10 cyclesOne interval fails and the rest are correct, which is the signature Chapter 2.4 §7 described and this chapter now explains quantitatively. Three practical consequences follow.
The symptom is a framing error, not a data error. The last interval of a frame is the stop condition, so an out-of-budget link fails its stop check first (Chapter 3.4). An engineer seeing framing errors with otherwise plausible payloads should compute this budget before suspecting the framing configuration.
A shorter configuration may work where a longer one does not. The same ε_rel against 5N1 has only six intervals to accumulate over — 0.36 UI at 6%, comfortably inside. A link that fails at 8E2 and works at 8N1 is not behaving mysteriously; it is demonstrating the N_frame dependence.
The failure is a cliff, not a degradation. Below the budget every interval is sampled correctly and the link is perfect. Above it, the last interval fails on every frame. There is no region of gradually increasing error rate, because nothing here is statistical — which makes a marginal link look completely healthy until it does not.
6. Computing the Budget of a Real Design
The procedure is short enough to carry out on paper, and it is worth encoding so it cannot be skipped.
- Take
N_framefrom the configuration and usen = N_frame − 1. - Compute
δ_originasT_clk / T_bit, plus any bounded delay the input boundary adds. - Compute the local rate error from the divider (Chapter 4.3) and multiply by
n. - Take the far end's specification over the operating temperature range, not at room temperature, and multiply by
n. - Take
δ_samplefrom the sampling strategy (Module 5). - Choose
δ_reservedeliberately. - Check that the sum is below 0.5, and if solving for a tolerance, subtract the fixed terms before dividing by
n.
// Synthesizable SystemVerilog — elaboration-time budget check. Infers no
// hardware. Every term is in parts per million of a bit period, so the
// arithmetic is integer throughout and the units are the UI of §1.
//
// This is the inequality of §1 made into a build-time gate. The sampling
// term is a parameter because Module 5 owns its value; the far-end term is
// a parameter because only the integrator knows the part and its range.
module uart_budget_check #(
parameter int unsigned CLK_HZ = 100_000_000,
parameter int unsigned BAUD_HZ = 115_200,
parameter int unsigned N_FRAME = 10, // Chapter 3.5
// Implementation terms, ppm of one bit period.
parameter int unsigned SAMPLE_PPM = 62_500, // 1/16 UI — Module 5
parameter int unsigned RESERVE_PPM = 50_000, // 0.05 UI held back
// Far-end frequency error over the operating range, ppm. NOT the
// room-temperature figure, and NOT one endpoint's half of it.
parameter int unsigned FAR_END_PPM = 5_000 // 0.5%
) ();
localparam int unsigned WORST_N = N_FRAME - 1;
localparam int unsigned HALF_BIT = 500_000; // 0.5 UI in ppm
// delta_origin = T_clk / T_bit = BAUD_HZ / CLK_HZ, in ppm.
// Multiply before dividing: BAUD_HZ * 1e6 overflows nothing at these
// magnitudes and dividing first would truncate to zero.
localparam int unsigned ORIGIN_PPM = (BAUD_HZ * 1_000_000) / CLK_HZ;
// Local divider error, ppm: |f_clk/N_div - f_baud| / f_baud.
localparam int unsigned N_DIV = (2*CLK_HZ + BAUD_HZ) / (2*BAUD_HZ);
localparam int unsigned ACTUAL_HZ = CLK_HZ / N_DIV;
localparam int unsigned DIV_PPM = (ACTUAL_HZ > BAUD_HZ)
? ((ACTUAL_HZ - BAUD_HZ) * 1_000_000) / BAUD_HZ
: ((BAUD_HZ - ACTUAL_HZ) * 1_000_000) / BAUD_HZ;
// Only the rate terms accumulate across the frame.
localparam int unsigned SPENT_PPM =
ORIGIN_PPM
+ SAMPLE_PPM
+ RESERVE_PPM
+ WORST_N * (DIV_PPM + FAR_END_PPM);
initial begin
if (SPENT_PPM >= HALF_BIT)
$fatal(1,
"uart_budget_check: %0d ppm spent of %0d available at interval %0d (origin %0d, sample %0d, reserve %0d, rate %0d x %0d)",
SPENT_PPM, HALF_BIT, WORST_N,
ORIGIN_PPM, SAMPLE_PPM, RESERVE_PPM, WORST_N, DIV_PPM + FAR_END_PPM);
else
$info("uart_budget_check: %0d ppm spent of %0d, %0d ppm remaining",
SPENT_PPM, HALF_BIT, HALF_BIT - SPENT_PPM);
end
endmoduleOnly the rate terms are multiplied by WORST_N. ORIGIN_PPM, SAMPLE_PPM and RESERVE_PPM are fixed displacements that do not grow within a frame; the divider error and the far end's error do. Multiplying a fixed term by n overstates the budget enormously and is the easiest way to get this arithmetic wrong.
FAR_END_PPM is the combined figure, and the comment says so. Chapter 2.4 §4 established that two endpoints each within 0.5% can be 1% apart. A parameter named for one side invites exactly that error, which is why the comment states the convention rather than assuming it.
Every term is ppm of a bit period, so the arithmetic is integer, portable, and directly comparable with the tables above. The error message prints the terms separately, because a budget failure is only actionable if you know which term dominated.
What it cannot check is whether FAR_END_PPM is honest. A design whose integrator supplies a room-temperature figure passes and fails in the field, which is why step 4 above says what it says.
7. Verification and Measurement
Test at the boundary the design computes, not at a quoted number. §4 showed the budget differs between designs built to the same specification, so the cases that matter are placed around this design's figure: comfortably inside, just inside, just outside, and far outside — with the outside cases expected to fail, and checked that they fail as §5 predicts.
Assert the failure signature, not just the failure. A design just outside budget should corrupt the last interval of the frame and nothing earlier. A checker that only compares final byte values sees a corrupted result and cannot distinguish a timing-budget failure from a framing-configuration error. One that records which interval failed distinguishes them immediately — and catches a wrong-direction defect, where a design fails at the start of frames, which indicates an origin problem rather than a drift problem.
Sign matters in the stimulus. ε_rel is a difference, so (+0.5%, −0.5%) and (+1.0%, 0) are nearly equivalent in magnitude and a generator that varies one combined knob cannot tell them apart. Driving the two endpoints independently is what covers the opposite-sign case that Chapter 2.4 §4 identified as the hard one.
Frame length is an axis, and the longest supported configuration is the worst case by the N_frame − 1 factor — which also means a budget verified only at 8N1 says nothing about a design that also supports 8E2.
And the cliff is what makes soak testing useless here. §5 established that below budget every frame is perfect and above it every frame fails at the same interval. There is no intermediate error rate to discover by running for longer, so duration buys nothing and parameter variation buys everything.
8. What This Means on an FPGA
Compute δ_origin before choosing a rate. It is T_clk / T_bit, so it scales directly with the rate: 0.00115 UI at 115,200 from 100 MHz, and 0.01 UI at 1 Mbaud from the same clock. Pushing the rate up grows this term proportionally while the divider term may improve or vanish — the two move in opposite directions, and only the sum matters.
Budget the far end over temperature, and combined. It is the dominant term by a factor of 26 in §3's example, so it is the one worth getting right. Room-temperature figures and single-endpoint figures are the two ways to get it wrong, and both are optimistic.
Reserve deliberately. §6's RESERVE_PPM exists so the decision is recorded rather than implicit. A design that leaves nothing passes its own check and has no tolerance for a part at the edge of its distribution.
And when a link fails, compute before probing. Framing errors with plausible payloads, failing at the end of frames, on longer configurations first, with a cliff rather than a gradual onset — that combination is this chapter's signature, and the budget computation confirms or eliminates it in five minutes without instrumenting anything.
9. Understanding Check
10. Summary
The budget is one inequality evaluated at the frame's last interval:
0.5 > δ_origin + δ_sample + (N_frame − 1) x ε_rel + δ_reserveSetting every implementation term to zero gives ε_rel,max = 0.5 / (N_frame − 1), which for 8N1 is 5.556% — the origin of the familiar figure. That derivation assumes an exact origin, instantaneous centre sampling, no reserve, a perfectly stable bit cell and clean failure at half a bit. All five are false in hardware, and the bound is configuration-dependent even within the idealisation: 8.333% at 5N1, 4.167% at 9E2.
Putting the terms back for 100 MHz, 115,200, 8N1 with a ±0.5% far end: the origin costs 0.001152 UI, the divider 0.000576 UI, and the far end 0.045 UI. The far end dominates by a factor of 26, and the implementation terms cost only 0.02 percentage points of tolerance — which is why the folklore figure survives at ordinary rates.
It does not survive elsewhere. The same design at 1 Mbaud has an origin term 8.68× larger because the bit period shrank, and adding a sampling granularity of 1/8 UI brings the tolerance to 4.056% — a 26% reduction with no change to the protocol, the configuration or the far end. Six implementation choices are hidden inside any quoted number, and none of them is stated.
Failure is a cliff: below budget every interval is correct, above it the frame's last interval fails and the rest do not. The symptom is a framing error with plausible payloads, appearing on longer configurations first — which makes it diagnosable by computation before any instrument is connected.
11. Where Module 4 Leaves You
Five chapters have turned a configuration field into an engineering quantity.
Chapter 4.1 separated signalling rate from delivered payload and established the module's notation. Chapter 4.2 explained why the standard rates exist and showed, by prime factorisation, why a modern fabric clock cannot divide onto them. Chapter 4.3 made rounding a decision with a measured cost and built the counter that implements it. Chapter 4.4 kept the remainder instead of discarding it, and found that the quantity it improves is one a UART receiver never measures. This chapter assembled every term into a budget, derived the famous number exactly, and then showed it moving by a quarter of its value under ordinary implementation choices.
An engineer holding this chain can be handed a clock frequency, a rate, a configuration and a far-end datasheet, and produce a defensible tolerance — together with the knowledge of which term to improve if it is not enough.
12. What Comes Next
δ_sample has appeared in every budget in this chapter as a term with a symbol and no derivation. It is the largest implementation term in §4's table, and it belongs to a decision this module has deliberately not made: how a receiver decides when to sample.
Module 5 makes it. It establishes why reception is the harder half, how a start edge is qualified rather than merely detected, what oversampling strategies exist and what each costs in granularity and noise immunity, and how the sampling instant behaves as clock mismatch consumes the margin this chapter has just budgeted.
Browse the full path on the UART tutorials index. For a timing budget assembled from the same kind of terms but closed by periodic re-training rather than by ending a frame, see Write Levelling.
Continue learning
Related tutorials
- Related topic
Integer Dividers and Baud-Rate Error
The ratio is a fraction and a counter holds an integer, so rounding is a design decision with a measurable cost. Three policies, the actual rate each produces, and why the error belongs in units of a bit period rather than as a bare percentage.
- Related topic
Sampling Under Clock Mismatch
Walk the receiver's sampling positions across a real frame under a real frequency error: the migration in oversample ticks, why the final interval always fails first, and why a voting window fails before a single sample would.
- Related topic
What a UART Actually Is
Two digital systems need to exchange a small amount of data over very few wires, and no clock travels with it. A UART is the logic that answers that problem — it converts between locally meaningful parallel data and timed activity on a single line, and the timing agreement it depends on is what the rest of the curriculum builds.
- Related topic
Synchronous vs Asynchronous Serial Links
A forwarded clock is a sampling reference generated by the same source as the data. Remove it and the receiver must assemble one from a configured rate, an observable event in the signal, and its own local clock — the responsibility shift that turns a receiver into a state machine and shapes every UART design decision that follows.
Where this fits
Part of the UART curriculum.
