I²C · Module 11
Why I²C Timing Parameters Exist
Before any parameter is named, separate the three independent questions a single bit has to answer — what it means, when it may change, and how long it must hold. Sixteen numbers in Table 10 are answers to those three questions.
Ten modules have treated time as something that simply works. A bit is a level while SCL is high; SDA may change while SCL is low; a byte is nine pulses. All true, all sufficient to build a write, a read and a combined transaction — and all silent about how long any of it has to last.
Module 11 supplies the numbers. It is the specification's timing table worked through one parameter group at a time, and this chapter is the frame the rest hang on, because the numbers are unintelligible until you know what they are numbers for.
The organising claim is this: a bit has to answer three questions, and they fail independently.
1. Three Questions, Not One
Take a single bit on the wire and ask what could be wrong with it.
| # | question | what settles it | how it fails |
|---|---|---|---|
| 1 | What does it mean? | the level of SDA while SCL is high | SDA moved during the high phase, so there is no single level |
| 2 | When may it change? | only while SCL is low | SDA moved while SCL was high — and that edge is reserved |
| 3 | How long must it hold? | stable before the rise, and through the whole high phase | it was stable, but not for long enough |
These are not three views of one requirement. A bit can be perfectly stable and arrive too late (question 3 fails, 1 and 2 pass). It can be stable for a long time and then move mid-phase (1 and 2 fail, 3 passes). It can be entirely well-defined on a clock whose high phase was too short for any receiver to use (3 fails on a different term).
That independence is why Table 10 has sixteen entries rather than one. Each entry constrains one way of getting time wrong, and the reason the table looks intimidating is that people try to read it as a list of numbers instead of as answers to a small number of questions.
2. What the Specification Actually Constrains
It is worth being precise about the shape of Table 10 before reading any of it, because two structural features surprise people.
Almost every entry is a MINIMUM. tLOW, tHIGH, tSU;DAT, tSU;STA, tHD;STA, tSU;STO, tBUF — all minima. A device that waits longer is always compliant. This is why clock stretching is legal (Module 12) and why a bus can idle for hours: the table almost never tells you to hurry.
The exceptions are the interesting ones. Four entries are maxima, and each is a promise rather than a permission:
| symbol | what it limits | whose promise |
|---|---|---|
fSCL | the clock frequency — equivalently a minimum period | the master's |
tVD;DAT, tVD;ACK | how long a transmitter may take to produce a bit | the transmitter's |
tr, tf | how long an edge may take | the board's |
tSP | the widest pulse an input must reject | the receiver's |
tSP is the odd one in that list and worth flagging now: it constrains what a device must tolerate, not what it may produce. Chapter 11.8 is about that inversion.
And one entry constrains neither a device nor a transfer:
tBUF spans the gap between transfers, so it is the only parameter about the interval in which nobody owns the bus. Chapter 10.2 measured that interval for a different reason; Chapter 11.6 prices it.
3. A Bit Cell, Drawn
Here is one bit with the three questions marked against it.
A bit cell and the three questions it must answer
10 cyclesThis figure uses kind: "signal" for SCL rather than kind: "clock", and that is deliberate: the point of the drawing is that SCL's level at each moment is what licenses or forbids an SDA change, so the figure has to show a particular level per interval rather than a generic square wave. A clock row would render a uniform period and the claims in the markers would no longer be about anything.
Read the question row across and the structure of the chapter is visible: Q2 applies at the moments SDA moves, Q3 to the interval before the rise, Q1 to the high phase itself. Three questions, three regions, no overlap.
4. What a Violation Actually Does
It is easy to treat a timing violation as an abstraction. It is not; each of the three failures does something specific and different to a receiver.
Question 1 fails — SDA moved during the high phase. The receiver samples at some point in that phase and gets whichever level happened to be present. Two receivers on the same bus can disagree about the same bit, which is the worst property a failure can have: the bus is no longer a single source of truth, and two devices' views of the same transfer diverge with nothing reporting a problem.
Question 2 fails — the edge was while SCL was high. Chapter 5.1 established that such an edge is reserved for framing, so the failure is not a corrupt bit. It is a spurious START or STOP inside a byte, and the consequence is structural: every device resets its bus logic and expects an address (Chapter 10.2 quotes the note), so the rest of the transfer is reinterpreted from scratch.
Question 3 fails — too little setup. The receiver's input stage samples a line that is still settling. What it gets is not a wrong value, it is an undefined one — and on a bus with several receivers, they may resolve it differently. This is the marginal failure: it works at room temperature, on that board, with that pull-up, and stops working when any of those change.
5. Measuring Time in Hardware
Before the design, one practical point that governs every block in this module.
Everything is counted in ticks of a sample clock. The specification is in microseconds and nanoseconds; the hardware has a system clock. So a user converts the table once — at 100 MHz one tick is 10 ns, and Fast-mode's tSU;DAT of 100 ns becomes 10 ticks — and from then on the logic never deals in nanoseconds. That is why every parameter in this module is a tick count, and why the testbenches state their sample rate in a header comment.
The resolution of the measurement is one tick. A 100 MHz sampler cannot tell 95 ns from 99 ns. For Fast-mode's 100 ns setup that is a 10 % granularity, which is enough to catch a gross violation and not enough for compliance testing — compliance is a scope measurement. What a hardware checker is for is continuous monitoring of a working system, where the question is "did anything go badly wrong in the last hour" rather than "is this margin 4 ns or 6 ns".
And a measurement must include the cycle in which it is taken. This sounds pedantic and is not: reading a counter register gives its value as of the previous edge, so every interval comes out one tick short, and every comparison against a minimum is shifted by one sample period. §6a records how that was found.
6. The Bit-Cell Classifier in Three Languages
The design watches the two wires and, for every SCL high phase, reports the three verdicts plus the two measurements they rest on.
| output | question | meaning |
|---|---|---|
cell_value | 1 | the level sampled at the rising edge |
viol_meaning | 1 | SDA moved during the high phase, so there is no single level |
edge_while_high | 2 | a fact, reported without judgement — see §6a |
cell_su_ticks, viol_setup | 3 | how long SDA was stable before the rise |
cell_high_ticks, viol_high_short | 3 | how long the high phase lasted |
// A BIT-CELL classifier. It watches SDA and SCL and, for every SCL high phase, answers
// the three questions that between them decide whether a bit is legal:
//
// 1. WHAT DOES IT MEAN? the level of SDA while SCL is HIGH
// 2. WHEN MAY IT CHANGE? only while SCL is LOW
// 3. HOW LONG MUST IT HOLD? stable for tSU;DAT before the rise, and through the
// whole high phase
//
// Those are three separate obligations and a real capture can fail any one of them
// independently, which is why this block reports three separate verdicts rather than
// one "bit bad" flag. Chapters 11.3 and 11.4 attach the specification's numbers to
// questions 3 and 2; this block is the frame they hang on.
//
// It is PASSIVE: it observes the two wires and drives nothing.
//
// One thing it deliberately does NOT do is decide whether an SDA edge during the high
// phase is an error. Chapter 5.1 established that such an edge is RESERVED for framing,
// so it is either a START/STOP (legal, and not a bit at all) or a corrupt bit. Only a
// frame decoder knows which. So the block reports the FACT -- edge_while_high -- and
// leaves the interpretation to its consumer.
module i2c_bit_cell_checker #(
parameter int TICK_W = 16,
// tSU;DAT, in sample-clock ticks. Fast-mode is 100 ns, so 10 ticks at 100 MHz.
parameter int T_SU_DAT = 10,
// tHIGH minimum, in ticks. Fast-mode is 0.6 us, so 60 ticks at 100 MHz.
parameter int T_HIGH_MIN = 60
)(
input logic clk,
input logic rst_n,
// Both wires, already synchronised and filtered by the input stage of Module 4.
input logic sda_in,
input logic scl_in,
// ---- the cell, reported at the END of each high phase ----
output logic cell_valid, // pulse: a high phase just ended
output logic cell_value, // Q1: the level sampled at the rising edge
output logic [TICK_W-1:0] cell_high_ticks, // how long the high phase lasted
output logic [TICK_W-1:0] cell_su_ticks, // how long SDA was stable before the rise
// ---- the three verdicts, one per question ----
// Q1 fails when the level cannot be determined: SDA moved during the high phase, so
// there is no single level the cell "means".
output logic viol_meaning,
// Q2 fails when SDA changed while SCL was HIGH. Reported as a fact by
// edge_while_high and as a violation only once the consumer says it was a data cell.
output logic edge_while_high,
// Q3 fails when SDA was not stable for T_SU_DAT before the rising edge, or when the
// high phase itself was shorter than T_HIGH_MIN.
output logic viol_setup,
output logic viol_high_short,
// ---- running totals, so a capture can be summarised ----
output logic [TICK_W-1:0] n_cells,
output logic [TICK_W-1:0] n_bad
);
logic sda_q, scl_q;
logic scl_rise, scl_fall, sda_changed;
assign scl_rise = !scl_q && scl_in;
assign scl_fall = scl_q && !scl_in;
assign sda_changed = sda_q != sda_in;
// How long SDA has been stable, counted continuously. At the rising edge of SCL this
// counter IS tSU;DAT as observed -- which is the cheapest possible way to measure a
// setup time: do not start a timer when the edge arrives, because by then it is too
// late. Run the timer always and sample it.
logic [TICK_W-1:0] stable_ticks;
logic [TICK_W-1:0] high_ticks;
// A measurement must INCLUDE the sample period in which it is taken. Reading the
// register directly gives the count as of the PREVIOUS edge, which under-reports
// every interval by exactly one tick -- a systematic error that shifts every
// comparison against a spec minimum by one sample period, and one that only a test
// at the exact boundary will find. So both counters are sampled through a
// combinational "including this cycle" value.
logic [TICK_W-1:0] stable_now, high_now;
assign stable_now = sda_changed ? '0 : (stable_ticks + 1'b1);
assign high_now = high_ticks + 1'b1;
// Latched during the high phase, reported when it ends.
logic in_high;
logic moved_during_high;
logic value_at_rise;
logic [TICK_W-1:0] su_at_rise;
always_ff @(posedge clk) begin
if (!rst_n) begin
sda_q <= 1'b1; // an idle bus is high on both wires
scl_q <= 1'b1;
stable_ticks <= '0;
high_ticks <= '0;
in_high <= 1'b0;
moved_during_high <= 1'b0;
value_at_rise <= 1'b1;
su_at_rise <= '0;
cell_valid <= 1'b0;
cell_value <= 1'b1;
cell_high_ticks <= '0;
cell_su_ticks <= '0;
viol_meaning <= 1'b0;
edge_while_high <= 1'b0;
viol_setup <= 1'b0;
viol_high_short <= 1'b0;
n_cells <= '0;
n_bad <= '0;
end else begin
sda_q <= sda_in;
scl_q <= scl_in;
cell_valid <= 1'b0;
edge_while_high <= 1'b0;
// ---- the always-running stability timer ----
stable_ticks <= stable_now;
if (scl_rise) begin
// The rising edge is where Q1 is answered and Q3's setup half is judged.
in_high <= 1'b1;
high_ticks <= '0;
moved_during_high <= 1'b0;
value_at_rise <= sda_in;
su_at_rise <= stable_now;
end else if (scl_fall) begin
if (in_high) begin
// The cell is over. Report everything at once, so a consumer sees a
// complete verdict rather than having to assemble one.
in_high <= 1'b0;
cell_valid <= 1'b1;
cell_value <= value_at_rise;
cell_high_ticks <= high_now;
cell_su_ticks <= su_at_rise;
// Q1: if SDA moved during the high phase there is no single level
// this cell means. That is a different failure from a short setup
// time -- the bit is not late, it is undefined.
viol_meaning <= moved_during_high;
// Q3, both halves. The setup comparison is STRICTLY LESS THAN, so a
// measurement exactly equal to the minimum passes: the spec value is
// a minimum, and a design that rejected the boundary would reject
// legal traffic.
viol_setup <= (su_at_rise < T_SU_DAT[TICK_W-1:0]);
viol_high_short <= (high_now < T_HIGH_MIN[TICK_W-1:0]);
n_cells <= n_cells + 1'b1;
if (moved_during_high
|| (su_at_rise < T_SU_DAT[TICK_W-1:0])
|| (high_now < T_HIGH_MIN[TICK_W-1:0]))
n_bad <= n_bad + 1'b1;
end
end else if (in_high) begin
high_ticks <= high_now;
if (sda_changed) begin
// Q2: SDA moved while SCL was high. A FACT, not yet a verdict --
// Chapter 5.1 reserves this edge for framing, so it is either a
// START/STOP or a corrupt bit, and only a frame decoder knows which.
moved_during_high <= 1'b1;
edge_while_high <= 1'b1;
end
end
end
end
endmodule `timescale 1ns/1ps
// The sample clock is 100 MHz, so one tick is 10 ns and Fast-mode's parameters are round
// numbers: tSU;DAT = 100 ns = 10 ticks, tHIGH(min) = 0.6 us = 60 ticks. Every stimulus
// below is written in TICKS and the expected results are derived from the parameters,
// not from a table of constants -- so the tests check the comparison, not a transcription.
module i2c_bit_cell_checker_tb;
localparam int TICK_W = 16;
localparam int T_SU_DAT = 10; // Fast-mode tSU;DAT = 100 ns
localparam int T_HIGH_MIN = 60; // Fast-mode tHIGH = 0.6 us
logic clk = 1'b0;
always #5 clk = ~clk; // 100 MHz: one tick per 10 ns
logic rst_n = 1'b0;
logic sda_in = 1'b1, scl_in = 1'b1;
logic cell_valid, cell_value, viol_meaning, edge_while_high;
logic viol_setup, viol_high_short;
logic [TICK_W-1:0] cell_high_ticks, cell_su_ticks, n_cells, n_bad;
int errors = 0;
int base;
logic [TICK_W-1:0] cells_before, bad_before;
i2c_bit_cell_checker #(.TICK_W(TICK_W), .T_SU_DAT(T_SU_DAT), .T_HIGH_MIN(T_HIGH_MIN))
dut (.*);
initial begin #500000; $display("FAIL: watchdog expired"); $finish; end
// ---- observation: capture each cell's verdict as it is reported ----------------
logic [TICK_W-1:0] su_log [0:31];
logic [TICK_W-1:0] hi_log [0:31];
logic vm_log [0:31];
logic vs_log [0:31];
logic vh_log [0:31];
logic val_log [0:31];
int n_log;
always @(posedge clk) if (rst_n && cell_valid && n_log < 32) begin
su_log[n_log] = cell_su_ticks;
hi_log[n_log] = cell_high_ticks;
vm_log[n_log] = viol_meaning;
vs_log[n_log] = viol_setup;
vh_log[n_log] = viol_high_short;
val_log[n_log] = cell_value;
n_log++;
end
task automatic tick(input int n);
begin
repeat (n) @(negedge clk);
end
endtask
// Drive one bit cell: present the value, wait `su` ticks, raise SCL for `hi` ticks,
// then drop it and wait `lo` ticks. This is the cell in its three parts, so a test
// can make any one of them illegal on its own.
task automatic drive_cell(input logic v, input int su, input int hi, input int lo);
begin
scl_in = 1'b0;
sda_in = v; tick(su);
scl_in = 1'b1; tick(hi);
scl_in = 1'b0; tick(lo);
end
endtask
initial begin
tick(3);
if (n_cells !== '0) begin $display("FAIL: n_cells out of reset"); errors++; end
rst_n = 1'b1; tick(2);
sda_in = 1'b1; scl_in = 1'b0; tick(5);
// ---- 1: four LEGAL cells with generous margins. Nothing may be flagged, and
// the measured setup must be at least the parameter -- a checker that
// flagged legal traffic is the failure mode that gets a checker ignored.
drive_cell(1'b0, 40, 80, 40);
drive_cell(1'b1, 40, 80, 40);
drive_cell(1'b0, 40, 80, 40);
drive_cell(1'b1, 40, 80, 40);
if (n_log !== 4) begin
$display("FAIL: %0d cells reported, expected 4", n_log); errors++; end
if (n_bad !== '0) begin
$display("FAIL: %0d legal cells flagged bad", n_bad); errors++; end
// Q1: the values must come back in order.
if (val_log[0] !== 1'b0 || val_log[1] !== 1'b1
|| val_log[2] !== 1'b0 || val_log[3] !== 1'b1) begin
$display("FAIL: cell values were %b%b%b%b, expected 0101",
val_log[0], val_log[1], val_log[2], val_log[3]); errors++; end
// Q3: the high phase is measured, not assumed.
if (hi_log[0] < 16'd75 || hi_log[0] > 16'd85) begin
$display("FAIL: an 80-tick high phase measured %0d", hi_log[0]); errors++; end
// ---- 2: a SHORT SETUP. SDA changes only 4 ticks before the rising edge, where
// tSU;DAT demands 10. Q3's setup half must fail and NOTHING ELSE may --
// the bit's value is perfectly well defined and the high phase is legal.
begin
base = n_log;
drive_cell(1'b0, 4, 80, 40);
if (vs_log[base] !== 1'b1) begin
$display("FAIL: a 4-tick setup was not flagged (tSU;DAT = %0d)", T_SU_DAT);
errors++; end
if (vm_log[base] !== 1'b0) begin
$display("FAIL: a short setup also flagged the MEANING -- the two are different questions");
errors++; end
if (vh_log[base] !== 1'b0) begin
$display("FAIL: a short setup also flagged a short high phase"); errors++; end
if (su_log[base] > 16'd6) begin
$display("FAIL: a 4-tick setup measured %0d ticks", su_log[base]); errors++; end
end
// ---- 3: THE BOUNDARY. A setup of EXACTLY tSU;DAT is legal, because the spec
// value is a minimum. A checker that rejects the boundary rejects
// compliant traffic, which is worse than missing a violation.
begin
base = n_log;
drive_cell(1'b1, T_SU_DAT, 80, 40);
if (vs_log[base] !== 1'b0) begin
$display("FAIL: a setup of EXACTLY tSU;DAT (%0d ticks) was rejected", T_SU_DAT);
errors++; end
end
// ---- 4: one tick BELOW the boundary must fail. Testing the last legal value
// and the first illegal one is what pins down a comparison; either alone
// passes on a design that is off by one in the other direction.
//
// The value is 0 because the PREVIOUS cell drove 1. A setup-time test must
// actually CHANGE the signal: driving the same value again produces no edge,
// so the stability timer keeps accumulating from the previous cell and the
// measured setup is the whole history rather than the interval under test.
// This test passed for that reason before the value was alternated.
begin
base = n_log;
drive_cell(1'b0, T_SU_DAT - 1, 80, 40);
if (vs_log[base] !== 1'b1) begin
$display("FAIL: a setup of tSU;DAT-1 (%0d ticks) was accepted", T_SU_DAT - 1);
errors++; end
end
// ---- 5: SDA MOVES DURING THE HIGH PHASE. Q2's fact must be reported and Q1's
// verdict must fail -- there is no single level this cell means. The setup
// was generous, so Q3 must NOT fail: the bit is not late, it is undefined.
begin
base = n_log;
scl_in = 1'b0; sda_in = 1'b0; tick(40);
scl_in = 1'b1; tick(30);
sda_in = 1'b1; tick(30); // an edge while SCL is HIGH
scl_in = 1'b0; tick(40);
if (vm_log[base] !== 1'b1) begin
$display("FAIL: an SDA edge during the high phase did not fail the MEANING test");
errors++; end
if (vs_log[base] !== 1'b0) begin
$display("FAIL: an undefined cell was also reported as a setup violation");
errors++; end
if (val_log[base] !== 1'b0) begin
$display("FAIL: the reported value should be the level AT THE RISING EDGE (0)");
errors++; end
end
// ---- 5b: WHICH SAMPLE IS THE BIT. When SDA changes in the same cycle the rising
// edge is observed -- a zero setup time -- the block must report the level AT the
// edge, not the one before it. The choice has to be specified either way; what
// cannot happen is for it to be accidental, because then two implementations of
// the same checker disagree about what a marginal capture contained.
//
// The setup is zero, so viol_setup must also fire: this is simultaneously the
// worst possible setup time and a well-defined level.
begin
base = n_log;
scl_in = 1'b0; sda_in = 1'b1; tick(40);
// one negedge: SDA changes and SCL rises together
sda_in = 1'b0; scl_in = 1'b1; tick(80);
scl_in = 1'b0; tick(40);
if (val_log[base] !== 1'b0) begin
$display("FAIL: with SDA changing at the rising edge the reported value was %b -- the block sampled the PREVIOUS level, not the level at the edge",
val_log[base]); errors++; end
if (vs_log[base] !== 1'b1) begin
$display("FAIL: a zero setup time was not flagged"); errors++; end
end
// ---- 6: a SHORT HIGH PHASE. 40 ticks where tHIGH(min) demands 60. Only Q3's
// high-phase half may fail.
begin
base = n_log;
drive_cell(1'b0, 40, 40, 40);
if (vh_log[base] !== 1'b1) begin
$display("FAIL: a 40-tick high phase was not flagged (tHIGH min = %0d)",
T_HIGH_MIN); errors++; end
if (vm_log[base] !== 1'b0 || vs_log[base] !== 1'b0) begin
$display("FAIL: a short high phase also flagged another question"); errors++; end
end
// ---- 7: tHIGH exactly at the minimum is legal.
begin
base = n_log;
drive_cell(1'b1, 40, T_HIGH_MIN, 40);
if (vh_log[base] !== 1'b0) begin
$display("FAIL: a high phase of EXACTLY tHIGH(min) was rejected"); errors++; end
end
// ---- 8: THREE questions failing INDEPENDENTLY is the whole point of the
// block, so check that a cell can fail two of them at once and report both.
begin
base = n_log;
scl_in = 1'b0; sda_in = 1'b0; tick(3); // short setup ...
scl_in = 1'b1; tick(15);
sda_in = 1'b1; tick(15); // ... AND an edge while high
scl_in = 1'b0; tick(40); // ... AND a 30-tick high phase
if (!(vs_log[base] && vm_log[base] && vh_log[base])) begin
$display("FAIL: a cell failing all three questions reported %b%b%b",
vs_log[base], vm_log[base], vh_log[base]); errors++; end
end
// ---- 9: an IDLE bus reports nothing. No SCL activity means no cells, and the
// bus spends most of its life here.
begin
cells_before = n_cells;
sda_in = 1'b1; scl_in = 1'b1; tick(200);
if (n_cells !== cells_before) begin
$display("FAIL: an idle bus produced %0d cells", n_cells - cells_before); errors++; end
end
// ---- 10: SCL activity with NO SDA movement at all -- a clock running on an
// idle-high SDA. Every cell is legal and reads 1. This is what a bus
// recovery sequence looks like, and it must not be flagged.
begin
bad_before = n_bad;
sda_in = 1'b1;
repeat (9) drive_cell(1'b1, 40, 80, 40);
if (n_bad !== bad_before) begin
$display("FAIL: nine clean recovery pulses produced %0d violations",
n_bad - bad_before); errors++; end
end
if (errors == 0)
$display("PASS: the three questions are judged independently, both boundaries are exact, an undefined cell is not a late cell");
else $display("FAIL: %0d error(s)", errors);
$finish;
end
endmodule // A BIT-CELL classifier. (Verilog-2001) It watches SDA and SCL and, for every SCL high phase, answers
// the three questions that between them decide whether a bit is legal:
//
// 1. WHAT DOES IT MEAN? the level of SDA while SCL is HIGH
// 2. WHEN MAY IT CHANGE? only while SCL is LOW
// 3. HOW LONG MUST IT HOLD? stable for tSU;DAT before the rise, and through the
// whole high phase
//
// Those are three separate obligations and a real capture can fail any one of them
// independently, which is why this block reports three separate verdicts rather than
// one "bit bad" flag. Chapters 11.3 and 11.4 attach the specification's numbers to
// questions 3 and 2; this block is the frame they hang on.
//
// It is PASSIVE: it observes the two wires and drives nothing.
//
// One thing it deliberately does NOT do is decide whether an SDA edge during the high
// phase is an error. Chapter 5.1 established that such an edge is RESERVED for framing,
// so it is either a START/STOP (legal, and not a bit at all) or a corrupt bit. Only a
// frame decoder knows which. So the block reports the FACT -- edge_while_high -- and
// leaves the interpretation to its consumer.
module i2c_bit_cell_checker #(
parameter TICK_W = 16,
// tSU;DAT, in sample-clock ticks. Fast-mode is 100 ns, so 10 ticks at 100 MHz.
parameter T_SU_DAT = 10,
// tHIGH minimum, in ticks. Fast-mode is 0.6 us, so 60 ticks at 100 MHz.
parameter T_HIGH_MIN = 60
)(
input wire clk,
input wire rst_n,
// Both wires, already synchronised and filtered by the input stage of Module 4.
input wire sda_in,
input wire scl_in,
// ---- the cell, reported at the END of each high phase ----
output reg cell_valid, // pulse: a high phase just ended
output reg cell_value, // Q1: the level sampled at the rising edge
output reg [TICK_W-1:0] cell_high_ticks, // how long the high phase lasted
output reg [TICK_W-1:0] cell_su_ticks, // how long SDA was stable before the rise
// ---- the three verdicts, one per question ----
// Q1 fails when the level cannot be determined: SDA moved during the high phase, so
// there is no single level the cell "means".
output reg viol_meaning,
// Q2 fails when SDA changed while SCL was HIGH. Reported as a fact by
// edge_while_high and as a violation only once the consumer says it was a data cell.
output reg edge_while_high,
// Q3 fails when SDA was not stable for T_SU_DAT before the rising edge, or when the
// high phase itself was shorter than T_HIGH_MIN.
output reg viol_setup,
output reg viol_high_short,
// ---- running totals, so a capture can be summarised ----
output reg [TICK_W-1:0] n_cells,
output reg [TICK_W-1:0] n_bad
);
reg sda_q, scl_q;
wire scl_rise, scl_fall, sda_changed;
assign scl_rise = !scl_q && scl_in;
assign scl_fall = scl_q && !scl_in;
assign sda_changed = sda_q != sda_in;
// How long SDA has been stable, counted continuously. At the rising edge of SCL this
// counter IS tSU;DAT as observed -- which is the cheapest possible way to measure a
// setup time: do not start a timer when the edge arrives, because by then it is too
// late. Run the timer always and sample it.
reg [TICK_W-1:0] stable_ticks;
reg [TICK_W-1:0] high_ticks;
// A measurement must INCLUDE the sample period in which it is taken. Reading the
// register directly gives the count as of the PREVIOUS edge, which under-reports
// every interval by exactly one tick -- a systematic error that shifts every
// comparison against a spec minimum by one sample period, and one that only a test
// at the exact boundary will find. So both counters are sampled through a
// combinational "including this cycle" value.
wire [TICK_W-1:0] stable_now, high_now;
assign stable_now = sda_changed ? {TICK_W{1'b0}} : (stable_ticks + 1'b1);
assign high_now = high_ticks + 1'b1;
// Latched during the high phase, reported when it ends.
reg in_high;
reg moved_during_high;
reg value_at_rise;
reg [TICK_W-1:0] su_at_rise;
always @(posedge clk) begin
if (!rst_n) begin
sda_q <= 1'b1; // an idle bus is high on both wires
scl_q <= 1'b1;
stable_ticks <= {TICK_W{1'b0}};
high_ticks <= {TICK_W{1'b0}};
in_high <= 1'b0;
moved_during_high <= 1'b0;
value_at_rise <= 1'b1;
su_at_rise <= {TICK_W{1'b0}};
cell_valid <= 1'b0;
cell_value <= 1'b1;
cell_high_ticks <= {TICK_W{1'b0}};
cell_su_ticks <= {TICK_W{1'b0}};
viol_meaning <= 1'b0;
edge_while_high <= 1'b0;
viol_setup <= 1'b0;
viol_high_short <= 1'b0;
n_cells <= {TICK_W{1'b0}};
n_bad <= {TICK_W{1'b0}};
end else begin
sda_q <= sda_in;
scl_q <= scl_in;
cell_valid <= 1'b0;
edge_while_high <= 1'b0;
// ---- the always-running stability timer ----
stable_ticks <= stable_now;
if (scl_rise) begin
// The rising edge is where Q1 is answered and Q3's setup half is judged.
in_high <= 1'b1;
high_ticks <= {TICK_W{1'b0}};
moved_during_high <= 1'b0;
value_at_rise <= sda_in;
su_at_rise <= stable_now;
end else if (scl_fall) begin
if (in_high) begin
// The cell is over. Report everything at once, so a consumer sees a
// complete verdict rather than having to assemble one.
in_high <= 1'b0;
cell_valid <= 1'b1;
cell_value <= value_at_rise;
cell_high_ticks <= high_now;
cell_su_ticks <= su_at_rise;
// Q1: if SDA moved during the high phase there is no single level
// this cell means. That is a different failure from a short setup
// time -- the bit is not late, it is undefined.
viol_meaning <= moved_during_high;
// Q3, both halves. The setup comparison is STRICTLY LESS THAN, so a
// measurement exactly equal to the minimum passes: the spec value is
// a minimum, and a design that rejected the boundary would reject
// legal traffic.
viol_setup <= (su_at_rise < T_SU_DAT);
viol_high_short <= (high_now < T_HIGH_MIN);
n_cells <= n_cells + 1'b1;
if (moved_during_high
|| (su_at_rise < T_SU_DAT)
|| (high_now < T_HIGH_MIN))
n_bad <= n_bad + 1'b1;
end
end else if (in_high) begin
high_ticks <= high_now;
if (sda_changed) begin
// Q2: SDA moved while SCL was high. A FACT, not yet a verdict --
// Chapter 5.1 reserves this edge for framing, so it is either a
// START/STOP or a corrupt bit, and only a frame decoder knows which.
moved_during_high <= 1'b1;
edge_while_high <= 1'b1;
end
end
end
end
endmodule `timescale 1ns/1ps
// The sample clock is 100 MHz, so one tick is 10 ns and Fast-mode's parameters are round
// numbers: tSU;DAT = 100 ns = 10 ticks, tHIGH(min) = 0.6 us = 60 ticks. Every stimulus
// below is written in TICKS and the expected results are derived from the parameters,
// not from a table of constants -- so the tests check the comparison, not a transcription.
module i2c_bit_cell_checker_tb; // Verilog-2001
localparam TICK_W = 16;
localparam T_SU_DAT = 10; // Fast-mode tSU;DAT = 100 ns
localparam T_HIGH_MIN = 60; // Fast-mode tHIGH = 0.6 us
reg clk = 1'b0;
always #5 clk = ~clk; // 100 MHz: one tick per 10 ns
reg rst_n = 1'b0;
reg sda_in = 1'b1, scl_in = 1'b1;
wire cell_valid, cell_value, viol_meaning, edge_while_high;
wire viol_setup, viol_high_short;
wire [TICK_W-1:0] cell_high_ticks, cell_su_ticks, n_cells, n_bad;
integer errors = 0;
integer base = 0;
reg [TICK_W-1:0] cells_before, bad_before;
i2c_bit_cell_checker #(.TICK_W(TICK_W), .T_SU_DAT(T_SU_DAT), .T_HIGH_MIN(T_HIGH_MIN))
dut (
.clk(clk), .rst_n(rst_n), .sda_in(sda_in), .scl_in(scl_in), .cell_valid(cell_valid),
.cell_value(cell_value), .cell_high_ticks(cell_high_ticks),
.cell_su_ticks(cell_su_ticks), .viol_meaning(viol_meaning),
.edge_while_high(edge_while_high), .viol_setup(viol_setup),
.viol_high_short(viol_high_short), .n_cells(n_cells), .n_bad(n_bad));
initial begin #500000; $display("FAIL: watchdog expired"); $finish; end
// ---- observation: capture each cell's verdict as it is reported ----------------
reg [TICK_W-1:0] su_log [0:31];
reg [TICK_W-1:0] hi_log [0:31];
reg vm_log [0:31];
reg vs_log [0:31];
reg vh_log [0:31];
reg val_log [0:31];
integer n_log = 0;
always @(posedge clk) if (rst_n && cell_valid && n_log < 32) begin
su_log[n_log] = cell_su_ticks;
hi_log[n_log] = cell_high_ticks;
vm_log[n_log] = viol_meaning;
vs_log[n_log] = viol_setup;
vh_log[n_log] = viol_high_short;
val_log[n_log] = cell_value;
n_log = n_log + 1;
end
task tick;
input integer n;
begin
repeat (n) @(negedge clk);
end
endtask
// Drive one bit cell: present the value, wait `su` ticks, raise SCL for `hi` ticks,
// then drop it and wait `lo` ticks. This is the cell in its three parts, so a test
// can make any one of them illegal on its own.
task drive_cell;
input v;
input integer su;
input integer hi;
input integer lo;
begin
scl_in = 1'b0;
sda_in = v; tick(su);
scl_in = 1'b1; tick(hi);
scl_in = 1'b0; tick(lo);
end
endtask
initial begin
tick(3);
if (n_cells !== {TICK_W{1'b0}}) begin $display("FAIL: n_cells out of reset"); errors = errors + 1; end
rst_n = 1'b1; tick(2);
sda_in = 1'b1; scl_in = 1'b0; tick(5);
// ---- 1: four LEGAL cells with generous margins. Nothing may be flagged, and
// the measured setup must be at least the parameter -- a checker that
// flagged legal traffic is the failure mode that gets a checker ignored.
drive_cell(1'b0, 40, 80, 40);
drive_cell(1'b1, 40, 80, 40);
drive_cell(1'b0, 40, 80, 40);
drive_cell(1'b1, 40, 80, 40);
if (n_log !== 4) begin
$display("FAIL: %0d cells reported, expected 4", n_log); errors = errors + 1; end
if (n_bad !== {TICK_W{1'b0}}) begin
$display("FAIL: %0d legal cells flagged bad", n_bad); errors = errors + 1; end
// Q1: the values must come back in order.
if (val_log[0] !== 1'b0 || val_log[1] !== 1'b1
|| val_log[2] !== 1'b0 || val_log[3] !== 1'b1) begin
$display("FAIL: cell values were %b%b%b%b, expected 0101",
val_log[0], val_log[1], val_log[2], val_log[3]); errors = errors + 1; end
// Q3: the high phase is measured, not assumed.
if (hi_log[0] < 16'd75 || hi_log[0] > 16'd85) begin
$display("FAIL: an 80-tick high phase measured %0d", hi_log[0]); errors = errors + 1; end
// ---- 2: a SHORT SETUP. SDA changes only 4 ticks before the rising edge, where
// tSU;DAT demands 10. Q3's setup half must fail and NOTHING ELSE may --
// the bit's value is perfectly well defined and the high phase is legal.
begin
base = n_log;
drive_cell(1'b0, 4, 80, 40);
if (vs_log[base] !== 1'b1) begin
$display("FAIL: a 4-tick setup was not flagged (tSU;DAT = %0d)", T_SU_DAT);
errors = errors + 1; end
if (vm_log[base] !== 1'b0) begin
$display("FAIL: a short setup also flagged the MEANING -- the two are different questions");
errors = errors + 1; end
if (vh_log[base] !== 1'b0) begin
$display("FAIL: a short setup also flagged a short high phase"); errors = errors + 1; end
if (su_log[base] > 16'd6) begin
$display("FAIL: a 4-tick setup measured %0d ticks", su_log[base]); errors = errors + 1; end
end
// ---- 3: THE BOUNDARY. A setup of EXACTLY tSU;DAT is legal, because the spec
// value is a minimum. A checker that rejects the boundary rejects
// compliant traffic, which is worse than missing a violation.
begin
base = n_log;
drive_cell(1'b1, T_SU_DAT, 80, 40);
if (vs_log[base] !== 1'b0) begin
$display("FAIL: a setup of EXACTLY tSU;DAT (%0d ticks) was rejected", T_SU_DAT);
errors = errors + 1; end
end
// ---- 4: one tick BELOW the boundary must fail. Testing the last legal value
// and the first illegal one is what pins down a comparison; either alone
// passes on a design that is off by one in the other direction.
//
// The value is 0 because the PREVIOUS cell drove 1. A setup-time test must
// actually CHANGE the signal: driving the same value again produces no edge,
// so the stability timer keeps accumulating from the previous cell and the
// measured setup is the whole history rather than the interval under test.
// This test passed for that reason before the value was alternated.
begin
base = n_log;
drive_cell(1'b0, T_SU_DAT - 1, 80, 40);
if (vs_log[base] !== 1'b1) begin
$display("FAIL: a setup of tSU;DAT-1 (%0d ticks) was accepted", T_SU_DAT - 1);
errors = errors + 1; end
end
// ---- 5: SDA MOVES DURING THE HIGH PHASE. Q2's fact must be reported and Q1's
// verdict must fail -- there is no single level this cell means. The setup
// was generous, so Q3 must NOT fail: the bit is not late, it is undefined.
begin
base = n_log;
scl_in = 1'b0; sda_in = 1'b0; tick(40);
scl_in = 1'b1; tick(30);
sda_in = 1'b1; tick(30); // an edge while SCL is HIGH
scl_in = 1'b0; tick(40);
if (vm_log[base] !== 1'b1) begin
$display("FAIL: an SDA edge during the high phase did not fail the MEANING test");
errors = errors + 1; end
if (vs_log[base] !== 1'b0) begin
$display("FAIL: an undefined cell was also reported as a setup violation");
errors = errors + 1; end
if (val_log[base] !== 1'b0) begin
$display("FAIL: the reported value should be the level AT THE RISING EDGE (0)");
errors = errors + 1; end
end
// ---- 5b: WHICH SAMPLE IS THE BIT. When SDA changes in the same cycle the rising
// edge is observed -- a zero setup time -- the block must report the level AT the
// edge, not the one before it. The choice has to be specified either way; what
// cannot happen is for it to be accidental, because then two implementations of
// the same checker disagree about what a marginal capture contained.
//
// The setup is zero, so viol_setup must also fire: this is simultaneously the
// worst possible setup time and a well-defined level.
begin
base = n_log;
scl_in = 1'b0; sda_in = 1'b1; tick(40);
// one negedge: SDA changes and SCL rises together
sda_in = 1'b0; scl_in = 1'b1; tick(80);
scl_in = 1'b0; tick(40);
if (val_log[base] !== 1'b0) begin
$display("FAIL: with SDA changing at the rising edge the reported value was %b -- the block sampled the PREVIOUS level, not the level at the edge",
val_log[base]); errors = errors + 1; end
if (vs_log[base] !== 1'b1) begin
$display("FAIL: a zero setup time was not flagged"); errors = errors + 1; end
end
// ---- 6: a SHORT HIGH PHASE. 40 ticks where tHIGH(min) demands 60. Only Q3's
// high-phase half may fail.
begin
base = n_log;
drive_cell(1'b0, 40, 40, 40);
if (vh_log[base] !== 1'b1) begin
$display("FAIL: a 40-tick high phase was not flagged (tHIGH min = %0d)",
T_HIGH_MIN); errors = errors + 1; end
if (vm_log[base] !== 1'b0 || vs_log[base] !== 1'b0) begin
$display("FAIL: a short high phase also flagged another question"); errors = errors + 1; end
end
// ---- 7: tHIGH exactly at the minimum is legal.
begin
base = n_log;
drive_cell(1'b1, 40, T_HIGH_MIN, 40);
if (vh_log[base] !== 1'b0) begin
$display("FAIL: a high phase of EXACTLY tHIGH(min) was rejected"); errors = errors + 1; end
end
// ---- 8: THREE questions failing INDEPENDENTLY is the whole point of the
// block, so check that a cell can fail two of them at once and report both.
begin
base = n_log;
scl_in = 1'b0; sda_in = 1'b0; tick(3); // short setup ...
scl_in = 1'b1; tick(15);
sda_in = 1'b1; tick(15); // ... AND an edge while high
scl_in = 1'b0; tick(40); // ... AND a 30-tick high phase
if (!(vs_log[base] && vm_log[base] && vh_log[base])) begin
$display("FAIL: a cell failing all three questions reported %b%b%b",
vs_log[base], vm_log[base], vh_log[base]); errors = errors + 1; end
end
// ---- 9: an IDLE bus reports nothing. No SCL activity means no cells, and the
// bus spends most of its life here.
begin
cells_before = n_cells;
sda_in = 1'b1; scl_in = 1'b1; tick(200);
if (n_cells !== cells_before) begin
$display("FAIL: an idle bus produced %0d cells", n_cells - cells_before); errors = errors + 1; end
end
// ---- 10: SCL activity with NO SDA movement at all -- a clock running on an
// idle-high SDA. Every cell is legal and reads 1. This is what a bus
// recovery sequence looks like, and it must not be flagged.
begin
bad_before = n_bad;
sda_in = 1'b1;
repeat (9) drive_cell(1'b1, 40, 80, 40);
if (n_bad !== bad_before) begin
$display("FAIL: nine clean recovery pulses produced %0d violations",
n_bad - bad_before); errors = errors + 1; end
end
if (errors == 0)
$display("PASS: the three questions are judged independently, both boundaries are exact, an undefined cell is not a late cell");
else $display("FAIL: %0d error(s)", errors);
$finish;
end
endmodule library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- A BIT-CELL classifier. For every SCL high phase it answers the three questions that
-- between them decide whether a bit is legal:
--
-- 1. WHAT DOES IT MEAN? the level of SDA while SCL is HIGH
-- 2. WHEN MAY IT CHANGE? only while SCL is LOW
-- 3. HOW LONG MUST IT HOLD? stable for tSU;DAT before the rise, and through the whole
-- high phase
--
-- Those are three separate obligations and a real capture can fail any one independently,
-- which is why this block reports three separate verdicts rather than one "bit bad" flag.
--
-- It deliberately does NOT decide whether an SDA edge during the high phase is an error.
-- Chapter 5.1 established that such an edge is RESERVED for framing, so it is either a
-- START/STOP (legal, and not a bit at all) or a corrupt bit -- and only a frame decoder knows
-- which. The block reports the FACT, edge_while_high, and leaves the interpretation to its
-- consumer.
--
-- PASSIVE: observes the two wires and drives nothing.
entity i2c_bit_cell_checker is
generic (
TICK_W : positive := 16;
-- tSU;DAT in sample-clock ticks. Fast-mode is 100 ns, so 10 ticks at 100 MHz.
T_SU_DAT : natural := 10;
-- tHIGH minimum in ticks. Fast-mode is 0.6 us, so 60 ticks at 100 MHz.
T_HIGH_MIN : natural := 60
);
port (
clk : in std_logic;
rst_n : in std_logic;
-- Both wires, already synchronised and filtered by the input stage of Module 4.
sda_in : in std_logic;
scl_in : in std_logic;
-- the cell, reported at the END of each high phase
cell_valid : out std_logic;
cell_value : out std_logic;
cell_high_ticks : out unsigned(TICK_W - 1 downto 0);
cell_su_ticks : out unsigned(TICK_W - 1 downto 0);
-- the three verdicts, one per question
viol_meaning : out std_logic; -- Q1: no single level; SDA moved during the phase
edge_while_high : out std_logic; -- Q2: a FACT, not yet a verdict
viol_setup : out std_logic; -- Q3a: shorter than tSU;DAT
viol_high_short : out std_logic; -- Q3b: the high phase itself was too short
n_cells : out unsigned(TICK_W - 1 downto 0);
n_bad : out unsigned(TICK_W - 1 downto 0)
);
end entity;
architecture rtl of i2c_bit_cell_checker is
signal sda_q, scl_q : std_logic := '1';
signal scl_rise, scl_fall, sda_changed : std_logic;
signal stable_ticks, high_ticks : unsigned(TICK_W - 1 downto 0) := (others => '0');
-- A measurement must INCLUDE the sample period in which it is taken. Reading the register
-- directly gives the count as of the PREVIOUS edge, which under-reports every interval by
-- exactly one tick -- a systematic error that shifts every comparison against a spec
-- minimum by one sample period, and one that only a test at the exact boundary will find.
signal stable_now, high_now : unsigned(TICK_W - 1 downto 0);
signal in_high, moved_during_high, value_at_rise : std_logic := '0';
signal su_at_rise : unsigned(TICK_W - 1 downto 0) := (others => '0');
begin
scl_rise <= (not scl_q) and scl_in;
scl_fall <= scl_q and (not scl_in);
sda_changed <= '1' when sda_q /= sda_in else '0';
-- How long SDA has been stable, counted continuously. At the rising edge of SCL this
-- counter IS tSU;DAT as observed -- the cheapest way to measure a setup time: do not start
-- a timer when the edge arrives, because by then the interval is over. Run it always.
stable_now <= (others => '0') when sda_changed = '1' else stable_ticks + 1;
high_now <= high_ticks + 1;
process (clk)
begin
if rising_edge(clk) then
if rst_n = '0' then
sda_q <= '1'; -- an idle bus is high on both wires
scl_q <= '1';
stable_ticks <= (others => '0');
high_ticks <= (others => '0');
in_high <= '0';
moved_during_high <= '0';
value_at_rise <= '1';
su_at_rise <= (others => '0');
cell_valid <= '0';
cell_value <= '1';
cell_high_ticks <= (others => '0');
cell_su_ticks <= (others => '0');
viol_meaning <= '0';
edge_while_high <= '0';
viol_setup <= '0';
viol_high_short <= '0';
n_cells <= (others => '0');
n_bad <= (others => '0');
else
sda_q <= sda_in;
scl_q <= scl_in;
cell_valid <= '0';
edge_while_high <= '0';
stable_ticks <= stable_now;
if scl_rise = '1' then
-- The rising edge is where Q1 is answered and Q3's setup half is judged.
in_high <= '1';
high_ticks <= (others => '0');
moved_during_high <= '0';
value_at_rise <= sda_in;
su_at_rise <= stable_now;
elsif scl_fall = '1' then
if in_high = '1' then
-- The cell is over. Report everything at once, so a consumer sees a
-- complete verdict rather than having to assemble one.
in_high <= '0';
cell_valid <= '1';
cell_value <= value_at_rise;
cell_high_ticks <= high_now;
cell_su_ticks <= su_at_rise;
-- Q1: if SDA moved during the high phase there is no single level
-- this cell means. A different failure from a short setup time --
-- the bit is not late, it is undefined.
viol_meaning <= moved_during_high;
-- Q3, both halves. The comparisons are STRICTLY LESS THAN, so a
-- measurement exactly equal to a specified minimum passes: the
-- table's values are minima, and rejecting the boundary would reject
-- compliant traffic.
if su_at_rise < to_unsigned(T_SU_DAT, TICK_W) then
viol_setup <= '1';
else
viol_setup <= '0';
end if;
if high_now < to_unsigned(T_HIGH_MIN, TICK_W) then
viol_high_short <= '1';
else
viol_high_short <= '0';
end if;
n_cells <= n_cells + 1;
if moved_during_high = '1'
or su_at_rise < to_unsigned(T_SU_DAT, TICK_W)
or high_now < to_unsigned(T_HIGH_MIN, TICK_W) then
n_bad <= n_bad + 1;
end if;
end if;
elsif in_high = '1' then
high_ticks <= high_now;
if sda_changed = '1' then
-- Q2: SDA moved while SCL was high. A FACT, not yet a verdict.
moved_during_high <= '1';
edge_while_high <= '1';
end if;
end if;
end if;
end if;
end process;
end architecture; library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- 100 MHz sample clock, so one tick is 10 ns and Fast-mode's parameters are round numbers:
-- tSU;DAT = 100 ns = 10 ticks, tHIGH(min) = 0.6 us = 60 ticks. Every stimulus is written in
-- TICKS and every expectation is derived from the generics rather than from constants, so the
-- tests check the comparisons and not a transcription.
entity i2c_bit_cell_checker_tb is
end entity;
architecture sim of i2c_bit_cell_checker_tb is
constant TICK_W : positive := 16;
constant T_SU_DAT : natural := 10;
constant T_HIGH_MIN : natural := 60;
signal clk : std_logic := '0';
signal rst_n : std_logic := '0';
signal sda_in, scl_in : std_logic := '1';
signal cell_valid, cell_value, viol_meaning, edge_while_high : std_logic;
signal viol_setup, viol_high_short : std_logic;
signal cell_high_ticks, cell_su_ticks : unsigned(TICK_W - 1 downto 0);
signal n_cells, n_bad : unsigned(TICK_W - 1 downto 0);
-- observation, owned solely by the observe process
type tick_arr is array (0 to 31) of unsigned(TICK_W - 1 downto 0);
type bit_arr is array (0 to 31) of std_logic;
signal su_log, hi_log : tick_arr := (others => (others => '0'));
signal vm_log, vs_log, vh_log, val_log : bit_arr := (others => '0');
signal n_log : natural := 0;
signal test_done : std_logic := '0';
begin
dut : entity work.i2c_bit_cell_checker
generic map (TICK_W => TICK_W, T_SU_DAT => T_SU_DAT, T_HIGH_MIN => T_HIGH_MIN)
port map (clk => clk, rst_n => rst_n, sda_in => sda_in, scl_in => scl_in,
cell_valid => cell_valid, cell_value => cell_value,
cell_high_ticks => cell_high_ticks, cell_su_ticks => cell_su_ticks,
viol_meaning => viol_meaning, edge_while_high => edge_while_high,
viol_setup => viol_setup, viol_high_short => viol_high_short,
n_cells => n_cells, n_bad => n_bad);
clk <= not clk after 5 ns;
watchdog : process
begin
wait for 500 us;
if test_done = '0' then report "watchdog expired" severity failure; end if;
wait;
end process;
observe : process (clk)
begin
if rising_edge(clk) and rst_n = '1' and cell_valid = '1' and n_log < 32 then
su_log(n_log) <= cell_su_ticks;
hi_log(n_log) <= cell_high_ticks;
vm_log(n_log) <= viol_meaning;
vs_log(n_log) <= viol_setup;
vh_log(n_log) <= viol_high_short;
val_log(n_log) <= cell_value;
n_log <= n_log + 1;
end if;
end process;
stim : process
variable errs : natural := 0;
variable base : natural;
variable cells_before, bad_before : unsigned(TICK_W - 1 downto 0);
procedure tick (n : in positive) is
begin
for i in 1 to n loop wait until falling_edge(clk); end loop;
end procedure;
-- Drive one bit cell: present the value, wait `su` ticks, raise SCL for `hi` ticks,
-- then drop it and wait `lo` ticks. The cell in its three parts, so a test can make
-- any one of them illegal on its own.
procedure drive_cell (v : in std_logic; su, hi, lo : in positive) is
begin
scl_in <= '0';
sda_in <= v; tick(su);
scl_in <= '1'; tick(hi);
scl_in <= '0'; tick(lo);
end procedure;
begin
tick(3);
if n_cells /= to_unsigned(0, TICK_W) then
report "n_cells out of reset" severity error; errs := errs + 1; end if;
rst_n <= '1'; tick(2);
sda_in <= '1'; scl_in <= '0'; tick(5);
-- 1: four LEGAL cells with generous margins. Nothing may be flagged -- a checker
-- that flags legal traffic is the failure mode that gets a checker ignored.
drive_cell('0', 40, 80, 40);
drive_cell('1', 40, 80, 40);
drive_cell('0', 40, 80, 40);
drive_cell('1', 40, 80, 40);
if n_log /= 4 then
report "wrong number of cells reported, expected 4" severity error;
errs := errs + 1; end if;
if n_bad /= to_unsigned(0, TICK_W) then
report "legal cells were flagged bad" severity error; errs := errs + 1; end if;
if val_log(0) /= '0' or val_log(1) /= '1' or val_log(2) /= '0' or val_log(3) /= '1' then
report "cell values wrong, expected 0101" severity error; errs := errs + 1; end if;
if hi_log(0) < to_unsigned(75, TICK_W) or hi_log(0) > to_unsigned(85, TICK_W) then
report "an 80-tick high phase measured out of range" severity error;
errs := errs + 1; end if;
-- 2: a SHORT SETUP. Only Q3's setup half may fail -- the bit's value is perfectly
-- well defined and the high phase is legal.
base := n_log;
drive_cell('0', 4, 80, 40);
if vs_log(base) /= '1' then
report "a 4-tick setup was not flagged" severity error; errs := errs + 1; end if;
if vm_log(base) /= '0' then
report "a short setup also flagged the MEANING -- different questions"
severity error; errs := errs + 1; end if;
if vh_log(base) /= '0' then
report "a short setup also flagged a short high phase" severity error;
errs := errs + 1; end if;
-- 3: THE BOUNDARY. A setup of EXACTLY tSU;DAT is legal, because the spec value is a
-- minimum. A checker that rejects the boundary rejects compliant traffic.
base := n_log;
drive_cell('1', T_SU_DAT, 80, 40);
if vs_log(base) /= '0' then
report "a setup of EXACTLY tSU;DAT was rejected" severity error;
errs := errs + 1; end if;
-- 4: one tick BELOW the boundary must fail. Testing the last legal value and the
-- first illegal one is what pins down a comparison.
--
-- The value is 0 because the PREVIOUS cell drove 1. A setup-time test must actually
-- CHANGE the signal: driving the same value again produces no edge, so the stability
-- timer keeps accumulating and the measured setup is the whole history rather than
-- the interval under test.
base := n_log;
drive_cell('0', T_SU_DAT - 1, 80, 40);
if vs_log(base) /= '1' then
report "a setup of tSU;DAT-1 was accepted" severity error; errs := errs + 1; end if;
-- 5: SDA MOVES DURING THE HIGH PHASE. Q1's verdict must fail -- there is no single
-- level this cell means. The setup was generous, so Q3 must NOT fail: the bit is not
-- late, it is undefined.
base := n_log;
scl_in <= '0'; sda_in <= '0'; tick(40);
scl_in <= '1'; tick(30);
sda_in <= '1'; tick(30); -- an edge while SCL is HIGH
scl_in <= '0'; tick(40);
if vm_log(base) /= '1' then
report "an SDA edge during the high phase did not fail the MEANING test"
severity error; errs := errs + 1; end if;
if vs_log(base) /= '0' then
report "an undefined cell was also reported as a setup violation" severity error;
errs := errs + 1; end if;
if val_log(base) /= '0' then
report "the reported value should be the level AT THE RISING EDGE" severity error;
errs := errs + 1; end if;
-- 5b: WHICH SAMPLE IS THE BIT. When SDA changes in the same cycle the rising edge is
-- observed -- a zero setup time -- the block must report the level AT the edge, not the
-- one before it. The choice has to be specified either way; what cannot happen is for it
-- to be accidental, because then two implementations of the same checker disagree about
-- what a marginal capture contained. The setup is zero, so viol_setup must fire too.
base := n_log;
scl_in <= '0'; sda_in <= '1'; tick(40);
sda_in <= '0'; scl_in <= '1'; tick(80); -- SDA changes and SCL rises together
scl_in <= '0'; tick(40);
if val_log(base) /= '0' then
report "with SDA changing at the rising edge the block sampled the PREVIOUS level"
severity error; errs := errs + 1; end if;
if vs_log(base) /= '1' then
report "a zero setup time was not flagged" severity error; errs := errs + 1; end if;
-- 6: a SHORT HIGH PHASE. Only Q3's high-phase half may fail.
base := n_log;
drive_cell('0', 40, 40, 40);
if vh_log(base) /= '1' then
report "a 40-tick high phase was not flagged" severity error; errs := errs + 1; end if;
if vm_log(base) /= '0' or vs_log(base) /= '0' then
report "a short high phase also flagged another question" severity error;
errs := errs + 1; end if;
-- 7: tHIGH exactly at the minimum is legal.
base := n_log;
drive_cell('1', 40, T_HIGH_MIN, 40);
if vh_log(base) /= '0' then
report "a high phase of EXACTLY tHIGH(min) was rejected" severity error;
errs := errs + 1; end if;
-- 8: THREE questions failing INDEPENDENTLY is the whole point, so a cell can fail
-- all three at once and must report all three.
base := n_log;
scl_in <= '0'; sda_in <= '0'; tick(3); -- short setup ...
scl_in <= '1'; tick(15);
sda_in <= '1'; tick(15); -- ... AND an edge while high
scl_in <= '0'; tick(40); -- ... AND a 30-tick high phase
if not (vs_log(base) = '1' and vm_log(base) = '1' and vh_log(base) = '1') then
report "a cell failing all three questions did not report all three"
severity error; errs := errs + 1; end if;
-- 9: an IDLE bus reports nothing. No SCL activity means no cells.
cells_before := n_cells;
sda_in <= '1'; scl_in <= '1'; tick(200);
if n_cells /= cells_before then
report "an idle bus produced cells" severity error; errs := errs + 1; end if;
-- 10: SCL activity with NO SDA movement -- a clock running on an idle-high SDA. Every
-- cell is legal and reads 1. This is what a bus recovery sequence looks like and it
-- must not be flagged.
bad_before := n_bad;
sda_in <= '1';
for i in 1 to 9 loop drive_cell('1', 40, 80, 40); end loop;
if n_bad /= bad_before then
report "nine clean recovery pulses produced violations" severity error;
errs := errs + 1; end if;
if errs = 0 then
report "i2c_bit_cell_checker self-check complete: the three questions are judged "
& "independently, both boundaries are exact, an undefined cell is not a late "
& "cell" severity note;
else
report "i2c_bit_cell_checker self-check FAILED" severity error;
end if;
test_done <= '1';
wait;
end process;
end architecture;6a. Four Decisions Worth Defending
Question 2 is reported as a fact, not judged as a violation. edge_while_high says an SDA edge occurred while SCL was high. Whether that is an error depends on something this block cannot know: Chapter 5.1 reserves such an edge for framing, so it is either a legal START or STOP — in which case it is not a bit at all — or a corrupt bit. Only a frame decoder can tell. A block that guessed would flag every START condition on the bus, which is the false-positive failure Chapter 10.3 §7 argues destroys a checker's usefulness.
The setup time is measured by a timer that runs continuously, not one armed by the edge. This is forced rather than stylistic. A setup interval ends at its reference edge, so by the time the rising edge arrives the interval being measured is already over — there is nothing left to time. The only way to know how long SDA had been stable is to have been counting all along and to sample the counter at the edge. Chapter 11.5 §5a draws the general rule: whether a parameter can be measured with an armed counter is decided by which end of it the reference edge sits at.
Every measurement includes the sample period in which it is taken. Both counters are read through a combinational "including this cycle" value rather than straight out of the register. Without it each interval reads one tick short, which shifts every comparison against a spec minimum by one sample period — a systematic error, in the unsafe direction, that no amount of ordinary stimulus reveals. It was found by the boundary tests in §7, which is precisely what boundary tests are for.
The comparisons are strictly less-than, so a measurement exactly equal to the minimum passes. Table 10's values are minima; a device that hits one exactly is compliant. A checker that rejected the boundary would report violations on conforming traffic, and mutation A1 in §8 injects exactly that.
6b. Verified Execution
$ iverilog -g2012 -o d1 i2c_bit_cell_checker.sv i2c_bit_cell_checker_tb.sv && ./d1
PASS: the three questions are judged independently, both boundaries are exact, an undefined
cell is not a late cell
i2c_bit_cell_checker_tb.sv:236: $finish called at 33060000 (1ps)
$ iverilog -g2005 -o v1 i2c_bit_cell_checker.v i2c_bit_cell_checker_tb.v && ./v1
PASS: the three questions are judged independently, both boundaries are exact, an undefined
cell is not a late cell
i2c_bit_cell_checker_tb.v:246: $finish called at 33060000 (1ps)
$ nvc -a i2c_bit_cell_checker.vhd i2c_bit_cell_checker_tb.vhd
$ nvc -e i2c_bit_cell_checker_tb && nvc -r i2c_bit_cell_checker_tb --stop-time=600us
** Note: 33060ns+0: i2c_bit_cell_checker self-check complete: the three questions are judged
independently, both boundaries are exact, an undefined cell is not a late cellAll three at 33060 ns.
7. What the Testbench Proves
The stimulus drives one bit cell at a time with its three parts independently settable — the setup interval, the high phase and the low tail — so each question can be made to fail on its own.
| # | stimulus | what it establishes |
|---|---|---|
| 1 | four legal cells | nothing flagged; the values come back in order |
| 2 | a 4-tick setup | only Q3's setup half fails |
| 3 | a setup of exactly tSU;DAT | legal — the boundary is inclusive |
| 4 | one tick below the minimum | illegal — the boundary is pinned from both sides |
| 5 | SDA moves during the high phase | Q1 fails; Q3 does not — an undefined cell is not a late one |
| 5b | SDA changes in the same cycle as the rise | the reported level is the one at the edge, and the zero setup is flagged |
| 6 | a 40-tick high phase | only Q3's high-phase half fails |
| 7 | tHIGH exactly at the minimum | legal |
| 8 | all three wrong at once | all three verdicts fire together |
| 9 | an idle bus | no cells reported at all |
| 10 | nine clean pulses on an idle-high SDA | nothing flagged — this is a bus-recovery sequence |
Tests 3 and 4 are the pair that found the off-by-one of §6a, and neither alone would have. Test 3 passes on a design that measures one tick long; test 4 passes on one that measures one tick short. Only requiring both — the last legal value accepted and the first illegal one rejected — pins the comparison down.
Test 5 is the one that keeps the three questions genuinely separate. The stimulus gives a generous setup and then moves SDA mid-phase, so a design that lumped the failures together would report a setup violation as well. Test 8 is the converse: a cell that is wrong in all three ways must report all three, not just the first one found.
Test 10 deserves a note because it is the case a naive checker gets wrong. Nine SCL pulses with SDA released high is the Chapter 5.5 bus-recovery sequence, and it is entirely legal — SDA never moves, so there is no setup interval to fail. A checker that demanded a transition per cell would flag every recovery attempt.
8. Mutation Testing
Six defects injected into the SystemVerilog classifier.
| # | injected defect | outcome |
|---|---|---|
| A1 | the setup comparison rejects the boundary | killed |
| A2 | the measurement excludes the sampling cycle | killed |
| A3 | the high phase is not checked at all | killed |
| A4 | an SDA edge during the high phase is ignored | killed |
| A5 | the cell value is sampled at the falling edge | killed |
| A6 | the stability timer never resets | killed |
Six injected, six killed — and across all nine of this module's designs the tally is 48 injected, 48 killed, no survivors. Several mutations survived their first run and were closed either by a new test or by separating two parameters the specification gives the same value, and one was removed as a provably equivalent mutant. §8 of the later chapters records each of those where it arose.
A5 is the one worth dwelling on, because closing it required specifying something rather than testing something. Sampling sda_q instead of sda_in at the rising edge reads the previous sample. On every legal cell those are the same value — SDA has been stable for at least tSU;DAT — so the mutation is invisible until SDA changes in the very cycle the edge is observed, which is a zero setup time.
So the test that kills it had to decide what the block should report in that case, and the answer is the level at the edge. Either choice is defensible; what is not defensible is leaving it accidental, because then two implementations of the same checker disagree about what a marginal capture contained — and a marginal capture is exactly when you need them to agree. Test 5b makes the choice explicit and asserts it.
A2 is the off-by-one, and its interest is that it is caught only at a boundary. With the measurement one tick short, every setup and every high phase reads low by one sample period. Tests 1, 2, 5 and 6 all still pass, because their margins are tens of ticks. Only tests 3 and 4, sitting exactly on the minimum, notice.
9. Verification Connection — Timing Belongs in an Interface, Not a Test
A timing parameter is a property of the interface, so in a UVM environment it belongs to the interface and its assertions rather than to any sequence. A test that happened to check setup times would check them only where it looked; an interface assertion checks every bit of every transfer in every test ever written against it.
interface i2c_timing_if #(parameter int T_SU_DAT = 10, parameter int T_HIGH_MIN = 60)
(input logic clk);
logic sda, scl;
// A continuously running stability timer, for the reason section 6a gives: a setup
// interval ends at its reference edge, so it cannot be timed by a counter armed there.
int stable_ticks;
always_ff @(posedge clk)
stable_ticks <= ($changed(sda)) ? 0 : stable_ticks + 1;
// ---- QUESTION 3: the data was stable long enough before the rising edge ----
property p_setup;
@(posedge clk) $rose(scl) |-> (stable_ticks >= T_SU_DAT);
endproperty
assert property (p_setup)
else $error("tSU;DAT violated: SDA stable for only %0d ticks", stable_ticks);
// ---- QUESTION 1: the level does not move during the high phase ----
//
// Note the exclusion. An SDA edge while SCL is high is RESERVED for framing, so this
// property must not fire on a legal START or STOP -- and it cannot tell the difference
// itself. `framing_expected` is driven by the monitor that decodes frames. An assertion
// that omitted it would flag every START on the bus, which is the false-positive
// failure that gets a checker switched off.
property p_stable_while_high;
@(posedge clk) disable iff (framing_expected)
(scl && $past(scl)) |-> $stable(sda);
endproperty
assert property (p_stable_while_high)
else $error("SDA moved while SCL was high outside a framing event");
// ---- QUESTION 3, the other half: the high phase was usable ----
int high_ticks;
always_ff @(posedge clk)
high_ticks <= scl ? high_ticks + 1 : 0;
property p_high_long_enough;
@(posedge clk) $fell(scl) |-> (high_ticks >= T_HIGH_MIN);
endproperty
assert property (p_high_long_enough)
else $error("tHIGH violated: the high phase lasted %0d ticks", high_ticks);
logic framing_expected; // driven by the frame monitor
endinterfaceAnd the coverage, which for timing is about how close to the limit traffic actually came — because a suite that only ever ran with enormous margins has not tested the timing at all.
covergroup i2c_setup_margin_cg with function sample(int measured, int minimum);
// The bins are RELATIVE to the specified minimum, not absolute tick counts. That is the
// only formulation that is reusable across speed modes -- an absolute bin set written for
// Fast-mode says nothing useful about Fast-mode Plus, where the same nanosecond figure is
// a different fraction of the budget.
margin: coverpoint (measured - minimum) {
bins violation = {[$:-1]}; // below the minimum: must be reachable in a
// directed test, and must never occur in a
// randomised one
bins exactly_at = {0}; // the boundary -- the case section 7 pins down
bins tight = {[1:5]};
bins comfortable = {[6:50]};
bins vast = {[51:$]};
}
// Crossing the margin with WHICH question is being measured is what stops one comfortable
// parameter from masking another that is permanently tight.
which: coverpoint measured iff (measured >= 0);
endgroup10. FPGA and ASIC Implications
The block is two counters and a handful of state. At TICK_W = 16 it is roughly 50 flops. There is no arithmetic beyond increments and two magnitude compares against parameters, both on paths with a whole bit time to settle.
Sizing the sample clock is the real decision, and it is a resolution-versus-area trade. A 100 MHz sampler gives 10 ns granularity, which resolves Fast-mode's 100 ns setup to 10 % and Fast-mode Plus's 50 ns to 20 %. Going faster improves the resolution linearly and costs a faster clock domain; the honest answer is that a monitoring checker does not need compliance-grade resolution, and if you need compliance-grade resolution you need a scope, not more flops.
The two wires must be synchronised before they arrive. This block samples sda_in and scl_in on the system clock and compares consecutive samples. Feeding raw pads in would let a metastable sample produce a phantom edge — and a phantom edge here is a phantom bit cell with garbage measurements. The input stage of Module 4 is a prerequisite, not an optimisation.
And the spike filter of Chapter 11.8 belongs in front of it, with a consequence worth knowing now. That filter delays every transition by its threshold, equally on both lines. Because this block measures intervals between transitions on the two lines, a delay applied equally to both cancels out of the measurement — the interval is unchanged. What does not cancel is the filter's effect on the budget, which Chapter 11.9 spends explicitly.
11. Debugging — The Bus That Worked Until the Board Got Colder
Pitfall — a setup-time violation that is invisible in a logic-analyser capture
// A sensor read on a Fast-mode bus. The master's bit engine presents the next data bit
// on the falling edge of SCL and releases SCL again after a fixed delay:
//
// on SCL falling: sda_out <= next_bit;
// after N cycles: scl_out <= 1; // release SCL
//
// N was chosen from the tLOW minimum -- 1.3 us at Fast-mode, so N covers 1.3 us -- and the
// logic is correct as far as that goes. What was not accounted for is that sda_out drives a
// pad, the pad drives a 300 pF bus through a 4.7 kohm pull-up, and SDA's RISING edge takes
// most of a microsecond to get anywhere near VIH.
//
// So on a bit that goes from 0 to 1, the sequence is:
//
// SCL falls -> sda_out released -> SDA rises SLOWLY -> SCL released
// __ still climbing when SCL goes high __/
//
// tSU;DAT is measured to the point SDA is VALID, not to the point the driver let go.It worked. On the bench, for months, across two board revisions.
Then a unit in a cold-chamber test started returning corrupted sensor values -- not every read, perhaps one in fifty, and only below about 5 degrees. Warming the board made it stop. Nothing in the firmware had changed.
A logic-analyser capture at 24 MHz showed nothing wrong. Every byte was well formed, every acknowledge present, the addresses correct, the framing textbook. The captured SDA trace showed each bit sitting at the right level for the whole high phase, because a logic analyser reports a THRESHOLDED value: once SDA crosses the analyser's own threshold it reads as 1, and the analyser's threshold is not the receiving device's.
The theory that held longest was a marginal supply, because temperature-dependent and intermittent points that way. Considerable time went into the regulator.
A scope on SDA and SCL together resolved it in one screen. On a 0-to-1 bit, SDA was still rising as SCL crossed its own high threshold -- the two edges overlapped. The setup time was not small, it was NEGATIVE: the clock was sampling before the data had arrived. Cold made the pull-up's effective drive slightly worse and the CMOS input thresholds slightly higher, and the margin that had been a few nanoseconds went away.
The master timed tLOW from when it RELEASED SDA rather than from when SDA became valid, so the bus's rise time was spent inside the setup interval instead of before it.
The specification accounts for exactly this: the low phase has to hold tVD;DAT, then the rise, then tSU;DAT, and Chapter 11.9 shows that in Fast-mode those three sum to exactly the tLOW minimum with nothing left over. Designing to tLOW(min) while ignoring the rise means over-committing the low phase by the rise time -- which on a lightly loaded bench board is small enough to get away with, and on a real one is not.
12. Common Misconceptions
"A timing violation means a corrupted bit." Sometimes. A question-1 violation gives different receivers different values, which is worse; a question-2 violation produces a spurious START or STOP and changes the frame's structure; a question-3 violation gives an undefined level that may resolve either way.
"If the capture looks clean the timing is fine." A logic analyser reports a thresholded value against its own threshold, so it cannot show a setup violation at all. §11 is that mistake costing weeks.
"Table 10 is a list of numbers to look up." It is a list of answers to a small number of questions, and almost every entry is a minimum — meaning waiting longer is always compliant. The four maxima are the ones that constrain a design's speed.
"The three questions are really one requirement." They fail independently, which is exactly why the table has sixteen entries. A stable bit can be late; an undefined bit can have a generous setup; a well-defined bit can sit on a clock phase too short to use.
"An SDA edge during the high phase is always an error." It is reserved for framing. A START or STOP is exactly that edge, legally. Only a frame decoder can tell which it was, which is why §6's block reports the fact and refuses to judge it.
"A faster sample clock makes the checker compliance-grade." It improves resolution linearly and never reaches scope territory. A hardware checker's job is continuous monitoring of a working system, not qualification.
13. Reason It Through
A capture shows every byte well formed and the system is intermittently wrong. Which of the three questions do you suspect, and what instrument do you reach for?
Question 3. Questions 1 and 2 change what a capture looks like — an SDA edge inside the high phase, or a frame that restructures — so a clean capture largely rules them out. A setup violation leaves the capture perfect, because the analyser thresholds the signal before recording it. The instruments are a scope, or a checker like §6's that measures the interval in the system itself.
Why can a setup time not be measured with a counter started by the rising edge?
Because the interval ends at that edge. By the time the reference event arrives there is nothing left to time — the question "how long had SDA been stable" is about the past. The only implementation is a timer that runs continuously and is sampled at the edge, which is why §6's block has a free-running stability counter. Contrast a hold time, whose interval begins at its reference edge and which an armed counter measures directly.
A checker reports a setup of exactly the specified minimum as a violation. Why is that worse than missing a real violation?
Because it fires on compliant traffic. A device that hits a minimum exactly is legal, so the checker is now reporting faults that are not faults — and within a few weeks its output is ignored, at which point it occupies the place a working checker would have had. Chapter 10.3 §7 makes the same argument about atomicity: a false positive removes coverage.
SDA changes in the same cycle the rising edge is observed. What should the checker report, and why does it matter that the answer is specified rather than accidental?
Either answer is defensible — §6's block reports the level at the edge. What matters is that it is decided, because this is precisely the marginal case where two implementations of the same checker would otherwise disagree, and a marginal capture is when you most need them to agree. Mutation A5 is unobservable on every legal cell and only separable here, so closing it meant writing the specification down.
The spike filter of Chapter 11.8 delays every transition by its threshold. Does that corrupt this block's measurements?
No, because this block measures intervals between transitions and the filter delays both lines equally, so the delay cancels. What it does affect is the budget: the filter's latency has to come from somewhere inside the low phase, which is Chapter 11.9's subject. A delay that cancels out of a measurement can still consume a margin.
14. Understanding Check
15. Summary
A bit answers three independent questions, and Table 10 has sixteen entries because each can fail alone. What the bit means is the level while SCL is high; when it may change is only while SCL is low; how long it must hold is the setup before the rise plus the whole high phase.
The three failures are not equally visible, and that ordering matters more than the numbers. A question-2 failure restructures the frame and shows up immediately. A question-1 failure is visible in a capture. A question-3 failure leaves the capture perfect and appears as "it works on my board" — which is why it is the one worth building a checker for.
Almost every parameter is a minimum. Waiting longer is compliant, which is why clock stretching is legal and why a bus may idle indefinitely. The four maxima — the clock frequency, the data-valid times, the edge rates, and the spike width to reject — are the ones that constrain how fast a design may be.
A setup time and a hold time are measured differently, and the reason is structural. A setup interval ends at its reference edge so it needs a free-running timer sampled there; a hold interval begins at its edge so an armed counter suffices. Which end the reference edge sits at decides the implementation, and that rule recurs in every chapter of this module.
Include the sampling cycle in every measurement. Omitting it under-reports every interval by one tick, in the unsafe direction, invisibly — until a test sits exactly on a boundary.
Report facts separately from judgements. An SDA edge during the high phase is a fact; whether it is a fault depends on framing that this block cannot see. A checker that guesses fires on legal traffic, and a checker that fires on legal traffic gets switched off.
16. What Comes Next
Chapter 11.2 takes question 3's first half — the clock's own phases — and finds that a legal clock is three constraints rather than one frequency. The surprising case is a clock at a perfectly compliant 400 kHz whose duty cycle is illegal, and the chapter also opens an identity that runs through the whole module: tLOW(min) + tHIGH(min) + tr(max) + tf(max) equals 1/fSCL(max) exactly, in all three speed modes. The period budget is fully accounted for, which means every real design has to beat at least one of the four terms.
From there the module works outward: Chapter 11.3 constrains the data against the clock, Chapter 11.4 constrains how fast a transmitter must be, Chapters 11.5 and 11.6 put numbers on the framing margins, Chapter 11.7 prices the edges, Chapter 11.8 builds the one block in the module that sits in the datapath, and Chapter 11.9 closes a real budget by hand and checks it in hardware.
Continue learning
Related tutorials
- Related topic
The Data-Valid Rule — SDA Stable While SCL Is High
One sentence governs every bit on an I²C bus, and it is derived rather than decreed: the receiver needs a settled value at the instant it looks. What falls out is that an SDA edge while SCL is HIGH cannot be data — which is why the bus reserves it for framing.
- Related topic
Reading an I²C Timing Diagram
A specification timing diagram shows every relationship at once, which is why it looks impenetrable. Read it in passes instead: signals, edges, stable regions, framing, intervals, edge shapes, and finally who owes each requirement.
- Related topic
tSU;DAT and tHD;DAT — The I²C Data Window
Two parameters every bit of every byte must satisfy, measured against two different edges. One has a specified minimum of zero and is in practice among the tightest constraints on the bus — this chapter resolves that contradiction.
- Related topic
Pull-Up Resistors — Sizing, Rise Time and Bus Capacitance
The element that restores a released line, and the price it charges. Because HIGH is recovered passively through a resistor into real bus capacitance, the rising edge takes time — so the resistor sets timing as well as the idle level, and its correct value is a bounded range rather than a number to memorise.
