Skip to content
VLSI Mentor

I²C · Module 7

The ACK/NACK Cycle — What the Ninth Clock Proves

An acknowledge is one device pulling SDA low for one clock pulse. A not-acknowledge is nobody doing anything. That asymmetry decides how the bus behaves when a device is absent, and it is why an ACK proves far less than engineers assume.

Chapter 7.1 established that every byte costs nine clock pulses and that the transmitter's job in the ninth is to stop driving. This chapter is about what happens in the slot it vacated.

It is the most important single bit on the bus, and the most over-interpreted.

1. The Definition, and the Asymmetry Inside It

UM10204 §3.1.6:

The acknowledge takes place after every byte. The acknowledge bit allows the receiver to signal the transmitter that the byte was successfully received and another byte may be sent. The master generates all clock pulses, including the acknowledge ninth clock pulse.

The Acknowledge signal is defined as follows: the transmitter releases the SDA line during the acknowledge clock pulse so the receiver can pull the SDA line LOW and it remains stable LOW during the HIGH period of this clock pulse. Set-up and hold times (specified in Section 6) must also be taken into account.

When SDA remains HIGH during this ninth clock pulse, this is defined as the Not Acknowledge signal.

Read the last two paragraphs together and the asymmetry is unmistakable:

what it iswho does something
ACKSDA pulled LOW for the ninth pulsethe receiver acts
NACKSDA remains HIGHnobody acts

A NACK is not a signal. It is the absence of one. There is no NACK driver, no NACK level anybody asserts, nothing transmitted. The pull-up network of Chapter 2.4 produces the high level because the transmitter released and nothing else pulled down.

That single fact explains most of this chapter, and it has an immediate consequence that is worth stating before anything else: a bus with nothing attached NACKs everything, correctly, with no device participating. The default answer on this bus is "no", and it costs nothing to produce. That is a deliberate and rather elegant piece of design — the failure mode requires no working hardware.

ACK — the receiver pulls the ninth slot low

9 cycles
Nine clock periods, one per bit. SDA carries the byte one zero one zero zero one zero one across the first eight intervals, then is low in the ninth interval because the receiver has pulled it low to acknowledge.eight data bitseight data bitsACKACKtransmitter releases after this bittransmitter releases afterthis bitACK — the receiver pulls lowACK — the receiver pullslowsclsda101001010t0t1t2t3t4t5t6t7t8
Figure 1 — an acknowledged byte. Eight data bits, then a ninth pulse in which the receiver pulls SDA low. The transmitter has released, so the low level is produced entirely by the receiver: somebody is actively saying yes.

NACK — nobody pulls the ninth slot low

9 cycles
Nine clock periods, one per bit. SDA carries the same byte as the previous figure across the first eight intervals, and in the ninth interval it stays high because no device pulled it low. The high level is produced by the pull-up resistor.eight data bitseight data bitsNACKNACKtransmitter releases after this bittransmitter releases afterthis bitNACK — nobody pulls lowNACK — nobody pulls lowsclsda101001011t0t1t2t3t4t5t6t7t8
Figure 2 — the same byte, not acknowledged. Identical in the first eight intervals; in the ninth, nobody pulls the line down and the pull-up leaves it high. No device transmitted anything to produce this — it is what the bus does when left alone, which is why an absent device NACKs correctly without being present.

2. The Acknowledge Is a Bit Like Any Other

One sentence in the definition is easy to skim past and it carries real design weight:

...and it remains stable LOW during the HIGH period of this clock pulse. Set-up and hold times (specified in Section 6) must also be taken into account.

So the acknowledge obeys Chapter 4.2's data-valid rule exactly like a data bit. It is established while SCL is low, held stable through the high period, and released afterwards — and the setup and hold parameters that govern ordinary bits govern it too.

Three consequences:

The receiver must establish the acknowledge while SCL is low. A receiver that decided late and pulled SDA down during the high period would be producing an SDA edge while SCL is high — which Chapter 5.1 established is reserved framing, so it would emit a START or STOP into the middle of a transfer. The decision has to be made in time.

That is a real latency requirement on a slave. Between the eighth rising edge and the ninth falling edge, a slave has to have decided whether it can take the byte. On a fast bus that is not much time, and it is the reason the specification offers clock stretching — Chapter 7.1 §8 quoted the slave's right to hold SCL low precisely when it cannot decide in time.

And the transmitter must sample the answer on the rising edge, for the same reason it samples data there. The block in §5 does exactly that, and a mutation that samples on the falling edge is caught by a test that releases the far end as SCL falls.

3. The Five Reasons for a NACK

UM10204 lists them, and they are worth reading as five genuinely different situations rather than one error condition:

There are five conditions that lead to the generation of a NACK:

  1. No receiver is present on the bus with the transmitted address so there is no device to respond with an acknowledge.
  2. The receiver is unable to receive or transmit because it is performing some real-time function and is not ready to start communication with the master.
  3. During the transfer, the receiver gets data or commands that it does not understand.
  4. During the transfer, the receiver cannot receive any more data bytes.
  5. A master-receiver must signal the end of the transfer to the slave transmitter.

Grouping them by what they actually tell you:

#situationwho NACKswhat it means for the master
1nothing at that addressnobody — the pull-up answersthe device is absent, unpowered, or at a different address
2the device is busythe addressed slaveretry later; the device exists
3the content was not understoodthe addressed slavea protocol or register-map disagreement
4the device is fullthe addressed slavestop sending; what arrived so far is probably fine
5the master is finishedthe masternot an error at all

Two observations about that table are the whole point of it.

Condition 1 is produced by nobody. It is the only one that requires no participating device, and it is the reason an address scan works: writing an address and observing the ninth slot tells you whether anything is there, with no cooperation needed from the device.

Condition 5 is not an error. It is a master-receiver deliberately saying "that was the last byte I want", and it is the normal, correct ending of every read on this bus. Chapter 7.4 is entirely about it. A driver that logs every NACK as an error will log one per read, forever, and the noise will hide conditions 1 through 4.

4. What an ACK Does Not Prove

This is the section to remember, because an acknowledge is routinely treated as a delivery receipt and it is nothing of the kind.

An ACK proves exactly one thing: some device pulled SDA low during that ninth clock pulse. Everything below is outside what the bit can carry.

It does not prove the data was correct. There is no checksum, parity or CRC at this layer. A byte corrupted by a marginal edge arrives, gets sampled as something, and is acknowledged — the receiver has no way to know it is wrong and nothing to compare it against.

It does not prove the device understood it. Condition 3 exists for the case where a device can tell, but a device writing an unrecognised value into a register it does have will acknowledge happily.

It does not prove the device will act on it. An acknowledge is per byte, and it happens the instant the byte arrives. Whether the command is executed, whether an EEPROM write reaches the cell, whether a configuration takes effect — none of that is in scope. An EEPROM acknowledges the byte and then spends milliseconds writing it, during which it will NACK everything (condition 2).

It does not prove that exactly one device answered. This is the one that surprises people. The wired-AND of Chapter 2.5 makes several devices pulling SDA low indistinguishable from one. Chapter 6.2 relies on that deliberately — several devices acknowledge a 10-bit prefix — and Chapter 6.4 shows what it costs when two devices share an address by accident.

