Skip to content
VLSI Mentor

UART · Module 8

RX and TX Baud Timing: One Generator or Two?

A receiver needs sixteen ticks per bit interval and a transmitter needs one. Sharing a base is excellent when that base is fractional and 73 times worse when it is not — and it does nothing at all for the receiver's phase uncertainty.

Chapter 7.3 §6 raised an asymmetry and deliberately declined to resolve it:

ReceiverTransmitter
Ticks per bit intervalOVERSAMPLE — typically 161
Whymust find a boundary it was never told aboutdefines the boundary

Both halves need timing from the same fabric clock and the same nominal rate, and they need it at rates that differ by a factor of sixteen. That is the question this chapter settles.

It has an answer that is not obvious, and it is worth stating up front because it inverts the usual intuition: sharing one generator is the better architecture — but only if the shared generator is fractional. A shared integer base is dramatically worse than two independent integer dividers, for a reason that follows directly from Chapter 8.3 §3.

1. The Receiver's Rate

From Chapter 5.3, the receiver divides each bit interval into M positions, so it needs M enables per interval:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
f_sample  =  BAUD_HZ × M            [Hz] = [baud] × [dimensionless]

At 115,200 baud and M = 16:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
f_sample = 115,200 × 16 = 1,843,200 Hz

1,843,200 sample enables per second, against the transmitter's 115,200. That number should look familiar: Chapter 4.2 showed 1.8432 MHz is itself a standard crystal frequency, which is exactly why 16× became conventional — a board with that crystal gets the receiver's tick with no division at all.

On a 100 MHz clock it is not free, and the divisor is where the trouble starts:

baudMsample rateideal divisor @ 100 MHzinteger divisorrate error
9,60016153,600651.0417651+0.0064 %
115,2008921,600108.5069109−0.4523 %
115,200161,843,20054.253554+0.4694 %
1,000,0001616,000,0006.25006+4.1667 %

The oversample divisor is M times smaller than the bit-rate divisor, so by Chapter 8.3 §3's law its relative rounding error is roughly M times larger. At 115,200 and 16× the divisor is 54 and the error is 0.47% — against 0.0064% for the bit-rate divisor of 868.

This is the fact the whole chapter turns on.

2. Three Architectures

A — independent generators. One for the receiver at M × BAUD, one for the transmitter at BAUD.

B — shared base. One generator at M × BAUD feeding the receiver directly, with a divide-by-M counter producing the transmitter's enable.

C — shared parameters, separate state. Two generators, but their divisors or increments derived from one set of parameters at elaboration.

They differ in resources, in coupling, and — the part that decides it — in accuracy.

3. The Accuracy Result

Machine-computed at 100 MHz and 115,200 baud, M = 16:

ArchitectureTX rateTX errorvs independent
A — independent integer dividers (N = 868)115,207.3733+0.0064 %baseline
B — shared integer base (N = 54, then ÷16)115,740.7407+0.4694 %73× worse
B — shared fractional base, ACC_W = 16115,203.8574+0.00335 %1.9× better
B — shared fractional base, ACC_W = 24115,200.1321+0.00011 %58× better

4. What Sharing Does Not Fix

This is the distinction most easily blurred, and getting it wrong leads to a real design error.

A shared generator makes the receiver's and transmitter's enables coherent with each other. It does nothing whatever about the receiver's phase relative to the incoming data.

The receiver's sampling positions are anchored to the start edge it detects on the wire (Chapter 5.2 §4, Chapter 6.1 §4). That edge is produced by a different device with a different oscillator. No amount of internal generator sharing changes where it falls, how uncertain its observation is, or how the far end's frequency error accumulates across the frame:

QuantitySourceDoes sharing help?
δ_grid — placement onto the tick gridour Mno — set by M, not by sharing
δ_origin — quantisation of the observed edgeour clk periodno
ε_rel — relative rate mismatchthe far end's oscillatorno
our own contribution to ε_relour generator's accuracyyes — this one

