Skip to content
VLSI Mentor

UART · Module 5

Oversampling Strategies: 8×, 16× and the Alternatives

Oversampling is a grid of sample positions inside each bit interval. A higher factor buys placement resolution and costs tick rate, counter width and generator accuracy — and 16× became conventional for an arithmetic reason the standard crystal frequencies make obvious.

Chapter 5.2 used an oversample tick throughout — to count to the validation point, to place the check at the middle of the start interval — without saying where it comes from or how many there are. This chapter supplies it.

The mechanism answers the third of Chapter 5.1's four decisions: where inside each interval should the line be read? A receiver acts on its own clock edges, and Chapter 2.5 established it should aim at the centre of each bit cell. Oversampling is the standard way of getting enough timing resolution to aim.

It is also the place where a piece of UART folklore needs dismantling — and, satisfyingly, where the arithmetic explains exactly where that folklore came from.

1. What Oversampling Is

The receiver generates a periodic event faster than the bit rate, by an integer factor. Call the factor M:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
f_os = M x f_baud                  oversample tick rate

T_os = T_bit / M = 1/M UI          interval between ticks

That is the whole definition. It does not mean the receiver reads the line M times per bit — it may read once, or three times, or any number (Chapter 5.4). What it provides is a grid of M equally spaced positions inside every bit interval, any of which the receiver can choose to act on.

Worked at 115,200 baud, where T_bit ≈ 8680.556 ns:

Mf_osT_osT_os in UI
4460.8 kHz2170.139 ns0.2500
8921.6 kHz1085.069 ns0.1250
161.8432 MHz542.535 ns0.0625
323.6864 MHz271.267 ns0.03125

The tick is a clock enable in the clk domain, not a second clock. Everything in this module and in Module 6 is clocked by clk and qualified by os_tick. Chapter 8.1 gives the full argument; the short version is that a divided clock creates a domain to constrain, distribute and cross in exchange for nothing the enable does not provide.

2. Where 16× Came From

The conventional factor has an arithmetic origin, and Chapter 4.2 already laid the groundwork without saying what it was for.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
16 x 115,200 = 1,843,200 Hz = 1.8432 MHz

That is exactly the crystal frequency Chapter 4.2 identified as dividing cleanly onto the whole classic rate series. The relationship it noted there — 1,843,200 = 115,200 x 16 — was stated as the reason the fastest rate needed a divisor of 1 "once the sampling factor is accounted for". This is the sampling factor.

Check the consequence directly:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1.8432 MHz / (16 x 115,200) = 1        exactly
1.8432 MHz / (8  x 115,200) = 2        exactly

A receiver clocked from that crystal gets its 16× oversample tick with no division at all, and its 8× tick by dividing by two. Every slower rate in the series follows by further halving, because the series is powers of two.

So 16× is not a protocol requirement, a theoretical optimum, or a noise-immunity threshold. It is the factor that made the arithmetic free on the hardware the convention grew up on. That is a perfectly good engineering reason, and it stopped applying the moment designs moved to fabric clocks chosen for other purposes.

3. The Grid, and Where the Samples Go

Fix the origin at the accepted start, per Chapter 5.2's convention: tick 0 at the candidate, with the start interval spanning ticks 0 to M−1.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
start interval centre   =  M/2                ticks   = 0.5 UI
data[k] centre          =  (k + 1.5) x M      ticks   = (k + 1.5) UI
stop centre (8N1)       =  9.5 x M            ticks   = 9.5 UI

The +1.5 is the start interval's full width plus half of the data interval — the geometry Chapter 2.2 established, now expressed in ticks.

Positionticks at M=8ticks at M=16UI
start centre480.5
data[0] centre12241.5
data[1] centre20402.5
data[7] centre681368.5
stop centre (8N1)761529.5

Note that M/2 is where Chapter 5.2 put the validation check — the same position a start-interval sample would use. That is not a coincidence: it is why the same counter serves both, and why validating at the interval centre costs nothing extra.

Sixteen positions per bit — the first ten

