Real I2C devices are used through a handful of transaction patterns: writing a register, reading a register with a repeated START, and reading or writing several registers in one go. A target that needs time can stretch the clock in the middle of a transaction. This article goes through each pattern with the example register target, and shows clock stretching in a simulation.
8 min read | Intermediate
What You'll Learn
- Write and read device registers over I2C
- Use a repeated START to change direction without releasing the bus
- Read and write several bytes with an auto-incrementing pointer
- Recognize and handle clock stretching
Writing a Register
A register write is one transaction in one direction:
op(START, 0, 0);
op(WRITE, {dev, 1'b0}, 0); // address + W
op(WRITE, {6'b0, r}, 0); // register pointer
op(WRITE, v, 0); // data
op(STOP, 0, 0);
The target acknowledges all three bytes. The specification describes this as the controller-transmitter addressing a target-receiver, with the transfer direction never changing.
Reading a Register: the Repeated START
To read a register, the controller must first tell the target which register, which is a write, and then read, which needs a new address byte with R/W = 1. It could send STOP and start again, but another controller could take the bus in between. Instead it sends a repeated START (Sr): a START without a STOP before it. The bus stays busy, and the target keeps its pointer:
op(START, 0, 0);
op(WRITE, {dev, 1'b0}, 0); // address the target for writing the pointer
op(WRITE, {6'b0, r}, 0);
op(START, 0, 0); // repeated START
op(WRITE, {dev, 1'b1}, 0); // address it again, now for reading
op(READ, 0, 1); // one byte, then NACK
op(STOP, 0, 0);
After the second address byte, the direction turns around: the target transmits and the controller acknowledges. To end the read, the controller answers the last byte with a NACK, so that the target releases SDA and the controller can generate STOP.
Quick Check
Q: Why does the controller send NACK, not ACK, after the last byte it reads?
Show Answer
An ACK tells the target to send another byte, so it would start driving SDA with the next bit. The NACK tells it to stop and release SDA, so the controller can generate the STOP condition.
Several Bytes at Once
Most register targets increment their pointer after every byte, like the example target. A controller can then write or read a block of registers in one transaction, which saves the address and pointer bytes each time. EEPROMs use the same idea for pages of memory. How the pointer behaves, whether it wraps and at what boundary, is up to the device designer and is described in its datasheet.
Clock Stretching
A target that cannot keep up may hold SCL low after a byte: the controller releases SCL for the next clock, sees that it stays low, and waits. The specification calls this clock stretching; it is optional, and many targets cannot do it at all. The example target can stretch for a set number of clock cycles after each written data byte:
WDATA: begin
sda_oe <= 1'b0;
if (STRETCH != 0)
hold <= STRETCH; // need time to store the byte: hold SCL low
end
With the stretch set to 2 µs, a register write and read back still succeed, just later:
7915 write 0x51 reg2 = 0x5a 15925 read 0x51 reg2 = 0x5a
The controller does not need to know that the target stretched: the "wait until SCL is really high" rule in its bit timing absorbs the delay. A controller that ignores SCL and drives the clock blindly breaks with any stretching target.
Quick Check
Q: A controller has a push-pull SCL output. Can it work with a target that stretches the clock?
Show Answer
No. It would drive SCL high while the target pulls it low, a short circuit, and it would never see the stretch. The specification allows a push-pull SCL only for a single controller with no stretching devices on the bus.
Running It in ChipVerify Lab
The example runs the register write and read with clock stretching. Change STRETCH and watch the transaction slow down.
Common Mistakes
Mistake #1: STOP instead of a repeated START
Some targets reset their pointer on STOP, and in a multi-controller system another controller can take the bus. Use a repeated START between the pointer write and the read.
Mistake #2: ACKing the last byte read
The target keeps transmitting and may hold SDA low, so the controller cannot create STOP. NACK the last byte.
Mistake #3: Timeouts too short for stretching
Some targets stretch for milliseconds during internal writes, EEPROMs in particular. Size software and hardware timeouts from the datasheet.
Practice Exercise
Challenge: A Burst Write
Write registers 1, 2 and 3 of target 0x50 with 0x11, 0x22 and 0x33 in a single transaction, then read them back one by one.
Hint
Send the pointer once, then three data bytes before STOP. The target increments its pointer after each one.
Solution
op(START, 0, 0);
op(WRITE, {7'h50, 1'b0}, 0);
op(WRITE, 8'h01, 0); // pointer: register 1
op(WRITE, 8'h11, 0); // register 1
op(WRITE, 8'h22, 0); // register 2 (the pointer incremented)
op(WRITE, 8'h33, 0); // register 3
op(STOP, 0, 0);
9675 burst write of 3 bytes from reg1 17685 read 0x50 reg1 = 0x11 25695 read 0x50 reg2 = 0x22 33705 read 0x50 reg3 = 0x33
Three registers in one transaction of six bytes, against nine bytes for three separate writes.
Open the ready-made example in the lab and run the simulation.
Summary
- A register write is S, address+W, pointer, data, P.
- A register read writes the pointer, then uses a repeated START and address+R to read.
- The controller ACKs every byte it reads except the last, which it NACKs before STOP.
- Auto-incrementing pointers allow multi-byte reads and writes in one transaction.
- Targets may stretch SCL; controllers must wait until SCL is really high.