UART · Module 3
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.
The four preceding chapters each defined a field and each ended with a choice. Chapter 3.1 fixed the entry at exactly one interval and left nothing to configure. Chapter 3.2 made the payload width a parameter. Chapter 3.3 made parity optional and, when present, one of several modes. Chapter 3.4 made the closing mark condition a configurable duration.
Those choices are not independent of one another, and they are not independent of the timing work in Module 2 either — every one of them changes N_frame, which Chapter 2.4 showed multiplies the accumulated timing error.
This chapter assembles them. It reads the shorthand engineers actually use, computes what each configuration costs, states precisely what the two endpoints must agree on, and closes the module by turning the frame from five separate fields into one contract.
1. Reading the Shorthand
A configuration is conventionally written as three characters:
8 N 1
│ │ │
│ │ └── stop condition: intervals of required mark
│ └──── parity mode: N none, E even, O odd
└────── payload width: bits of data per frameSo 8N1 is eight payload bits, no parity, one stop interval. 7E1 is seven payload bits, even parity, one stop interval. 8E2 is eight payload bits, even parity, two stop intervals.
The start interval is absent from the notation because it is not a choice — N_start = 1 in every configuration (Chapter 3.1 §5), so there is nothing to write.
2. The Configuration Tuple
The frame-format contract is four values, and it is worth naming them together because the shorthand only carries three:
UART frame configuration = { rate, payload width, parity mode, stop condition }Everything else a UART peripheral exposes — flow control, FIFO depths and thresholds, interrupt enables, loopback, break generation — sits outside this tuple. Those settings change how the device is driven and how data reaches software; they do not change what appears on the conductor for a given payload.
The distinction is architectural rather than pedantic. The four tuple members must be agreed between the two endpoints, because they determine the shape of the signal. The settings outside it are local: two devices can have completely different FIFO depths and interrupt configurations and interoperate perfectly, because neither is visible on the wire.
That is the line Module 10 and Module 13 build on, and it is why this module ends here rather than continuing into the peripheral.
3. What Each Configuration Costs
Chapter 2.2 gave the frame length as a sum of field counts. Module 3 has now supplied every term:
N_frame = N_start + N_data + N_parity + N_stop
N_start = 1 always (Chapter 3.1)
N_data = payload width (Chapter 3.2)
N_parity = 0 or 1 (Chapter 3.3)
N_stop = configured (Chapter 3.4)and the duration follows from the rate:
T_frame = N_frame x T_bitWorked across the configurations engineers actually meet, with T_frame at 115200 baud where T_bit ≈ 8.68056 µs:
| Config | N_data | Parity | N_stop | N_frame | Payload efficiency | T_frame at 115200 |
|---|---|---|---|---|---|---|
| 8N1 | 8 | none | 1 | 10 | 8/10 = 80.00% | ≈ 86.8056 µs |
| 8E1 | 8 | even | 1 | 11 | 8/11 = 72.73% | ≈ 95.4861 µs |
| 8O1 | 8 | odd | 1 | 11 | 8/11 = 72.73% | ≈ 95.4861 µs |
| 7E1 | 7 | even | 1 | 10 | 7/10 = 70.00% | ≈ 86.8056 µs |
| 8N2 | 8 | none | 2 | 11 | 8/11 = 72.73% | ≈ 95.4861 µs |
| 8E2 | 8 | even | 2 | 12 | 8/12 = 66.67% | ≈ 104.1667 µs |
Two rows are worth comparing directly.
8N1 and 7E1 occupy the same line time — ten intervals, about 86.8 µs — and deliver different amounts of data. 7E1 spends one of its ten intervals on parity that 8N1 spends on payload, so it carries 70% payload against 80% for the same conductor occupancy. A link that moves from 8N1 to 7E1 has not become slower per frame; it has become slower per byte, by 12.5%.
8E1 and 8N2 are indistinguishable in length — both eleven intervals — and completely different in what the eleventh interval does. One carries a parity value derived from the payload; the other carries a second interval of required mark. A receiver configured for one and given the other will find the interval's value is whatever the payload made it, which is right about half the time by accident.
4. Walking a Frame, Field by Field
The practical skill this module has been building toward is reading an arbitrary frame off a capture. 8E1 is the configuration that exercises all four fields at once.
8E1, payload 0xA6 — every field in one frame
11 cyclesThe dependency chain in Figure 2 is why a mismatch anywhere displaces everything after it. The parity interval's position depends on the payload width; the stop position depends on both. A receiver with the wrong payload width does not merely mis-read the payload — it checks parity and stop at the wrong intervals too.
5. Both Endpoints, One Interpretation
Nothing is negotiated (Chapter 2.1), so the tuple must be settled in advance at both ends. When it is not, the symptoms are specific and are worth knowing individually rather than as a general "it won't work".
Payload width mismatch. Every field after the payload is displaced. A receiver expecting fewer bits than were sent finds its parity or stop position inside the payload, where the value is data-dependent — so it reports errors on some frames and not others, and the payload it delivers is truncated. A receiver expecting more consumes the parity or stop intervals as payload.
Parity presence mismatch. One endpoint sends an interval the other does not expect, displacing the stop position by one. The characteristic symptom is a framing error rather than a parity error, which is genuinely confusing: the field that was misconfigured is not the field that reports. Chapter 3.4 §7 flagged this as an interaction worth testing deliberately.
Parity mode mismatch — even against odd. Both endpoints agree the interval exists and disagree on its value, which differs by inversion. The result is a parity error on every frame, without exception, and Chapter 3.3 §8 gave the diagnostic: universal errors mean configuration, intermittent ones mean corruption.
Stop mismatch. Asymmetric, as Chapter 3.4 §5 established. Sending more stop than expected passes silently; sending less produces framing errors. The silent direction is the dangerous one.
Rate mismatch. Module 2's territory entirely. The grid diverges, displacement accumulates, and the symptom is corruption concentrated at the end of frames (Chapter 2.4).
6. Configuration in RTL
The choices become a type, and where that type lives is an architectural decision.
// Synthesizable SystemVerilog — the frame-format configuration type.
// parity_mode_t is defined in uart_parity_pkg (Chapter 3.3) and is
// imported rather than redeclared, so one enumeration governs both the
// generator and this structure.
package uart_cfg_pkg;
import uart_parity_pkg::parity_mode_t;
typedef enum logic [1:0] {
STOP_1 = 2'b00,
STOP_2 = 2'b01
// Other durations exist in some implementations; this design
// supports these two and says so in its encoding.
} stop_mode_t;
typedef struct packed {
logic [3:0] data_bits; // payload width; legal range is checked
parity_mode_t parity; // Chapter 3.3
stop_mode_t stop; // Chapter 3.4
} uart_frame_cfg_t;
// N_frame from the tuple — the arithmetic of §3 as a function.
function automatic int unsigned frame_intervals(input uart_frame_cfg_t c);
return 1 // START
+ int'(c.data_bits) // payload
+ ((c.parity == uart_parity_pkg::PARITY_NONE) ? 0 : 1)
+ ((c.stop == STOP_2) ? 2 : 1);
endfunction
endpackagedata_bits is a value, not a width. Four bits hold the supported range comfortably, and the field stores how many payload intervals the frame has — not a mask and not a width-minus-one. Encodings that store width-minus-one are common in real register maps and are a reliable source of off-by-one defects; whichever convention a design picks, the function above is where it must be applied exactly once.
The function is the single source of N_frame. The sequencer needs it to know when the payload field ends, the timing check of Chapter 2.5 needs it to evaluate the budget at the right index, and a testbench needs it to predict the frame. Three copies of that arithmetic is three places to disagree; one function used by all three cannot.
The enumerations encode what this design supports. stop_mode_t has two members because this example supports two durations. That is more honest than a wider field with undefined encodings, and it makes an unsupported value a type error rather than a runtime surprise.
Parameter or register?
The same tuple can be fixed at elaboration or programmable at runtime, and the choice follows from what the block is.
// Synthesizable SystemVerilog — fixed-function form: configuration as a
// parameter, contrasted with the runtime-programmable form below.
module uart_fixed #(
parameter int unsigned DATA_W = 8
) ( /* ... */ );
// Registers are exactly DATA_W wide. The interval counter counts
// exactly as far as it must. Unsupported configurations do not exist
// in the netlist because they were never built.versus a reusable IP, where the payload register is built at the maximum supported width and the sequencer stops the field after however many intervals the current configuration calls for. The unused upper bits then need a defined treatment, and the counter comparison becomes a runtime value rather than a constant.
Neither is better in general. A debug UART in an FPGA design (Chapter 1.5) has one configuration for its whole life and should pay nothing for flexibility it will never use. An IP in a product's peripheral catalogue must be programmable, because the driver decides. What is expensive is choosing the flexible form by default — a runtime-configurable block carries wider registers, runtime comparisons, and a whole configuration-validity problem that the parameterised one does not have.
Two questions a configurable design must answer
Which configurations are legal, and what happens to the others? A four-bit data_bits field can hold values this design does not support. A production block decides whether such a value is prevented at the register interface, clamped, ignored, or accepted and reported — and it must decide, because silently building a frame from an unsupported width produces traffic that nothing on the far end can parse. Module 13 owns the register-interface half of this; the design decision belongs here.
What happens if the configuration changes mid-frame? Software can write a configuration register at any moment, including while the sequencer is partway through a frame. Figure 2 shows why that is dangerous: the position of every field depends on the widths of the fields before it, so a frame built half with one configuration and half with another has a layout neither endpoint can describe. The defensible policies are to latch the configuration at frame start and use that snapshot for the whole frame, to defer the change until the line is idle, or to prohibit writes while busy and report the attempt. Which one an IP chooses belongs in its documentation; having no policy is the failure, because the default behaviour is the malformed frame.
7. What This Means for Verification
This is where the module's verification threads converge, and the space is larger than it looks.
The dimensions. Payload width × parity mode × stop condition × payload pattern × frame spacing — and from Module 2, × relative clock error × the phase of the start transition. Seven dimensions before any fault is injected.
Do not enumerate the product. The full cross is large and most of it is uninformative, because most pairs of dimensions do not interact. What earns a test is an interaction that changes behaviour, and Module 3 has produced a specific list of those:
- Parity mode × payload pattern. The parity value is a function of the payload, so a mode is only exercised by payloads whose population count varies (Chapter 3.3 §8).
- Payload width × parity presence × stop. All three determine field positions, so an error in one is observed through another — the parity-presence mismatch that reports as a framing error is exactly this (Chapter 3.4 §7).
- Stop condition × frame spacing. Back-to-back frames are where a stop requirement interacts with the next frame's entry (Chapter 3.4 §4).
- Frame length × clock error.
N_framemultiplies accumulated displacement, so the longest supported configuration is the worst case for timing (Chapter 2.4).
Boundaries in each dimension. Narrowest and widest supported payload, each parity mode including the non-detecting ones, each stop duration, payloads with zero and maximum population, zero and long inter-frame gaps.
Configuration as stimulus, not setup. Three cases are easy to omit because they feel like test-harness concerns rather than DUT behaviour, and all three are DUT behaviour: mismatched endpoints in each of the §5 forms, with the expected symptom asserted rather than merely observing failure; illegal configuration values, with the design's declared policy checked; and configuration changed between frames and during a frame, with the §6 policy verified rather than assumed.
That last group is the difference between verifying the frame and verifying the configurable frame, and it is the part most likely to reach silicon untested.
8. What This Means on an FPGA
Parameterise unless you know you need registers. Most FPGA UARTs are fixed-function for the life of the design, and a parameterised block is smaller, simpler to close timing on, and has no configuration-validity problem at all.
Derive everything from one function. frame_intervals() gives the sequencer's terminal count, the testbench's prediction, and the input to the timing check of Chapter 2.5. Recomputing it by hand in any of those places is how a re-parameterised design develops an inconsistency that only appears at one width.
Check the timing budget against the longest configuration you will actually build. A block supporting 8E2 has a worst-case index of 11 rather than 9, and the elaboration-time guard of Chapter 2.5 §5 should be evaluated with that number, not with 8N1's.
Annotate captures with the configuration in hand. Figure 1 is the procedure: find the departure from idle, count the payload intervals the configuration specifies, take the next one as parity if configured, and check the closing mark. Trying to infer the configuration from the capture is possible but slow, and the fastest way to identify a mismatch is to walk the frame twice — once with each endpoint's configuration — and see which one produces a consistent result.
9. Understanding Check
10. Summary
A configuration is written as three characters — payload width, parity mode, stop condition — and the start interval is absent because it is not a choice. The shorthand omits the rate, which is the fourth member of the tuple and the term most likely to be wrong; two links can both be 8N1 and be unable to communicate.
The full contract is { rate, payload width, parity mode, stop condition }. Everything else a peripheral exposes — flow control, FIFOs, interrupts — is local, invisible on the conductor, and need not match between endpoints.
Frame length is the sum of the fields, N_frame = 1 + N_data + N_parity + N_stop, and it determines both throughput and robustness. 8N1 and 7E1 occupy the same ten intervals and deliver 80% against 70% payload. 8E1 and 8N2 are both eleven intervals and differ entirely in what the eleventh does. And because accumulated timing displacement is linear in the interval index, a longer frame spends more timing budget — so adding parity can reduce robustness on a link whose binding constraint was margin rather than detection.
Every field's position depends on the widths of the fields before it, which is why a mismatch displaces everything downstream and why the field that was misconfigured is often not the field that reports. The symptoms discriminate: universal parity errors mean parity mode; framing errors with plausible payloads mean parity presence or stop; end-of-frame corruption means rate; truncated values mean width.
In RTL the tuple becomes a type, and N_frame becomes one function used by the sequencer, the timing check and the testbench alike. Whether the configuration is a parameter or a register follows from whether the block is fixed-function or a reusable IP — and the runtime form brings two obligations the parameterised one does not have: deciding what happens to illegal values, and defining a policy for configuration writes during an active frame.
11. Where Module 3 Leaves You
Five chapters have assembled one frame.
Chapter 3.1 established that a frame opens with a transition whose instant is the timing origin and an interval of known value — an edge and a bit cell, two jobs that are routinely conflated. Chapter 3.2 mapped a parallel value onto consecutive intervals, separated the three things called bit order, and showed that nothing is ever reversed. Chapter 3.3 added one derived interval and drew the exact line between the corruption it always catches and the corruption it never does. Chapter 3.4 closed the frame with a checked mark condition, corrected the resynchronisation folklore from the framing side, and showed that no gap is required before the next frame. This chapter assembled the choices into a contract and priced each one.
An engineer holding that chain can put an instrument on a UART line, annotate IDLE, START, D0 through D(N−1), PARITY and STOP, reconstruct the payload, and identify a configuration mismatch from its symptom. That was the goal.
12. What Comes Next
Module 3 has treated the rate as a number both endpoints were handed. Module 2 showed that number is never achieved exactly, and this chapter has just made it the one term the shorthand omits.
Module 4 takes it seriously. It covers the standard rates and where they came from, how a system clock is divided to approximate one, how much error that approximation leaves, what fractional generation does about it — and then closes Module 2's unfinished business by deriving the full timing budget for a stated design, with every term this curriculum has introduced accounted for.
Browse the full path on the UART tutorials index. For a UART configuration seen from the software side — the registers a driver writes to select exactly this tuple — see UART APB Interface.
Continue learning
Related tutorials
- 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
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
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
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.
Where this fits
Part of the UART curriculum.