It does not prove the right device answered. The acknowledge carries no identity. If two devices answer one address, the acknowledge is identical to a correct one — which is why Chapter 6.4 recommends reading an identifying register rather than trusting a successful transfer.

And it does not prove the transfer was legal. Chapter 5.5 §12 catalogued framing that is well formed in shape and illegal in timing. Every byte of such a transfer can be acknowledged.

Azvya Education Pvt. Ltd.VLSI Mentor
MATHEMATICAL DERIVATION — what one bit can carry
   information in the acknowledge slot           = 1 bit
   distinct meanings the specification assigns   = 5 (the NACK conditions)
   identity of the responder                     = not carried
   count of responders                           = not carried
   integrity of the data                         = not carried
   eventual effect of the byte                   = not carried

   An acknowledge is a LIVENESS signal, not a delivery receipt: it says something
   was listening at that instant. Every other property has to come from somewhere
   else -- an identifying register read, a read-back of what was written, a status
   bit, or a device-level protocol layered on top.

5. The Acknowledge Slot in Three Languages

Small, and every line of it is a decision from §1 to §3.

Azvya Education Pvt. Ltd.VLSI Mentor
i2c_ack_slot.sv — SYNTHESIZABLE RTL. Drives the slot only when it owns it, and samples the answer in every case.
   // The ninth clock pulse of a byte. ACK is SDA pulled LOW; NACK is SDA left HIGH.
   // This block drives the slot when this device owns it, and samples the resolved
   // level in every case -- because a transmitter must read the answer it was given.
   module i2c_ack_slot (
       input  logic clk,
       input  logic rst_n,
       input  logic scl_in,             // observed bus level
       input  logic sda_in,             // observed bus level
       input  logic ack_slot,           // from the byte shifter: the ninth clock
       input  logic we_acknowledge,     // 1 = this device owns the slot for this byte
       input  logic send_ack,           // 1 = acknowledge (pull LOW); 0 = NACK (release)
       output logic sda_drive_low,      // DRIVE INTENT for the ninth slot only
       output logic ack_bit,            // the raw level sampled in the ninth slot
       output logic ack_received,       // 1 = ACK, because the bit was LOW
       output logic nack_received,      // 1 = NACK, because the bit was HIGH
       output logic ack_valid           // pulse: the ninth bit has been sampled
   );
       logic scl_q;
       logic scl_rise, scl_fall;
       logic slot_q;

       assign scl_rise = !scl_q &&  scl_in;
       assign scl_fall =  scl_q && !scl_in;

       // ACK is the LOW level. Naming both directions explicitly is not redundancy:
       // "the acknowledge bit was 0" and "the byte was acknowledged" are the same
       // fact stated with opposite polarity, and conflating them is the classic bug.
       //
       // These are LEVELS describing the MOST RECENT acknowledge slot, not pulses.
       // A sequencer asks "was the last byte acknowledged?" several cycles after the
       // slot ended, so a one-cycle pulse would be unusable to it; `ack_valid` is the
       // pulse that says a new answer has landed. Out of reset, before any slot has
       // happened, ack_bit is 1 and so the reported state is NACK -- the safe
       // direction, because assuming an acknowledge nobody gave is how a transmitter
       // walks off the end of a transfer.
       assign ack_received  = !ack_bit;
       assign nack_received =  ack_bit;

       always_ff @(posedge clk) begin
           if (!rst_n) begin
               scl_q         <= 1'b1;   // idle bus: released, therefore high
               slot_q        <= 1'b0;
               sda_drive_low <= 1'b0;   // RELEASE on reset
               ack_bit       <= 1'b1;   // an unanswered slot reads as a NACK
               ack_valid     <= 1'b0;
           end else begin
               ack_valid <= 1'b0;
               scl_q     <= scl_in;
               slot_q    <= ack_slot;

               if (!ack_slot) begin
                   // Outside the ninth clock this block never touches the bus.
                   sda_drive_low <= 1'b0;
               end else begin
                   // Entering the slot, or already in it with SCL low: this is the only
                   // legal moment to establish the level, because SDA may not move
                   // while SCL is high.
                   if ((!slot_q || scl_fall) && !scl_in)
                       sda_drive_low <= we_acknowledge && send_ack;

                   if (scl_rise) begin
                       // The receiver's answer is read in the HIGH period of the ninth
                       // pulse -- the same data-valid window as any other bit.
                       ack_bit   <= sda_in;
                       ack_valid <= 1'b1;
                   end
               end
           end
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_ack_slot_tb.sv — SELF-CHECKING TESTBENCH, SIMULATION ONLY. Both polarities, both owners, and an unanswered slot.
   module i2c_ack_slot_tb;
       logic clk = 1'b0, rst_n, scl_in;
       logic ack_slot, we_acknowledge, send_ack;
       logic sda_drive_low, ack_bit, ack_received, nack_received, ack_valid;
       int errors = 0;

       // Wired-AND of the DUT's driver and the testbench's far end, plus a pull-up.
       logic far_drive_low = 1'b0;
       wire  sda_bus = ~(sda_drive_low | far_drive_low);

       i2c_ack_slot dut (.clk(clk), .rst_n(rst_n), .scl_in(scl_in), .sda_in(sda_bus),
           .ack_slot(ack_slot), .we_acknowledge(we_acknowledge), .send_ack(send_ack),
           .sda_drive_low(sda_drive_low), .ack_bit(ack_bit), .ack_received(ack_received),
           .nack_received(nack_received), .ack_valid(ack_valid));

       always #5 clk = ~clk;
       initial begin #40000; $display("FAIL: watchdog expired"); $finish; end

       // Continuous data-valid monitor: the acknowledge is a bit like any other and
       // must not move while SCL is high.
       logic scl_q2, sda_q2;
       int   dv_violations = 0;
       always @(posedge clk) if (rst_n) begin
           if (scl_q2 && scl_in && (sda_bus !== sda_q2)) dv_violations++;
           scl_q2 <= scl_in; sda_q2 <= sda_bus;
       end

       int n_valid = 0;
       always @(posedge clk) if (rst_n && ack_valid) n_valid++;

       logic captured_bit;
       // Run one acknowledge slot. `far_acks` is what the OTHER end does.
       task automatic run_ack_slot(input logic mine, input logic ack, input logic far_acks);
           we_acknowledge = mine; send_ack = ack;
           scl_in = 1'b0;                  repeat (1) @(negedge clk);
           ack_slot = 1'b1;                repeat (2) @(negedge clk);
           far_drive_low = far_acks;       repeat (1) @(negedge clk);
           scl_in = 1'b1;                  repeat (1) @(negedge clk);
           captured_bit = sda_bus;                                   // what a scope sees
                                           repeat (1) @(negedge clk);
           // Release the far end AT THE SAME MOMENT SCL falls. This is legal -- SDA may
           // move once SCL is low -- and it is what distinguishes a design that sampled
           // the answer on the RISING edge from one that sampled it on the falling edge:
           // the two now see different values.
           scl_in = 1'b0; far_drive_low = 1'b0;   repeat (1) @(negedge clk);
           ack_slot = 1'b0;                       repeat (2) @(negedge clk);
       endtask

       initial begin
           rst_n = 1'b0; scl_in = 1'b1; ack_slot = 1'b0;
           we_acknowledge = 1'b0; send_ack = 1'b0;
           scl_q2 = 1'b1; sda_q2 = 1'b1;
           repeat (3) @(negedge clk);
           if (sda_drive_low !== 1'b0) begin $display("FAIL: reset did not release SDA"); errors++; end
           // An unanswered slot must read as a NACK, not as an ACK: the safe default.
           if (ack_bit !== 1'b1) begin $display("FAIL: ack_bit does not default to NACK"); errors++; end
           rst_n = 1'b1; @(negedge clk);

           // 1 -- WE acknowledge. The bus must be LOW in the slot, and the block must
           //      read back the level it is itself producing.
           run_ack_slot(1'b1, 1'b1, 1'b0);
           if (captured_bit !== 1'b0) begin $display("FAIL: our ACK did not pull the bus low"); errors++; end
           if (ack_received !== 1'b1) begin $display("FAIL: ACK not reported as received"); errors++; end
           if (nack_received !== 1'b0) begin $display("FAIL: NACK reported alongside an ACK"); errors++; end

           // 2 -- WE NACK. A NACK is not a signal: it is the ABSENCE of one, so the
           //      block must leave the line alone and the pull-up produces the HIGH.
           run_ack_slot(1'b1, 1'b0, 1'b0);
           if (captured_bit !== 1'b1) begin $display("FAIL: our NACK did not leave the bus high"); errors++; end
           if (nack_received !== 1'b1) begin $display("FAIL: NACK not reported"); errors++; end
           if (ack_received !== 1'b0) begin $display("FAIL: ACK reported alongside a NACK"); errors++; end

           // 3 -- the slot is NOT ours and the far end acknowledges. We must not drive,
           //      and must still read the answer -- a transmitter has to learn it.
           run_ack_slot(1'b0, 1'b1, 1'b1);
           if (ack_received !== 1'b1) begin
               $display("FAIL: did not read the far end's ACK"); errors++; end

           // 4 -- the slot is not ours and NOBODY acknowledges. The pull-up makes it a
           //      NACK, which is exactly specification condition 1: no receiver present.
           run_ack_slot(1'b0, 1'b1, 1'b0);
           if (nack_received !== 1'b1) begin
               $display("FAIL: an unanswered slot must read as a NACK"); errors++; end

           // 5 -- send_ack must be ignored when the slot is not ours. A device that
           //      acknowledged a byte it did not receive would corrupt the handshake.
           run_ack_slot(1'b0, 1'b1, 1'b0);
           if (captured_bit !== 1'b1) begin
               $display("FAIL: drove an acknowledge slot it does not own"); errors++; end

           // 6 -- exactly one ack_valid per slot: five slots, five pulses.
           if (n_valid != 5) begin
               $display("FAIL: expected 5 ack_valid pulses, saw %0d", n_valid); errors++; end

           // 7 -- outside the slot the block never drives, whatever the inputs say.
           we_acknowledge = 1'b1; send_ack = 1'b1; ack_slot = 1'b0;
           repeat (4) @(negedge clk);
           if (sda_drive_low !== 1'b0) begin
               $display("FAIL: drove SDA outside the acknowledge slot"); errors++; end

           if (dv_violations != 0) begin
               $display("FAIL: %0d data-valid violations in the acknowledge slot", dv_violations); errors++; end

           if (errors == 0)
               $display("PASS: ACK is a pulled-low slot, NACK is an absent one, %0d slots, zero data-valid violations",
                        n_valid);
           else $display("FAIL: %0d error(s)", errors);
           $finish;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_ack_slot.v — SYNTHESIZABLE RTL. The same slot handler in Verilog-2005.
   // The ninth clock pulse of a byte. ACK is SDA pulled LOW; NACK is SDA left HIGH.
   // This block drives the slot when this device owns it, and samples the resolved
   // level in every case -- because a transmitter must read the answer it was given.
   module i2c_ack_slot (
       input  wire clk,
       input  wire rst_n,
       input  wire scl_in,             // observed bus level
       input  wire sda_in,             // observed bus level
       input  wire ack_slot,           // from the byte shifter: the ninth clock
       input  wire we_acknowledge,     // 1 = this device owns the slot for this byte
       input  wire send_ack,           // 1 = acknowledge (pull LOW); 0 = NACK (release)
       output reg  sda_drive_low,      // DRIVE INTENT for the ninth slot only
       output reg  ack_bit,            // the raw level sampled in the ninth slot
       output wire ack_received,       // 1 = ACK, because the bit was LOW
       output wire nack_received,      // 1 = NACK, because the bit was HIGH
       output reg  ack_valid           // pulse: the ninth bit has been sampled
   );
       reg  scl_q, slot_q;
       wire scl_rise = ~scl_q &  scl_in;
       wire scl_fall =  scl_q & ~scl_in;

       // LEVELS describing the MOST RECENT slot, not pulses: a sequencer asks whether
       // the last byte was acknowledged several cycles later. Out of reset the state is
       // NACK, which is the safe direction.
       assign ack_received  = ~ack_bit;
       assign nack_received =  ack_bit;

       always @(posedge clk) begin
           if (!rst_n) begin
               scl_q         <= 1'b1;   // idle bus: released, therefore high
               slot_q        <= 1'b0;
               sda_drive_low <= 1'b0;   // RELEASE on reset
               ack_bit       <= 1'b1;   // an unanswered slot reads as a NACK
               ack_valid     <= 1'b0;
           end else begin
               ack_valid <= 1'b0;
               scl_q     <= scl_in;
               slot_q    <= ack_slot;

               if (!ack_slot) begin
                   sda_drive_low <= 1'b0;
               end else begin
                   // Establish the level only while SCL is low: SDA may not move
                   // while SCL is high.
                   if ((!slot_q || scl_fall) && !scl_in)
                       sda_drive_low <= we_acknowledge & send_ack;

                   if (scl_rise) begin
                       // The answer is read in the HIGH period of the ninth pulse.
                       ack_bit   <= sda_in;
                       ack_valid <= 1'b1;
                   end
               end
           end
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_ack_slot_tb.v — SELF-CHECKING TESTBENCH, SIMULATION ONLY. The same cases in Verilog idiom.
   module i2c_ack_slot_tb;
       reg clk, rst_n, scl_in;
       reg ack_slot, we_acknowledge, send_ack;
       wire sda_drive_low, ack_bit, ack_received, nack_received, ack_valid;
       integer errors;

       // Wired-AND of the DUT's driver and the testbench's far end, plus a pull-up.
       reg  far_drive_low;
       wire sda_bus = ~(sda_drive_low | far_drive_low);

       i2c_ack_slot dut (.clk(clk), .rst_n(rst_n), .scl_in(scl_in), .sda_in(sda_bus),
           .ack_slot(ack_slot), .we_acknowledge(we_acknowledge), .send_ack(send_ack),
           .sda_drive_low(sda_drive_low), .ack_bit(ack_bit), .ack_received(ack_received),
           .nack_received(nack_received), .ack_valid(ack_valid));

       initial clk = 1'b0;
       always #5 clk = ~clk;
       initial begin #40000; $display("FAIL: watchdog expired"); $finish; end

       // Continuous data-valid monitor: the acknowledge is a bit like any other and
       // must not move while SCL is high.
       reg scl_q2, sda_q2;
       integer dv_violations;
       always @(posedge clk) if (rst_n) begin
           if (scl_q2 && scl_in && (sda_bus !== sda_q2)) dv_violations = dv_violations + 1;
           scl_q2 <= scl_in; sda_q2 <= sda_bus;
       end

       integer n_valid;
       always @(posedge clk) if (rst_n && ack_valid) n_valid = n_valid + 1;

       reg captured_bit;
       // Run one acknowledge slot. far_acks is what the OTHER end does.
       task run_ack_slot; input mine; input ack; input far_acks; begin
           we_acknowledge = mine; send_ack = ack;
           scl_in = 1'b0;                  repeat (1) @(negedge clk);
           ack_slot = 1'b1;                repeat (2) @(negedge clk);
           far_drive_low = far_acks;       repeat (1) @(negedge clk);
           scl_in = 1'b1;                  repeat (1) @(negedge clk);
           captured_bit = sda_bus;                                   // what a scope sees
                                           repeat (1) @(negedge clk);
           // Release the far end AT THE SAME MOMENT SCL falls -- legal, and it is what
           // distinguishes a rising-edge sampler from a falling-edge one.
           scl_in = 1'b0; far_drive_low = 1'b0;   repeat (1) @(negedge clk);
           ack_slot = 1'b0;                       repeat (2) @(negedge clk);
       end endtask

       initial begin
           errors = 0; dv_violations = 0; n_valid = 0; far_drive_low = 1'b0;
           rst_n = 1'b0; scl_in = 1'b1; ack_slot = 1'b0;
           we_acknowledge = 1'b0; send_ack = 1'b0;
           scl_q2 = 1'b1; sda_q2 = 1'b1;
           repeat (3) @(negedge clk);
           if (sda_drive_low !== 1'b0) begin $display("FAIL: reset did not release SDA"); errors = errors + 1; end
           // An unanswered slot must read as a NACK, not as an ACK: the safe default.
           if (ack_bit !== 1'b1) begin $display("FAIL: ack_bit does not default to NACK"); errors = errors + 1; end
           rst_n = 1'b1; @(negedge clk);

           // 1 -- WE acknowledge. The bus must be LOW in the slot, and the block must
           //      read back the level it is itself producing.
           run_ack_slot(1'b1, 1'b1, 1'b0);
           if (captured_bit !== 1'b0) begin $display("FAIL: our ACK did not pull the bus low"); errors = errors + 1; end
           if (ack_received !== 1'b1) begin $display("FAIL: ACK not reported as received"); errors = errors + 1; end
           if (nack_received !== 1'b0) begin $display("FAIL: NACK reported alongside an ACK"); errors = errors + 1; end

           // 2 -- WE NACK. A NACK is not a signal: it is the ABSENCE of one, so the
           //      block must leave the line alone and the pull-up produces the HIGH.
           run_ack_slot(1'b1, 1'b0, 1'b0);
           if (captured_bit !== 1'b1) begin $display("FAIL: our NACK did not leave the bus high"); errors = errors + 1; end
           if (nack_received !== 1'b1) begin $display("FAIL: NACK not reported"); errors = errors + 1; end
           if (ack_received !== 1'b0) begin $display("FAIL: ACK reported alongside a NACK"); errors = errors + 1; end

           // 3 -- the slot is NOT ours and the far end acknowledges. We must not drive,
           //      and must still read the answer -- a transmitter has to learn it.
           run_ack_slot(1'b0, 1'b1, 1'b1);
           if (ack_received !== 1'b1) begin
               $display("FAIL: did not read the far end's ACK"); errors = errors + 1; end

           // 4 -- the slot is not ours and NOBODY acknowledges. The pull-up makes it a
           //      NACK, which is exactly specification condition 1: no receiver present.
           run_ack_slot(1'b0, 1'b1, 1'b0);
           if (nack_received !== 1'b1) begin
               $display("FAIL: an unanswered slot must read as a NACK"); errors = errors + 1; end

           // 5 -- send_ack must be ignored when the slot is not ours. A device that
           //      acknowledged a byte it did not receive would corrupt the handshake.
           run_ack_slot(1'b0, 1'b1, 1'b0);
           if (captured_bit !== 1'b1) begin
               $display("FAIL: drove an acknowledge slot it does not own"); errors = errors + 1; end

           // 6 -- exactly one ack_valid per slot: five slots, five pulses.
           if (n_valid != 5) begin
               $display("FAIL: expected 5 ack_valid pulses, saw %0d", n_valid); errors = errors + 1; end

           // 7 -- outside the slot the block never drives, whatever the inputs say.
           we_acknowledge = 1'b1; send_ack = 1'b1; ack_slot = 1'b0;
           repeat (4) @(negedge clk);
           if (sda_drive_low !== 1'b0) begin
               $display("FAIL: drove SDA outside the acknowledge slot"); errors = errors + 1; end

           if (dv_violations != 0) begin
               $display("FAIL: %0d data-valid violations in the acknowledge slot", dv_violations); errors = errors + 1; end

           if (errors == 0)
               $display("PASS: ACK is a pulled-low slot, NACK is an absent one, %0d slots, zero data-valid violations",
                        n_valid);
           else $display("FAIL: %0d error(s)", errors);
           $finish;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_ack_slot.vhd — SYNTHESIZABLE RTL. The same slot handler in VHDL.
   library ieee;
   use ieee.std_logic_1164.all;

   -- The ninth clock pulse of a byte. ACK is SDA pulled LOW; NACK is SDA left HIGH.
   -- This block drives the slot when this device owns it, and samples the resolved
   -- level in every case -- because a transmitter must read the answer it was given.
   entity i2c_ack_slot is
       port (
           clk            : in  std_logic;
           rst_n          : in  std_logic;
           scl_in         : in  std_logic;   -- observed bus level
           sda_in         : in  std_logic;   -- observed bus level
           ack_slot       : in  std_logic;   -- from the byte shifter: the ninth clock
           we_acknowledge : in  std_logic;   -- 1 = this device owns the slot
           send_ack       : in  std_logic;   -- 1 = ACK (pull LOW); 0 = NACK (release)
           sda_drive_low  : out std_logic;   -- DRIVE INTENT, ninth slot only
           ack_bit        : out std_logic;   -- the raw level sampled in the slot
           ack_received   : out std_logic;   -- 1 = ACK, because the bit was LOW
           nack_received  : out std_logic;   -- 1 = NACK, because the bit was HIGH
           ack_valid      : out std_logic    -- pulse: the ninth bit was sampled
       );
   end entity;

   architecture rtl of i2c_ack_slot is
       signal scl_q  : std_logic := '1';    -- idle bus: released, therefore high
       signal slot_q : std_logic := '0';
       signal abit   : std_logic := '1';    -- an unanswered slot reads as a NACK
       signal scl_rise, scl_fall : std_logic;
   begin
       scl_rise <= (not scl_q) and scl_in;
       scl_fall <= scl_q and (not scl_in);

       ack_bit <= abit;

       -- LEVELS describing the MOST RECENT slot, not pulses: a sequencer asks whether
       -- the last byte was acknowledged several cycles later. Out of reset the reported
       -- state is NACK, which is the safe direction.
       ack_received  <= not abit;
       nack_received <= abit;

       process (clk)
       begin
           if rising_edge(clk) then
               if rst_n = '0' then
                   scl_q         <= '1';
                   slot_q        <= '0';
                   sda_drive_low <= '0';    -- RELEASE on reset
                   abit          <= '1';
                   ack_valid     <= '0';
               else
                   ack_valid <= '0';
                   scl_q     <= scl_in;
                   slot_q    <= ack_slot;

                   if ack_slot = '0' then
                       sda_drive_low <= '0';
                   else
                       -- Establish the level only while SCL is low.
                       if (slot_q = '0' or scl_fall = '1') and scl_in = '0' then
                           sda_drive_low <= we_acknowledge and send_ack;
                       end if;

                       if scl_rise = '1' then
                           -- The answer is read in the HIGH period of the ninth pulse.
                           abit      <= sda_in;
                           ack_valid <= '1';
                       end if;
                   end if;
               end if;
           end if;
       end process;
   end architecture;
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_ack_slot_tb.vhd — SELF-CHECKING TESTBENCH, SIMULATION ONLY. The same cases with assert report severity.
   library ieee;
   use ieee.std_logic_1164.all;

   entity i2c_ack_slot_tb is
   end entity;

   architecture sim of i2c_ack_slot_tb is
       signal clk            : std_logic := '0';
       signal rst_n          : std_logic := '0';
       signal scl_in         : std_logic := '1';
       signal ack_slot       : std_logic := '0';
       signal we_acknowledge : std_logic := '0';
       signal send_ack       : std_logic := '0';
       signal sda_drive_low, ack_bit, ack_received, nack_received, ack_valid : std_logic;

       signal far_drive_low : std_logic := '0';
       signal sda_bus       : std_logic;

       signal n_valid, dv_violations : natural := 0;
       signal test_done : std_logic := '0';
   begin
       sda_bus <= not (sda_drive_low or far_drive_low);

       dut : entity work.i2c_ack_slot
           port map (clk => clk, rst_n => rst_n, scl_in => scl_in, sda_in => sda_bus,
                     ack_slot => ack_slot, we_acknowledge => we_acknowledge, send_ack => send_ack,
                     sda_drive_low => sda_drive_low, ack_bit => ack_bit,
                     ack_received => ack_received, nack_received => nack_received,
                     ack_valid => ack_valid);

       clk <= not clk after 5 ns;

       watchdog : process
       begin
           wait for 40 us;
           if test_done = '0' then
               report "watchdog expired -- the design never reached the expected state"
                   severity failure;
           end if;
           wait;
       end process;

       monitor : process (clk)
           variable scl_q2 : std_logic := '1';
           variable sda_q2 : std_logic := '1';
       begin
           if rising_edge(clk) then
               if rst_n = '1' then
                   if scl_q2 = '1' and scl_in = '1' and sda_bus /= sda_q2 then
                       dv_violations <= dv_violations + 1;
                   end if;
                   scl_q2 := scl_in; sda_q2 := sda_bus;
                   if ack_valid = '1' then n_valid <= n_valid + 1; end if;
               end if;
           end if;
       end process;

       stim : process
           variable errs         : natural := 0;
           variable captured_bit : std_logic;

           procedure waitn (n : in positive) is
           begin
               for i in 1 to n loop wait until falling_edge(clk); end loop;
           end procedure;

           -- Run one acknowledge slot. far_acks is what the OTHER end does.
           procedure run_ack_slot (mine, ack, far_acks : in std_logic) is
           begin
               we_acknowledge <= mine; send_ack <= ack;
               scl_in <= '0';                 waitn(1);
               ack_slot <= '1';               waitn(2);
               far_drive_low <= far_acks;     waitn(1);
               scl_in <= '1';                 waitn(1);
               captured_bit := sda_bus;                       -- what a scope sees
                                              waitn(1);
               -- Release the far end AT THE SAME MOMENT SCL falls -- legal, and it is
               -- what distinguishes a rising-edge sampler from a falling-edge one.
               scl_in <= '0'; far_drive_low <= '0';  waitn(1);
               ack_slot <= '0';                      waitn(2);
           end procedure;
       begin
           waitn(3);
           if sda_drive_low /= '0' then
               report "reset did not release SDA" severity error; errs := errs + 1; end if;
           if ack_bit /= '1' then
               report "ack_bit does not default to NACK" severity error; errs := errs + 1; end if;
           rst_n <= '1'; waitn(1);

           -- 1: WE acknowledge -- the bus must be LOW and we read back our own level.
           run_ack_slot('1', '1', '0');
           if captured_bit /= '0' then
               report "our ACK did not pull the bus low" severity error; errs := errs + 1; end if;
           if ack_received /= '1' then
               report "ACK not reported as received" severity error; errs := errs + 1; end if;
           if nack_received /= '0' then
               report "NACK reported alongside an ACK" severity error; errs := errs + 1; end if;

           -- 2: WE NACK -- a NACK is the ABSENCE of a signal; the pull-up makes the HIGH.
           run_ack_slot('1', '0', '0');
           if captured_bit /= '1' then
               report "our NACK did not leave the bus high" severity error; errs := errs + 1; end if;
           if nack_received /= '1' then
               report "NACK not reported" severity error; errs := errs + 1; end if;
           if ack_received /= '0' then
               report "ACK reported alongside a NACK" severity error; errs := errs + 1; end if;

           -- 3: not our slot, far end acknowledges -- we must not drive, and must read it.
           run_ack_slot('0', '1', '1');
           if ack_received /= '1' then
               report "did not read the far end's ACK" severity error; errs := errs + 1; end if;

           -- 4: not our slot and NOBODY acknowledges -- specification condition 1.
           run_ack_slot('0', '1', '0');
           if nack_received /= '1' then
               report "an unanswered slot must read as a NACK" severity error; errs := errs + 1; end if;

           -- 5: send_ack must be ignored when the slot is not ours.
           run_ack_slot('0', '1', '0');
           if captured_bit /= '1' then
               report "drove an acknowledge slot it does not own" severity error; errs := errs + 1; end if;

           -- 6: exactly one ack_valid per slot.
           if n_valid /= 5 then
               report "expected 5 ack_valid pulses" severity error; errs := errs + 1; end if;

           -- 7: outside the slot the block never drives, whatever the inputs say.
           we_acknowledge <= '1'; send_ack <= '1'; ack_slot <= '0';
           waitn(4);
           if sda_drive_low /= '0' then
               report "drove SDA outside the acknowledge slot" severity error; errs := errs + 1; end if;

           if dv_violations /= 0 then
               report "data-valid violations in the acknowledge slot" severity error;
               errs := errs + 1; end if;

           if errs = 0 then
               report "i2c_ack_slot self-check complete: ACK is a pulled-low slot, NACK is an "
                    & "absent one, " & integer'image(n_valid)
                    & " slots, zero data-valid violations" severity note;
           else
               report "i2c_ack_slot self-check FAILED" severity error;
           end if;
           test_done <= '1';
           wait;
       end process;
   end architecture;

5a. Three Decisions Worth Defending

ack_received and nack_received are latched levels, not pulses. A sequencer asks "was the last byte acknowledged?" several cycles after the slot ended — Chapter 7.4's sequencer does exactly that — so a one-cycle pulse would be unusable to it. ack_valid is the pulse that says a new answer has landed; the decode is a level describing the most recent one.

Out of reset the reported state is NACK. ack_bit resets to 1, so before any slot has happened the block reports not-acknowledged. That is the safe direction: assuming an acknowledge nobody gave is how a transmitter walks off the end of a transfer, and §1 established that "no" is the bus's natural default anyway.

Both polarities are named explicitly. ack_bit is the raw wire level; ack_received is the interpretation. Keeping both is not redundancy — "the acknowledge bit was 0" and "the byte was acknowledged" are the same fact with opposite polarity, and every inversion bug in this area comes from a design that only kept one of them and then had to remember which way round it was.

5b. Verified Execution and Cross-Language Parity

languagesimulatorresultcompletes at
SystemVerilogIcarus Verilog, -g2012PASS530 ns
Verilog-2005Icarus Verilog, -g2005PASS530 ns
VHDLnvc 1.23.0PASS530 ns
SystemVerilogVerilog-2005VHDL
slot trackinglogic slot_qreg slot_qsignal slot_q
polarity decodeassign on !ack_bitassign on ~ack_bitnot abit
drive conditionwe_acknowledge && send_ackwe_acknowledge & send_ackwe_acknowledge and send_ack
internal latched bitoutput register read directlyoutput register read directlyinternal abit, driven to the port

The VHDL version routes ack_bit through an internal signal because the architecture reads that value to compute the two decodes, and VHDL's port modes make reading an out port awkward. The Verilog versions can read an output register freely. The hardware is one flip-flop either way.

i2c_ack_slot — establishing and sampling the answer

10 cycles
Ten internal clock cycles. The ack slot input rises while the observed SCL input is low, and the SDA drive-low intent is asserted at that point so the observed SDA bus goes low. SCL then goes high and the ack bit is sampled, with the ack valid pulse and the ack received level both asserting.held stable through SCL highheld stable through SCL highslot opens, SCL lowslot opens, SCL lowpull low: this is the ACKpull low: this is the ACKsampled in the high periodsampled in the high periodclkscl_inack_slotsda_drive_lowsda_bus1100000011ack_validack_receivedt0t1t2t3t4t5t6t7t8t9
Figure 3 — this device acknowledging, from the simulation, on the internal clock. The slot opens while SCL is low, which is when the drive intent is established; the level is then held stable through SCL's high period and sampled there. Note that the block reads back the level it is itself producing — a transmitter has to learn the answer, and a device that drives the slot is also entitled to confirm it took effect. SIMULATION-DERIVED figure.

6. What the Testbench Proves

Five slots, chosen so that every combination of who owns the slot and what the answer is appears:

stepwho owns itanswerrequired result
1usACKthe bus goes low, and we read back our own level
2usNACKthe bus stays high — we assert nothing
3the far endACKwe do not drive, and we still read the answer
4the far endnoneNACK — condition 1, with no device participating
5the far end(we are told to ACK)we ignore send_ack — the slot is not ours

Plus two invariants: exactly one ack_valid per slot, and zero SDA edges while SCL is high across the whole simulation.

Step 2 is more interesting than it looks. "We NACK" means the block does nothing at all. Verifying that a device correctly produces a NACK is verifying that it correctly stays out of the way, and the only observable is that the pull-up wins. A design that drove a one instead of releasing would pass a naive check of the bus level and be electrically wrong on an open-drain bus.

Step 5 is the safety check. A device that acknowledged a byte it was not the receiver of would corrupt the handshake — the transmitter would believe the wrong device took its byte. send_ack has to be gated on ownership, and Chapter 7.3 is entirely about computing that ownership correctly.

The far end releases as SCL falls, deliberately. That makes the value present at the falling edge differ from the value during the high period, which is what distinguishes a design that samples on the rising edge from one that samples on the falling edge. §7's second mutation is caught by exactly this and by nothing else.

7. Mutation Testing

Six faults injected into the verified RTL. All six caught.

mutationwhat it breaksresult
acknowledge by releasing instead of pulling lowthe polarity of the whole mechanismFAIL — the ACK did not pull the bus low
sample the answer on the falling edgereads a line permitted to be movingFAIL — caught by the release-as-SCL-falls stimulus
drive a slot this device does not ownforges an acknowledge for another device's byteFAIL — an unanswered slot read as ACK
drive outside the slotcorrupts data bitsFAIL — drove SDA outside the slot
ACK and NACK decodes swappedevery answer is invertedFAIL — ACK not reported
reset defaults to ACKan unstarted block claims a byte was acknowledgedFAIL — the reset check

Two are worth a note.

The falling-edge mutation initially survived. The original testbench held the far end's level until after SCL had gone low, so the falling-edge sample saw the same value as the rising-edge one — the two designs were indistinguishable under that stimulus. Releasing the far end as SCL falls is legal (SDA may move once SCL is low) and makes the two differ. This is the same shape as Chapter 7.1's survivor: a timing fault is only observable if the stimulus changes something between the two candidate sampling instants.

The reset-default mutation is the cheapest real bug in the module. A block that reports "acknowledged" before it has seen a single acknowledge hands a false positive to whatever consumes it, at the worst possible moment — the first byte after reset. §5a's reasoning is why the default is NACK, and the mutation confirms a test actually pins it down.

8. What the Master Does Next

The specification gives the master exactly two options after a NACK:

The master can then generate either a STOP condition to abort the transfer, or a repeated START condition to start a new transfer.

There is no third option, and in particular there is no "carry on and hope". A NACK means the receiver is not accepting more bytes, so continuing to clock them out is transmitting into a device that has said it is not listening.

The two options map onto the two situations cleanly:

after a NACK the master wants to...issuewhy
give up on this transfer entirelySTOPreleases the bus; costs the bus-free interval of Chapter 5.3
try something else without losing the busrepeated STARTkeeps ownership, per Chapter 5.4

The repeated-START option is the interesting one for a retry. A master that NACKs on the address because the device was busy (condition 2) can retry immediately with an Sr, without releasing the bus to a competing controller — which on a multi-controller segment is the difference between a retry and a lost turn.

9. Verification Connection — Checking the Answer, and Checking the Question

An environment needs two different kinds of check around the acknowledge, and conflating them produces a monitor that cannot explain a failure.

Azvya Education Pvt. Ltd.VLSI Mentor
UVM CONCEPT — VERIFICATION ONLY. Two properties and one coverage model.
   // PROPERTY 1 -- protocol legality. The transmitter must have released. This is a
   // statement about the DUT's obligation and holds for every byte, forever.
   property transmitter_released_for_the_answer;
       @(posedge clk) disable iff (!rst_n)
       (ack_slot && we_are_transmitting) |-> !sda_drive_low;
   endproperty

   // PROPERTY 2 -- the acknowledge is a data bit and obeys the data-valid rule. A
   // receiver that decides late emits FRAMING, not a late acknowledge.
   property ack_stable_through_scl_high;
       @(posedge clk) disable iff (!rst_n)
       (ack_slot && $past(scl_in) && scl_in) |-> $stable(sda_in);
   endproperty

   // COVERAGE -- the five NACK conditions are five DIFFERENT situations, and a suite
   // that only ever produces condition 1 has not tested acknowledgement at all.
   covergroup ack_reason_cg @(posedge clk);
       option.per_instance = 1;
       cp : coverpoint nack_reason iff (ack_valid && nack_seen) {
           bins absent      = { NACK_NO_DEVICE };      // condition 1
           bins busy        = { NACK_BUSY };           // condition 2
           bins not_understood = { NACK_BAD_CONTENT }; // condition 3
           bins full        = { NACK_FULL };           // condition 4
           bins end_of_read = { NACK_MASTER_DONE };    // condition 5 -- NOT an error
       }
       // And the one that matters most in practice: an ACK on every byte of a long
       // transfer is the common case, so cover the LENGTH at which a NACK appeared.
       cp_pos : coverpoint byte_index_of_nack iff (nack_seen) {
           bins on_address = { 0 };
           bins first_data = { 1 };
           bins later_data = { [2:255] };
       }
   endgroup

Three observations.

The two properties check different things and both are needed. The first says the transmitter got out of the way; the second says whoever answered did so legally. A design can satisfy one and violate the other, and a single combined check cannot say which happened.

Condition 5 belongs in the coverage model, not in an error list. A master-receiver's final NACK is correct behaviour. Modelling it as a covered reason rather than as a failure is what keeps the error report meaningful — and it is the single most common mistake in I²C verification environments.

Covering the position of the NACK is worth more than covering that one occurred. A NACK on the address byte and a NACK on the twentieth data byte exercise entirely different paths in both the DUT and the driver. The cp_pos coverpoint asks the question a debug engineer actually asks first.

10. FPGA and ASIC Implications

The slave's decision latency is a real constraint. Between the eighth rising edge and the ninth falling edge, a slave must decide whether to acknowledge. At 400 kHz that is on the order of a microsecond; with an input filter and a synchroniser in the path it is less. A device that cannot decide in time must stretch the clock rather than answer late, because answering late means emitting framing.

The acknowledge output is the same open-drain cell as everything else. There is no separate acknowledge pin and no special driver — it is the same tristate enable, asserted for one clock pulse. On an FPGA, the mistake to avoid is the one from Chapter 5.1 §9: driving the buffer's data input low with the enable already asserted is correct; driving the data input high to "send a NACK" is not, because that drives a one onto an open-drain bus.

Sampling the answer needs the same synchronised input as the data. A transmitter reads the ninth slot through exactly the path it reads data bits through. There is no reason for a separate path and a good reason against one — two paths can disagree about what the bus did.

On an ASIC, expose the last acknowledge to software. A status bit saying whether the most recent byte was acknowledged, and ideally which byte index NACKed, turns §3's five-way ambiguity into something a driver can act on. Chapter 3.4 established that such status bits want write-one-to-clear semantics, because a driver must be able to distinguish one NACK from three.

11. Debugging — The EEPROM That Lost Half Its Writes

A configuration store that acknowledged every byte and remembered some of them

Pitfall — treating an acknowledge as proof that a write took effect
Buggy Code
// A driver writes a configuration block to an EEPROM, byte by byte, and checks
// the acknowledge after each one:
//
//     for (i = 0; i < len; i++) {
//         i2c_start();
//         i2c_write_byte(EEPROM_ADDR7 << 1);       // address + W
//         i2c_write_byte(reg_base + i);            // register pointer
//         i2c_write_byte(data[i]);
//         if (!i2c_get_ack()) return -EIO;         // "the byte did not land"
//         i2c_stop();
//     }
//     return 0;                                    // "all bytes landed"
//
// Every acknowledge is checked. The error path exists and works. The loop returns
// success only if every single byte was acknowledged. By the standards of most
// driver code this is careful.
Symptom

Configuration is written, the driver reports success, and on the next power cycle some of the block has reverted to its previous contents. Not all of it -- a prefix, usually, and the amount that survives varies between boards and between runs on the same board.

Reading the block back IMMEDIATELY after writing it returns the correct data, every time. So the driver's own verification passes, and the problem only appears across a power cycle, which points everyone at the EEPROM's retention specification or at the supply.

Slowing the bus down makes it better. Adding delays between bytes makes it go away entirely -- which looks exactly like a timing or signal-integrity problem and consumed a week of scope time.

Root Cause

The acknowledge was doing its job perfectly. It was being asked the wrong question.

An EEPROM acknowledges a byte when it RECEIVES it. Committing that byte to the non-volatile cell is a separate, much slower operation -- typically milliseconds -- that begins after the STOP. During that internal write cycle the device is busy, and section 3's condition 2 says exactly what it will do about any new transfer: NACK it, because it "is unable to receive or transmit because it is performing some real-time function".

So the sequence was:

write byte 0 -> ACK -> STOP -> EEPROM begins its internal write cycle write byte 1 -> the address byte is NACKed, device busy -> driver returns -EIO? NO: get_ack() was checked only after the DATA byte, and the transfer never got that far

Whether byte 1 landed depended on whether the EEPROM had finished its internal cycle, which depended on bus speed and on the device's own timing. Faster bus -> the next write arrives sooner -> more bytes lost. That is why slowing down "fixed" it, and why adding delays fixed it completely: the delay was accidentally implementing the acknowledge-polling the driver should have been doing.

The immediate read-back succeeded because the EEPROM serves reads from the data it has RECEIVED, not only from committed cells -- so the driver verified its own writes against a buffer that had not yet been committed.

Section 4 is the general statement: an acknowledge proves a byte was received at that instant. It says nothing about whether the device will act on it, and nothing about when that action completes.

Fix
// Poll for the device to become ready again, which is what the specification's
// condition 2 is FOR -- the NACK is the device telling you it is busy:
//
//     for (i = 0; i < len; i++) {
//         write_one_byte(reg_base + i, data[i]);
//         // "acknowledge polling": address the device repeatedly until it answers.
//         // A NACK here is not an error, it is the expected in-progress signal.
//         deadline = now() + EEPROM_WRITE_TIMEOUT;
//         do {
//             i2c_start();
//             ok = i2c_write_byte(EEPROM_ADDR7 << 1);   // address only
//             i2c_stop();
//         } while (!ok && now() < deadline);
//         if (!ok) return -ETIMEDOUT;
//     }
//
// The lessons, in order of how far they generalise.
//
//   1. AN ACKNOWLEDGE IS A LIVENESS SIGNAL, NOT A RECEIPT. Section 4 lists what it
//      does not prove; "the device will act on this" is on that list. Any device
//      with an internal operation slower than the bus needs a completion check that
//      is NOT the acknowledge -- polling, a status register, or a busy pin.
//
//   2. A NACK IS NOT ALWAYS AN ERROR. Condition 2 is a device saying "not yet" and
//      condition 5 is a master saying "I am done". A driver that maps every NACK to
//      -EIO cannot implement acknowledge polling at all, and will log one spurious
//      error per read for the life of the product.
//
//   3. READ-BACK THROUGH THE SAME PATH PROVES LESS THAN IT APPEARS TO. Verifying a
//      write by reading it back immediately can be satisfied by an uncommitted
//      buffer. The verification that matters crosses the boundary you care about --
//      here, a power cycle.
//
//   4. "SLOWING IT DOWN FIXES IT" USUALLY MEANS A MISSING HANDSHAKE, NOT A TIMING
//      VIOLATION. A genuine timing violation gets worse with temperature and
//      loading; a missing wait-for-ready gets better with any delay at all. The two
//      are distinguishable by asking whether the fix is a delay or a CHECK.
//
// And the bench habit: when an acknowledge is involved, ask what question it
// answered. "Did a device pull SDA low in that slot" is the only question it can
// answer, and it is rarely the question the code wanted.

12. Common Misconceptions

"A NACK is a signal the device sends." A NACK is the absence of a signal — nobody pulls the line down and the pull-up leaves it high. That is why a bus with nothing attached NACKs correctly.

"An ACK is SDA high, because high means yes." An ACK is SDA low. The polarity is the opposite of the intuitive one, and it follows from the bus being open-drain: the only thing a device can actively do is pull low.

"A NACK means an error." Sometimes. Condition 2 means "busy, try again" and condition 5 means "the master is finished" — and condition 5 ends every single read on the bus. A driver mapping all NACKs to errors logs one per read forever.

"An ACK means the byte was delivered and accepted." It means some device pulled SDA low at that instant. It says nothing about correctness, understanding, eventual effect, how many devices answered, or which one did.

"An ACK confirms the write is stored." §11 is an entire failure resting on this. A device acknowledges receipt; a slow internal operation completes later, and the device will NACK during it.

"A receiver can decide late and pull SDA down during the high period." That produces an SDA edge while SCL is high, which is reserved framing — so it emits a START or STOP mid-transfer. A device that cannot decide in time must stretch the clock instead.

"The transmitter should drive a one in the ninth slot so the receiver can override it." Nothing on this bus drives a one, and there is nothing to override — the transmitter releases and the pull-up does the rest.

"The master can continue clocking after a NACK." The specification gives two options: STOP or repeated START. Continuing means transmitting into a device that has said it is not listening.

13. Reason It Through

A bus has no devices attached at all. What does the master observe when it addresses one, and what produced that observation?

A NACK, produced by nothing. The master releases SDA after the eighth bit, no device pulls it low, and the pull-up leaves it high — which is by definition a not-acknowledge. This is condition 1, and it is the only NACK condition that requires no participating device, which is exactly why an address scan works.

Why must a slave establish its acknowledge while SCL is low rather than deciding during the high period?

Because SDA may only change while SCL is low. Pulling SDA down during the high period is an SDA edge inside a high phase, which is reserved framing — the device would emit a START or STOP into the middle of a transfer rather than a late acknowledge. If it cannot decide in time, its legitimate option is to hold SCL low and stretch the clock.

A master writes twenty bytes and the nineteenth is NACKed. Which conditions are plausible, and which are eliminated?

Conditions 3 and 4 — the receiver did not understand that byte, or it has no room for more. Condition 1 is eliminated because the address was acknowledged, so a device is present. Condition 5 is eliminated because the master is transmitting, not receiving. Condition 2 is possible but less likely mid-transfer than at the start. The position of the NACK did most of that narrowing, which is why a frame decoder records every byte's answer.

Two devices accidentally share an address and both acknowledge. What does the master see, and what would reveal the problem?

Exactly the same acknowledge it would see from one device — the wired-AND makes two devices pulling low indistinguishable from one. Nothing in the acknowledge reveals it. What reveals it is reading an identifying register: two devices transmitting different IDs produce the bitwise AND of them, which is almost never a valid ID, whereas two similar data values AND to something plausible.

A driver's writes to an EEPROM succeed according to every acknowledge, and some are lost across a power cycle. Slowing the bus helps. What is the mechanism, and why is "slowing helps" the clue?

The EEPROM acknowledges receipt and then spends milliseconds committing the byte, NACKing everything during that window. Later writes arrive while it is busy and are refused. Slowing the bus accidentally supplies the wait the driver should have implemented as acknowledge polling — and that is the tell: a genuine timing violation worsens with temperature and loading, while a missing handshake is cured by any delay at all. The distinction is whether the fix is a delay or a check.

Why is a mutation that samples the acknowledge on the falling edge hard to catch?

Because the answer is usually still present at the falling edge — a far end that holds its level until after SCL has gone low makes the two sampling instants indistinguishable. Catching it requires stimulus that changes SDA between the two candidate instants, which the testbench does by releasing the far end exactly as SCL falls.

14. Understanding Check

15. Summary

An ACK is a pulled-low ninth bit; a NACK is nobody doing anything. The asymmetry means a bus with no devices NACKs correctly, with no hardware participating — the default answer is "no" and it is free.

The acknowledge is a bit like any other. It obeys the data-valid rule, so a receiver must establish it while SCL is low; deciding late means emitting framing, not answering late.

Five conditions produce a NACK, and one bit cannot distinguish them. Narrowing them is done from outside the slot: which byte NACKed, how far into the transfer, whether it reproduces, and whether the master was reading.

Condition 5 is not an error. A master-receiver's final NACK ends every read, and treating it as a failure is the most common mistake in I²C driver and verification code alike.

An acknowledge is a liveness signal, not a receipt. It does not prove correctness, understanding, eventual effect, responder count, responder identity, or timing legality — and §11 is a production failure resting on the third of those.

Out of reset, report NACK. The safe default, matching what the bus itself does.

After a NACK the master has exactly two options: STOP, or repeated START to retry without losing the bus.

A timing fault is only observable if the stimulus changes something between the candidate sampling instants — the reason the falling-edge mutation needed a far end that releases exactly as SCL falls.

16. What Comes Next

The slot is now understood: what goes in it, what it means, and what it does not. What has been quietly assumed throughout is that somebody knows whose job it is to fill it — and this chapter's block takes that as an input called we_acknowledge without ever computing it.

Chapter 7.3 computes it, and resolves the question that confuses more beginners than any other on this bus: the acknowledge belongs to the receiver of a byte, which means the direction of the byte decides who answers — not whether a device is the master or the slave.

Browse the full path on the I²C tutorials index. For the slot this chapter fills, see Byte and Bit Transmission; for why several devices answering is indistinguishable from one, Wired-AND.

Continue learning