Only the last row improves, and §3 quantifies by how much. Everything Chapter 5.5 showed about sampling drift across a frame is untouched — the receiver still re-anchors on every start bit, still places samples on a grid with 1/M resolution, and still accumulates displacement at n × ε_rel.

The practical error this prevents: concluding that because one generator now drives both halves, an internal loopback test proves the timing is correct. It proves the two halves agree with each other, which they would even if the shared generator were 5% off. Only a test against an independent far end, or a measurement of the actual tick rate, checks the thing that matters.

5. Choosing

A — independentB — shared baseC — shared parameters
Generators21 + a small counter2
Accuracyeach independentexcellent if fractional, poor if integereach independent
RX and TX rates locked?no — can drift by their roundingyes, exactlyno
Different RX/TX rates possible?yesno — locked to Myes
Resource cost2 adders/counters1 adder + $clog2(M) counter2
Failure modetwo divisors to get rightone wrong base ruins bothparameters drift apart

Architecture B with a fractional base is the recommendation for an ordinary UART, where both halves run at the same configured rate: it is the cheapest, the most accurate, and it guarantees the two enables cannot disagree.

Architecture A is right when the two halves may run at different rates — an uncommon but real configuration, and one a shared base structurally cannot support because the transmitter's rate is defined as the base divided by M.

Architecture C is the weakest of the three. It pays for two generators without buying the independence that justifies them, and it introduces a maintenance hazard: two derivations that must stay consistent, with nothing enforcing it.

