UART · Module 4
Fractional Baud Generation
An accumulator keeps the remainder an integer divider discards, lengthening an occasional interval so the average converges on the ideal. That improves long-run accuracy by orders of magnitude while making individual intervals unequal — and a UART receiver never measures the average.
Chapter 4.3 discarded the fractional part of the ideal divisor and showed that at ordinary rates the cost is negligible — about 0.0006 UI over an 8N1 frame at 100 MHz and 115,200.
But it was discarded permanently. Every interval is the same integer length, so the residual error is systematic: the same sign, the same magnitude, on every interval, forever. It never averages out, because there is nothing to average against.
This chapter asks what happens if the remainder is kept. The mechanism is an accumulator, and the result is a genuine trade rather than a free improvement: the average gets dramatically better and the individual intervals get worse. Understanding which of those a link actually cares about is the engineering content.
1. The Problem With a Permanently Discarded Remainder
Recall the arithmetic from Chapter 4.2:
100,000,000 / 115,200 = 15,625 / 18 = 868.0555...An integer divider chooses 868 and throws 0.0556 away. Every interval is therefore short by 0.0556 clock cycles — about 0.556 ns — and since every interval is short by the same amount in the same direction, the shortfall accumulates:
ε = +0.006400% (Chapter 4.3)Over nine intervals that is +0.000576 UI, which Chapter 4.3 correctly called negligible. The interesting observation is why it is negligible: not because the mechanism is good, but because the divisor is large. At 868 cycles per interval, half a cycle of rounding is a small fraction. The same mechanism at a divisor of 20 leaves an error 40 times larger.
So the question is not whether integer division is acceptable — sometimes it obviously is — but whether a design can do better when it needs to, and what that costs.
2. Keep the Remainder
The idea is arithmetic before it is hardware. If the ideal divisor is 868.0556, then over 18 intervals the ideal total is:
18 x 868.0556 = 15,625 clock cyclesAn integer divider produces 18 x 868 = 15,624 — one cycle short over 18 intervals. So emit 17 intervals of 868 cycles and one of 869, and the total is exactly right. The average interval is exactly the ideal; only the individual intervals differ.
Generalising, that is the whole mechanism:
ideal = N_int + frac with 0 <= frac < 1
each interval is N_int cycles, except that a fraction `frac` of
intervals are lengthened to N_int + 1The hardware that decides which intervals are lengthened is an accumulator. Choose a width W, and represent the fraction as an integer increment:
INC = round(frac x 2^W)
every interval: acc = acc + INC
if acc overflows 2^W:
acc = acc − 2^W
this interval is N_int + 1 cycles
else:
this interval is N_int cyclesThe accumulator is a fixed-point remainder. Each interval it collects INC, and when the collected remainder reaches a whole cycle it is spent by lengthening one interval.
3. The Sequence, Worked
At W = 8, the fraction 0.0556 becomes:
INC = round(0.055556 x 256) = 14Running the accumulator from zero produces a completely deterministic sequence. Intervals 14 through 23:
One long interval every 256/14 ≈ 18.3 intervals
10 cyclesOne interval in every 256 / 14 ≈ 18.3 is lengthened. For an 8N1 frame of ten intervals, that means most frames contain no correction at all and roughly every other frame contains one — which is worth holding onto when §5 considers what a receiver experiences.
What it buys
The effective divisor becomes:
N_eff = 868 + 14/256 = 868.054688
f_actual = 100,000,000 / 868.054688 = 115,200.1152 baud
ε = +0.000100% = +1.00 ppmagainst the integer divider's +0.006400% (+64.0 ppm):
| Scheme | Effective divisor | Actual rate | ε | ppm |
|---|---|---|---|---|
Integer, N = 868 | 868 | 115,207.3733 | +0.006400% | +64.0 |
Fractional, W = 8 | 868.054688 | 115,200.1152 | +0.000100% | +1.00 |
Fractional, W = 16 | 868.055557 | 115,200.0 | ≈ 0 | −0.002 |
A 64× improvement for eight bits of accumulator, and essentially exact representation at sixteen. The residual comes only from quantising the fraction itself into W bits, so it shrinks geometrically with width — which is why fractional generators are cheap to make accurate once the mechanism exists at all.
4. What It Costs: Unequal Intervals
The improvement is in the average. Individual intervals are now worse than the integer divider's, and precisely so:
T_bit (ideal) = 8680.556 ns
interval of 868 = 8680.000 ns deviation −0.556 ns = −0.0064% of T_bit
interval of 869 = 8690.000 ns deviation +9.444 ns = +0.1088% of T_bit
peak-to-peak variation = one clock cycle = 10.000 ns = 0.1152% of T_bitSo the integer divider produces intervals that are all 0.0064% short, while the fractional generator produces intervals that are mostly 0.0064% short and occasionally 0.1088% long. The worst single interval is seventeen times further from nominal than anything the integer divider produced.
That is the trade, and it is worth stating as a principle: fractional generation converts a small systematic error into a larger bounded one that averages away.
5. Which Error Does a Link Actually Care About?
Now the judgement the chapter exists for, and the answer is not "the smaller number".
A receiver re-acquires its timing origin every frame (Chapter 2.3). It never integrates timing across more than one frame, so a rate error only matters through its accumulation over N_frame − 1 intervals — the result Chapter 2.5 evaluates.
That has a sharp consequence. The long-run average accuracy that fractional generation improves is a quantity no UART receiver ever measures. What the receiver experiences is the intervals of one frame, and over an 8N1 frame from §3's generator most frames contain no correction at all.
So compare what the receiver actually sees:
| Over one 8N1 frame (9 intervals) | Peak displacement within the frame |
|---|---|
Integer N = 868 | 0.000576 UI |
Fractional W = 8, frame with no long interval | 0.000576 UI |
Fractional W = 8, worst case — long interval first | 0.001088 UI |
(Peak displacement is the largest cumulative deviation from the nominal grid at any point in the frame, which is where the long interval falls earliest.)
Both are far below the half-bit budget, so at this pairing neither scheme is the constraint and the choice does not matter. But notice the direction: within a single frame the fractional generator's worst case is 1.89× larger than the integer divider's, because the one long interval displaces the grid by more than the systematic error accumulates over nine.
6. The Hardware, in Outline
The structure follows directly from §2, and the point of showing it is that it is barely larger than the integer divider.
// Conceptual SystemVerilog — the accumulator mechanism only.
//
// Shows how INC is derived and how the carry extends one interval. The
// PRODUCTION generator is Chapter 8.3: reset and start-up behaviour,
// runtime reconfiguration, whether RX and TX share an accumulator, and
// how the residual error is reported all belong there. This block is
// written to make Section 2's arithmetic concrete, not to be instantiated.
module uart_frac_accum #(
parameter int unsigned CLK_HZ = 100_000_000,
parameter int unsigned BAUD_HZ = 115_200,
parameter int unsigned ACC_W = 8 // fraction resolution
) (
input logic clk,
input logic rst_n,
input logic interval_done_i, // one pulse at the end of each bit interval
output logic extend_o // make the NEXT interval one cycle longer
);
// Integer part, floor — the fraction is handled separately, so floor
// is correct here rather than nearest (contrast Chapter 4.3 §1).
localparam int unsigned N_INT = CLK_HZ / BAUD_HZ;
// INC = round(frac x 2^ACC_W), computed with integer arithmetic:
// frac x 2^W = ((CLK_HZ % BAUD_HZ) x 2^W) / BAUD_HZ
// The +BAUD_HZ/2 before dividing performs round-half-up.
localparam int unsigned REMAINDER = CLK_HZ % BAUD_HZ;
localparam int unsigned INC =
(((REMAINDER << ACC_W) + (BAUD_HZ / 2)) / BAUD_HZ);
// One bit wider than the fraction, so the carry out is bit ACC_W.
logic [ACC_W:0] acc_q;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
acc_q <= '0;
extend_o <= 1'b0;
end else if (interval_done_i) begin
// Add INC into the low ACC_W bits; bit ACC_W is the carry.
// Assigning the sum back with the carry bit cleared is the
// "subtract 2^ACC_W" of Section 2.
acc_q <= {1'b0, acc_q[ACC_W-1:0]} + ACC_W'(INC);
extend_o <= (({1'b0, acc_q[ACC_W-1:0]} + ACC_W'(INC)) >> ACC_W) != 0;
end else begin
extend_o <= extend_o; // hold across the interval
end
end
endmoduleINC is computed from the remainder, not from a float. CLK_HZ % BAUD_HZ is the numerator of the fraction and BAUD_HZ its denominator, so (REMAINDER << ACC_W) / BAUD_HZ is the fraction scaled by 2^ACC_W in pure integer arithmetic. Elaboration-time arithmetic is integer arithmetic; introducing a real here would be both unnecessary and less portable.
The accumulator is ACC_W + 1 bits wide so the overflow appears as a bit rather than having to be inferred from a comparison. The top bit is the carry, and clearing it when writing back performs the subtraction.
Floor is correct for N_INT here, which contrasts with Chapter 4.3 §1 where nearest was preferred. The reason is that the fraction is no longer being discarded — it is being handled by the accumulator — so rounding the integer part up would double-count it.
What is deliberately missing: the counter and terminal comparison that consume extend_o, the interaction with reset mid-frame, whether the accumulator is reset between frames or free-runs, and what happens when the configuration changes. Every one of those is a real decision and every one belongs to Chapter 8.3.
7. Verification and Measurement
Fractional generation changes what a checker can assert, and getting that wrong produces false failures.
A fixed-interval check is now wrong. The monitor from Chapter 4.3 §6 compares each observed interval against a single expected value. Against a fractional generator it fails on every long interval — correctly detecting behaviour that is correct. The check must become a membership test: every observed interval is N_int or N_int + 1, and nothing else.
The accuracy claim is a long-run property and must be checked as one. Over M intervals the total should be within one cycle of M x ideal:
| sum(observed cycles over M intervals) − M x N_ideal | <= 1That is the assertion that actually captures what fractional generation promises, and it is the one a fixed-interval check cannot express. It also catches a real defect class: an accumulator that loses its remainder — reset between intervals, or wrongly cleared on a configuration write — passes the membership test on every interval and fails this one, because its average silently collapses back to the integer divisor.
Check the pattern's period, not just its values. With INC = 14 and W = 8 the long interval appears every 256/14 ≈ 18.3 intervals. An accumulator that is one bit too narrow, or whose INC was computed with the wrong rounding, produces a different period — which is visible in a long capture and invisible in a short one.
On hardware, the measurement technique from Chapter 4.3 §5 becomes essential rather than merely convenient. Measuring one interval now tells you almost nothing, because you may have measured a long one. Measuring across many intervals averages the pattern out and recovers the effective rate — which is exactly the quantity fractional generation was designed to make accurate.
8. Understanding Check
9. Summary
An integer divider discards the fractional part permanently, so its error is systematic — the same sign and magnitude on every interval, never averaging out. Whether that matters depends on the divisor: at 868 cycles per interval half a cycle of rounding is negligible; at 20 it is not.
A fractional accumulator keeps the remainder. Represent the fraction as INC = round(frac x 2^W), add it once per interval, and when it overflows, spend the accumulated cycle by making that one interval N_int + 1 long. At 100 MHz and 115,200 with W = 8, INC = 14 and one interval in every 256/14 ≈ 18.3 is lengthened.
It buys a 64× improvement in average rate error — +64.0 ppm to +1.00 ppm — for one register, one adder and a carry, improving geometrically with width: W = 16 is accurate to −0.002 ppm.
It costs interval equality. Intervals are mostly 0.0064% short and occasionally 0.1088% long, with a peak-to-peak variation of exactly one clock cycle. That is deterministic interval quantisation, not jitter — bounded, repeatable, and budgeted at its worst case rather than statistically.
The judgement is subtler than "smaller error is better". A UART receiver re-acquires every frame and never measures the long-run average, so the quantity fractional generation improves is one this protocol does not use. Over a single 8N1 frame the fractional generator's worst case is slightly larger than the integer divider's. It earns its place when the divisor is small, or when one generator must serve many rates — and not when it removes a term that was already a thousandth of the budget.
10. What Comes Next
Four chapters have produced terms: framing overhead, the divider's residual error, and the interval quantisation just described. Module 2 produced two more — the receiver's origin uncertainty and the far end's oscillator error — and Chapter 2.5 named the half-bit they are all spent from without assembling them.
Chapter 4.5 assembles the budget. It derives a tolerance from an explicitly stated model, shows exactly which assumptions produce the figure that folklore quotes as "about 5%", and then adds the real terms one at a time to show what the usable budget actually is for a stated design — and why no single number can be correct for all of them.
Browse the full path on the UART tutorials index. For accumulator-based rate generation applied to a different problem, see Clock Dividers and Timers.
Continue learning
Related tutorials
- Related topic
Parity Generation, Checking and Error Detection
One interval, one XOR reduction, and a detection guarantee with a sharp edge: parity catches every corruption that flips an odd number of protected bits and provably misses every even-numbered one — demonstrated, not asserted.
- Related topic
Frame Configurations: 8N1 and the Configuration Space
8N1 names three of the four choices a UART link depends on and omits the one most likely to be wrong. Reading the shorthand, computing what each configuration costs in intervals and line time, and why a longer frame spends timing margin as well as throughput.
- Related topic
Baud Rate, Bit Rate and Real Throughput
A baud figure is a signalling rate, not a delivery rate. Framing overhead, inter-frame gaps and the far end's ability to consume all sit between them — and only the first is computable from the configuration.
- Related topic
Standard Baud Rates and System-Clock Relationships
The familiar rates are what specific oscillator frequencies divide onto exactly, which is why they are powers of two rather than round decimals. A modern fabric clock does not divide onto them, and the prime factorisation shows why it cannot.
Where this fits
Part of the UART curriculum.