10 cycles
Two rows over ten oversample ticks at a factor of sixteen. The synchronised receive line is at the space level throughout, since these ticks fall inside the start interval. The oversample phase counter reads zero through nine across the ten columns. A marker identifies phase eight as the centre of the start interval, equal to the factor divided by two, which is one half of a unit interval from the interval's opening boundary. A phase band notes that the full interval is sixteen ticks wide and only ten are shown.first half of the intervalfirst half of the intervalpast centre — 16 ticks totalpast centre — 16ticks totaltick 0 — origintick 0 — originphase 8 = M/2 = 0.5 UIphase 8 = M/2 = 0.5 UIrx_sync_qos_phase0123456789t0t1t2t3t4t5t6t7t8t9
Figure 1 — the first ten oversample ticks of a frame at M = 16. Each column is one oversample tick, not a fabric-clock cycle and not a bit interval; the full start interval is sixteen ticks wide, so these ten span 10/16 of it. The phase counter reads 8 at the interval's centre, which is both the validation point of Chapter 5.2 and where a sample of the start interval would be taken.

4. What the Factor Buys: Placement Resolution

The receiver can only act on tick boundaries, so its sampling instant lands on a grid of spacing 1/M UI. How far that can be from the true centre depends on the architecture, and the distinction matters enough to state carefully.

The grid step is 1/M UI. At 16× that is 0.0625 UI; at 8×, 0.125 UI.

The worst placement error is not the same as the grid step. If the receiver's grid happens to be offset such that the intended centre falls midway between two ticks, the nearest available position is 1/(2M) UI away. That is the best case bound — 0.03125 UI at 16×, 0.0625 at 8×.

But the grid's own phase is set by the observed candidate, which Chapter 5.2 showed is itself quantised. A receiver that starts its tick counter at the candidate inherits that offset, and cannot round to a nearer position because it has no finer representation of where the true boundary was. In that architecture the placement error can approach a full 1/M UI, which is the conservative figure Chapter 4.5 used.

5. What the Factor Costs

Raising M is not free, and the costs are in different places from the benefit.

The tick must be generated M times faster, and Chapter 4.2's divisibility problem gets M times harder. From a 100 MHz fabric clock:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
100,000,000 / 115,200          = 15,625 / 18   ≈ 868.0556      (Chapter 4.3)
100,000,000 / (8 x 115,200)    = 15,625 / 144  ≈ 108.5069
100,000,000 / (16 x 115,200)   = 15,625 / 288  ≈  54.2535

None divides. Worse, the divisor shrinks as M rises — from 868 down to 54 — and Chapter 4.3 established that rounding error scales roughly as 1/N_div. So a higher oversampling factor makes the tick generator's own rate error larger, partially offsetting the placement resolution it was bought for. The fractional techniques of Chapter 4.4 exist partly for this reason, and Module 8 builds the generator.

Counters get wider and busier. The phase counter must reach M−1, so it needs $clog2(M) bits, and the frame-position counter must reach (N_frame − 0.5) x M ticks. At M = 16 and 8N1 that is 152 — eight bits — where at M = 8 it is 76.

And logic runs M times more often. The tick is an enable, so the receiver's state advances on it; more ticks per bit means more activity, which matters for power on a link that is otherwise almost idle.

M = 8M = 16M = 32
placement grid0.125 UI0.0625 UI0.03125 UI
tick rate at 115,200921.6 kHz1.8432 MHz3.6864 MHz
fabric clocks/tick at 100 MHz≈ 108.5≈ 54.3≈ 27.1
phase counter width3 bits4 bits5 bits
enable activitybaseline

There is no universally correct value. The factor is chosen so that δ_grid fits the budget Chapter 4.5 computes for the specific link — and if the budget has room, a lower factor is cheaper in every dimension.

A receiver timing structure. A tick generator in the fabric clock domain produces a one-cycle oversample enable at M times the baud rate. A phase counter advances on each enable and divides the bit interval into M positions. Comparators against named positions derived from the oversampling factor produce the validation event used for start qualification and the sample events used for reading data intervals. All logic remains in the fabric clock domain, with the oversample event acting as a clock enable rather than as a second clock.tick generatorModule 8 builds itos_tickenable, in clk domainphase counter0 .. M−1sample eventsat named positions== M/2, == 3M/2, …derived, never literalsM x f_baudadvancephasematch12
Figure 2 — where the tick sits in the receiver. The generator produces an enable in the fabric-clock domain; the phase counter divides each bit interval into M positions; comparators against named positions produce the validation and sample events the earlier chapters used. Nothing here is a second clock, and Module 6 assembles these into the receiver's datapath.