6. The Composed RTL

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------------
//  8.4 — composed timing: one oversample base serving RX directly and TX
//  through a divide-by-OVERSAMPLE. Illustrative composition, not a UART IP.
// ---------------------------------------------------------------------------
module uart_timing_gen #(
    parameter int unsigned CLK_HZ     = 100_000_000,
    parameter int unsigned BAUD_HZ    = 115_200,
    parameter int unsigned OVERSAMPLE = 16
) (
    input  logic clk,
    input  logic rst_n,
    output logic os_tick_o,        // OVERSAMPLE per bit interval — RX
    output logic baud_tick_o       // 1 per bit interval — TX
);
    localparam int unsigned OS_W = (OVERSAMPLE <= 1) ? 1 : $clog2(OVERSAMPLE);

    initial begin
        if (OVERSAMPLE < 1)
            $fatal(1, "uart_timing_gen: OVERSAMPLE must be >= 1");
        if (longint'(BAUD_HZ) * OVERSAMPLE > longint'(CLK_HZ))
            $fatal(1, "uart_timing_gen: %0d x %0d exceeds CLK_HZ %0d",
                   BAUD_HZ, OVERSAMPLE, CLK_HZ);
    end

    // The base runs at OVERSAMPLE x BAUD_HZ. RX consumes it directly.
    uart_baud_tick_frac #(
        .CLK_HZ  (CLK_HZ),
        .BAUD_HZ (BAUD_HZ * OVERSAMPLE),
        .ACC_W   (24)
    ) u_base (
        .clk (clk), .rst_n (rst_n), .baud_tick_o (os_tick_o)
    );

    // TX derives its bit enable by counting OVERSAMPLE base ticks. This costs
    // one small counter and guarantees the two enables cannot drift apart.
    logic [OS_W-1:0] os_cnt_q;

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            os_cnt_q    <= '0;
            baud_tick_o <= 1'b0;
        end else begin
            baud_tick_o <= 1'b0;
            if (os_tick_o) begin
                if (os_cnt_q == OS_W'(OVERSAMPLE - 1)) begin
                    os_cnt_q    <= '0;
                    baud_tick_o <= 1'b1;
                end else begin
                    os_cnt_q <= os_cnt_q + 1'b1;
                end
            end
        end
    end
endmodule

Four details are deliberate.

The base is the fractional generator, not the integer one. §3 is the whole argument. Instantiating Chapter 8.2's divider here would make the composition 73× less accurate than not sharing at all — the single most consequential line in the block.

BAUD_HZ * OVERSAMPLE is passed to the base, so the base generator needs no knowledge of oversampling. It produces a rate; the composition decides what that rate means.

The elaboration guard checks BAUD_HZ × OVERSAMPLE ≤ CLK_HZ in longint, because that product overflows 32 bits for high rates and large factors, and a wrapped comparison would pass a configuration that cannot work. At 1 Mbaud and 16× the required base is 16 MHz — a sixth of a 100 MHz clock, which is fine; at 8 Mbaud it would exceed it, and the guard says so rather than silently producing an unreachable rate.

The TX counter divides the base, it does not generate independently. That is what locks the two enables together: every sixteenth os_tick_o is also a baud_tick_o, exactly, forever. Simulation over three million fabric clocks: 55,312 oversample ticks and 3,457 baud ticks — a ratio of exactly 16, with the baud interval measured at 868–869 clocks as the fractional base requires.

A shared baud timing architecture. A single fabric clock drives one fractional phase-accumulator generator configured for the baud rate multiplied by the oversampling factor. Its output enable is used directly by the receiver as its oversampling grid, providing sixteen positions inside every bit interval. The same enable also feeds a small counter which counts sixteen of them and produces one transmit bit enable per bit interval. Because the transmit enable is a subsample of the receive enable rather than an independently generated signal, the two cannot drift apart. The receiver's sampling phase relative to incoming data is still established by the detected start edge and is unaffected by this sharing.clkone domainfractional baseM x BAUD — Ch 8.3os_tick_o1,843,200 Hzreceivergrid of M — Ch 5.3start edgefrom the WIREcount to M$clog2(M) bitsbaud_tick_o115,200 Hztransmitter1 per bit — Ch 7.3countscarrygridsubsampleevery Mthadvancephase — NOT fromhere12
Figure 1 — the shared-base composition. One fractional generator produces the high-rate enable; the receiver consumes it directly as its oversampling grid, and a divide-by-M counter derives the transmitter's bit enable from the same stream. Because the transmitter's enable is a subsample of the receiver's, the two can never disagree about where a bit boundary falls — which is a property no pair of independent generators has.

7. Configuring Two Halves at One Rate

A UART link normally runs both directions at the same rate, which raises a design question the composition above answers implicitly.

One rate parameter, or two? With a shared base there is structurally only one — the transmitter's rate is the base divided by M, so there is nothing separate to configure. That removes an entire class of bug: a receiver and transmitter configured to different rates by a software error cannot happen, because there is no second register to disagree.

The cost is that they cannot be different when that is wanted. Split rates are unusual but not unheard of — a device streaming telemetry fast while accepting commands slowly. A design that must support it needs architecture A and two configurations, and it should then also verify the two independently rather than assuming a single loopback test covers both.

Whichever is chosen, the rate should be one field, not a divisor and an increment. Exposing N_DIV or INC directly to software leaks the generator's architecture into its interface: changing from an integer divider to a fractional one would then change the register map. Exposing a rate and deriving the generator value keeps that free. Where that derivation happens — elaboration or at runtime — is Chapter 8.5's subject, and the register interface itself belongs to Module 13.

8. Verification

Assert the ratio, exactly. Every M-th oversample tick must be a bit tick, with no drift over any run length. Counting both and checking the quotient is a stronger check than measuring either rate:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
composed : os_tick=55312 baud_tick=3457  baud interval 868..869 clks

From simulation over three million fabric clocks — a ratio of exactly 16, and baud intervals in the two-value set the fractional base predicts.

Check the base rate, not the derived rate. An error in the base propagates to both consumers, so measuring the transmitter's rate alone can mask which generator is wrong. Measure os_tick_o directly and compare against BAUD_HZ × M.

Do not verify timing by internal loopback alone. §4's point stated as a test procedure: a loopback exercises the receiver against the transmitter, both driven by the same generator, so it passes whatever that generator's rate happens to be. It is an excellent test of framing, bit order and handshake, and it is worthless as a test of rate accuracy. Rate must be checked against an independent reference or measured directly.

Sweep OVERSAMPLE. The divide-by-M counter's width is derived, and values that are not powers of two exercise the terminal comparison rather than a natural wrap — the same hazard Chapter 6.3 §2 identified in the receiver's phase counter.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Assertion — a bit tick never occurs without a coincident oversample tick,
// which is what "subsample" means structurally.
property p_baud_implies_os;
    @(posedge clk) disable iff (!rst_n)
        baud_tick_o |-> os_tick_o;
endproperty
assert property (p_baud_implies_os);

// Assertion — the subsample counter stays within its modulus.
property p_os_count_in_range;
    @(posedge clk) disable iff (!rst_n)
        os_cnt_q <= OS_W'(OVERSAMPLE - 1);
endproperty
assert property (p_os_count_in_range);

The first is worth writing because it fails on the most likely restructuring error: someone replacing the subsample counter with an independent generator "to decouple the two", which silently reintroduces the drift the composition existed to prevent.

9. What This Means on an FPGA

The sharing is nearly free. One 25-bit adder for the base and a 4-bit counter for the subsample, against two generators in the independent architecture. The saving is small in absolute terms and the accuracy gain is the real reason to prefer it.

The oversample enable has higher fanout and a higher toggle rate. It pulses 1,843,200 times per second rather than 115,200 and reaches every timing-dependent register in the receiver. At UART scale this is still unremarkable — a few dozen endpoints toggling at under 2 MHz — but it is the one signal in the design worth glancing at if a power or fanout report looks unexpected.

Probe os_tick_o and baud_tick_o together. The ratio is directly visible and is the first check on a composition: sixteen of one per one of the other, always. A ratio that is right but a rate that is wrong points at the base generator; a ratio that is wrong points at the subsample counter.

Size the base generator from the highest rate the design supports, not the nominal one. The guard catches BAUD_HZ × OVERSAMPLE > CLK_HZ at elaboration, and for a runtime-configurable rate the same relationship must hold for the fastest configuration — which is the composition's equivalent of Chapter 8.2's DIV_MAX argument, inverted.

10. Understanding Check

11. Summary

The receiver needs M ticks per bit interval and the transmitter needs one, so a shared generator must run at BAUD_HZ × M1,843,200 Hz at 115,200 baud and 16×, which is itself a standard crystal frequency and the reason 16× became conventional.

The oversample divisor is M times smaller than the bit-rate divisor, so its relative rounding error is roughly M times larger: 54 instead of 868, 0.47% instead of 0.0064%.

That single fact decides the architecture, and it points both ways:

TX error at 100 MHz / 115,200vs independent
independent integer dividers+0.0064 %baseline
shared integer base+0.4694 %73× worse
shared fractional base, 24-bit+0.00011 %58× better

Share the base — with a fractional generator. It is cheaper, far more accurate, and it locks the two enables together so they cannot disagree. A shared integer base is the worst of the three options.

Sharing does not touch the receiver's phase uncertainty. The sampling phase comes from the start edge on the wire, produced by another device's oscillator. Sharing improves our own contribution to the rate mismatch and nothing else — and the practical consequence is that an internal loopback test cannot validate rate accuracy, because both halves are wrong together.

Verified in simulation: 55,312 oversample ticks to 3,457 bit ticks — exactly 16 — over three million fabric clocks.

12. What Comes Next

Four chapters have produced working generators and an architecture to compose them. What they have not done is state a contract: which parameter values are legal, what happens when an illegal one is supplied, what the generator does during and immediately after reset, and how a rate change should reach it safely.

Chapter 8.5 closes the module with exactly that. It defines the legal range and hardware consequence of every parameter; separates elaboration-time errors from runtime programming errors from accuracy warnings, which are three different things routinely conflated; specifies reset behaviour down to the first tick; and weighs compile-time specialisation against runtime programmability rather than building both and calling it flexible.

Browse the full path on the UART tutorials index. For the oversampling grid this chapter feeds, read back to Chapter 5.3; for the transmitter's single enable, Chapter 7.3.

Continue learning

Where this fits

Part of the UART curriculum.