6. The Phase Counter

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Synthesizable SystemVerilog — the oversample phase counter only.
// os_tick_i comes from the generator of Module 8. The bit counter, shift
// register and frame sequencing that consume these events are Chapter 6.3;
// this module produces the positions and nothing else.
module uart_os_phase #(
    parameter int unsigned OVERSAMPLE = 16
) (
    input  logic clk,
    input  logic rst_n,
    input  logic os_tick_i,      // one clk cycle, M times per bit interval
    input  logic rephase_i,      // accepted start: restart the grid here
    input  logic active_i,       // inside a frame
    output logic sample_o        // one cycle, at the interval centre
);
    // Every position is DERIVED from the parameter. A literal 8 here is
    // the defect §7 describes: correct at M=16 and silently wrong after.
    localparam int unsigned CENTER = OVERSAMPLE / 2;
    localparam int unsigned PH_W   =
        (OVERSAMPLE <= 1) ? 1 : $clog2(OVERSAMPLE);

    initial begin
        if (OVERSAMPLE < 2)
            $fatal(1, "uart_os_phase: OVERSAMPLE = %0d gives no positions to choose between", OVERSAMPLE);
        if (OVERSAMPLE % 2 != 0)
            $warning("uart_os_phase: OVERSAMPLE = %0d is odd; CENTER = %0d sits one half-tick before the true centre",
                     OVERSAMPLE, CENTER);
    end

    logic [PH_W-1:0] phase_q;

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            phase_q  <= '0;
            sample_o <= 1'b0;
        end else begin
            sample_o <= 1'b0;                     // default: one-cycle pulse

            if (rephase_i) begin
                // The accepted start defines the grid's phase. Everything
                // downstream is counted from here — Chapter 5.2 §4.
                phase_q <= '0;
            end else if (active_i && os_tick_i) begin
                // Fire the sample on the tick that CARRIES the count to
                // CENTER, not on the one after it. One tick of error is
                // 1/M UI: 6.25% of a bit at M = 16.
                sample_o <= (phase_q == PH_W'(CENTER - 1));

                phase_q <= (phase_q == PH_W'(OVERSAMPLE - 1))
                         ? '0                      // wrap into the next interval
                         : phase_q + 1'b1;
            end
        end
    end
endmodule

Width derivation. The counter spans 0 .. OVERSAMPLE-1, so $clog2(OVERSAMPLE) bits — 4 at M = 16. The OVERSAMPLE <= 1 guard exists because $clog2(1) is 0 and a zero-width vector is illegal, the same hazard Chapter 4.3 met.

Why CENTER - 1. The sample fires on the tick that advances the count to CENTER. Comparing against CENTER and acting on the next tick places every sample one grid position late — 1/M UI, which is 6.25% of a bit at M = 16 and is exactly the kind of systematic offset that gets blamed on the baud rate.

Odd factors are warned, not rejected. OVERSAMPLE / 2 truncates, so M = 15 gives CENTER = 7 where the true centre is 7.5 — the sample lands half a tick early. That is a usable design; it is not what the name suggests, and a silent half-tick offset is worth a message.

rephase_i is the architectural statement. The grid's phase is not free-running: it is anchored at the accepted start, which is what makes Chapter 2.3's per-frame re-acquisition concrete. A design whose phase counter free-ran and merely observed the start would inherit accumulated error from previous frames.

7. Verification

The oversampling factor is a first-class axis. A parameterised receiver must be exercised at every supported value, and the interesting cases are the boundaries: the smallest legal factor, the largest, and any odd value if odd factors are permitted. The §6 defect is invisible at the design's default and appears only when the parameter moves.

Assert the position, not just the outcome. A test that only checks the received byte cannot distinguish a sample at the centre from one near a boundary — both read correctly on a clean line. Recording the phase at which each sample fired, and asserting it equals the derived CENTER, catches the off-by-one and the hard-coded literal directly:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Assertion — the sample event occurs only at the derived centre position.
property p_sample_at_center;
    @(posedge clk) disable iff (!rst_n)
        sample_o |-> $past(phase_q == CENTER - 1) && $past(os_tick_i);
endproperty
assert property (p_sample_at_center);

// Assertion — no sample event while the receiver is not in a frame.
property p_no_sample_when_idle;
    @(posedge clk) disable iff (!rst_n)
        !active_i |-> !sample_o;
endproperty
assert property (p_no_sample_when_idle);

Both state a contract rather than restating the implementation: the first says where samples are allowed to happen, the second says when.

Check the phase wrap. The counter returning to 0 at OVERSAMPLE - 1 is where a width error shows up — a counter one bit too narrow wraps early and every subsequent interval is short. A test that runs a full frame and asserts the sample count equals the frame's interval count catches it; a test that checks one interval does not.

And exercise the rephase. Back-to-back frames (Chapter 3.4) mean rephase_i arrives immediately after the previous frame ended. A design that only re-phases from an idle state mis-handles the first frame of a burst.

8. What This Means on an FPGA

The tick generator is the hard part, not the phase counter. §5 showed the divisor falls as M rises, so the generator's own rate error grows. At 100 MHz and 115,200 the 16× divisor is about 54.25 — a fractional part of a quarter, which Chapter 4.3's integer rounding would leave as a real error. This is where the fractional techniques of Chapter 4.4 earn their place, and it is a case where they clearly do.

Choose the factor from the budget, not from tradition. Compute δ_grid for a candidate factor, put it into Chapter 4.5's inequality with the rest of the terms, and take the smallest factor that fits with the reserve you want. On a link with an accurate far end and a short frame, 8× may leave ample margin and cost half the tick rate.

If the board has a serial-family crystal, the arithmetic changes completely. §2 showed that 1.8432 MHz gives a 16× tick with no division. That remains true, and a design with such a clock available has a genuinely free high oversampling factor — which is exactly why the convention formed.

Never generate an os_clk. The tick is an enable. A divided clock here would create a domain crossing between the tick generator and everything in Modules 5 and 6, for no benefit.

9. Understanding Check

10. Summary

Oversampling generates a periodic tick at f_os = M x f_baud, giving a grid of M positions spaced 1/M UI apart inside every bit interval. The tick is a clock enable, never a second clock. It does not mean the line is read M times per bit.

16× became conventional because 16 x 115,200 = 1.8432 MHz — exactly the crystal frequency Chapter 4.2 showed divides cleanly onto the whole classic rate series. On that hardware the 16× tick required no division at all. That is an arithmetic accident of the era, not a protocol requirement, a theoretical optimum, or a noise-immunity threshold.

Positions are derived from the factor: start centre at M/2 ticks, data[k] centre at (k + 1.5) x M. The start centre coincides with Chapter 5.2's validation point, which is why one counter serves both.

The factor buys placement resolutionδ_grid, between 1/(2M) and 1/M UI depending on whether the receiver can re-phase to a finer estimate — and this resolves the δ_sample term Chapter 4.5 deferred, decomposing it into grid placement, decision-window spread, and architecture-specific terms.

It costs a tick M times faster, and therefore a divisor M times smaller — 54.25 rather than 868 at 16× from 100 MHz — so the generator's own rate error grows as the placement error shrinks. It also costs counter width and enable activity. No factor is universally correct: choose the smallest whose δ_grid fits the budget.

Every position must be a named constant derived from the parameter. A literal 7 is correct at M = 16 and silently wrong everywhere else — the defect that survives review because it passes at the default.

11. What Comes Next

The grid gives the receiver a place to look. Chapter 5.4 asks what it should do when it gets there: read once, or read several positions around the centre and combine them. Multi-sample decisions reject a class of disturbance that a single reading cannot — and fail on a class that looks very similar. The chapter also produces the second term in δ_sample, because a window has width, and at 8× the same three samples span twice as much of the bit as they do at 16×.

Browse the full path on the UART tutorials index. For where the oversample tick's own rate error comes from, and the fractional arithmetic that reduces it, see Chapter 4.4.

Continue learning

Where this fits

Part of the UART curriculum.