I2C
Why this matters
I2C is the bus that tells you what a board is made of. Every transaction carries the target’s address in band, so a single capture enumerates the devices on the bus without you tracing a single trace. That is a property SPI does not have, and it makes I2C the friendliest bus on the board to an attacker.
What rides on it is usually configuration rather than code — but “usually” is doing work in that sentence. EEPROMs on I2C hold calibration data, serial numbers, provisioning keys, and occasionally the credentials the device uses to talk to its cloud.
A terminology note. NXP’s UM10204 Rev 7.0 (2021) replaced master/slave with controller/target. This page uses the current terms. Most tools, decoders, and tutorials you will meet still use the old ones, so you need to read both.
The physical layer
Two wires, and the interesting part is how they are driven:
| Line | Meaning |
|---|---|
| SCL | Serial clock, driven by the controller |
| SDA | Serial data, bidirectional |
Both are open drain. A device can pull a line low but never drive it high; pull-up resistors return the line to idle. Three consequences follow, and all three matter:
- Any device can hold a line low at any time. This is a feature — it is how acknowledge and clock stretching work — and a failure mode, because one stuck device wedges the whole bus.
- Wired-AND arbitration. Two controllers can start simultaneously; the one
that transmits a
1while seeing a0on the wire loses and backs off, with no data corrupted. - Rise time is limited by the pull-ups. Weak pull-ups on a long bus give slow rising edges, which is the usual reason an I2C bus that “should work” does not.
Speed modes
| Mode | Maximum |
|---|---|
| Standard | 100 kbit/s |
| Fast | 400 kbit/s |
| Fast-mode Plus | 1 Mbit/s |
| High-speed | 3.4 Mbit/s |
Nearly everything you will meet in this course is 100 or 400 kHz — slow enough that any logic analyzer can capture it comfortably.
The protocol
START and STOP
The framing conditions are deliberately illegal as data, which makes them unmistakable in a capture:
START: SDA falls while SCL is HIGH
STOP: SDA rises while SCL is HIGH
During normal data transfer SDA is only allowed to change while SCL is low. So any SDA transition during a high clock is framing, not data. When you are hunting for the start of a transaction in a noisy capture, that is what you look for.
Addressing and the acknowledge
After START, the controller sends one byte: seven address bits then a direction bit.
bit: 7 6 5 4 3 2 1 0
[-- 7-bit address --------] [R/W]
R/W is 0 for write, 1 for read. So the byte on the wire is
address << 1 | rw — which is why a device at address 0x19 appears as 0x32
on the wire for a write and 0x33 for a read.
This is the single most common decoding error. A student who reports the
address as 0x32 has read the wire correctly and the datasheet incorrectly.
Many datasheets quote the 8-bit form, which compounds the confusion; when a
datasheet says “the device address is 0x94”, it means 7-bit 0x4A.
Note the trap in that example: 0x32 and 0x33 are the same device, once
being written to and once being read from. A scan that reports “devices at 0x32
and 0x33” has found one device and counted it twice.
Then the ninth bit: the transmitter releases SDA and the receiver pulls it low to acknowledge.
| Ninth bit | Meaning |
|---|---|
| SDA low (ACK) | A device at that address exists and is responding |
| SDA high (NAK) | Nothing there, or the device is refusing |
That nine-bit grouping is the signature of I2C in a capture. If you count groups of nine rather than eight, you are looking at I2C.
Repeated START
To read a register you must first write the register address, then read — but releasing the bus between the two lets another controller interleave. A repeated START (Sr) issues a new START without an intervening STOP, holding the bus across both phases:
S addr+W ACK reg ACK Sr addr+R ACK data NAK P
That pattern — write one byte, repeated start, read — is the most common transaction shape on the bus, and recognising it saves you a lot of time.
Note the final NAK from the controller: when reading, the controller NAKs the last byte to tell the target to stop transmitting. A NAK there is normal and correct, not an error.
Clock stretching
A target that needs time can hold SCL low after the acknowledge. The controller must wait for the line to release before continuing. Not all controllers implement this correctly, and it is a classic source of intermittent bus failures — and of captures where the clock period is suddenly irregular.
Reserved addresses
The bottom eight (0x00–0x07) and top eight (0x78–0x7F) addresses are
reserved by the specification. 0x00 is the general call address. A bus scan
should skip them, and a scanner that reports a device at 0x00 is confused.
That leaves 112 usable addresses, which is why address collisions between peripherals are a real design problem — and why some devices have address-select pins or jumpers.
Sniffing a bus
Attach a logic analyzer to SDA, SCL, and ground. Nothing else. An analyzer is high impedance and cannot disturb the bus, which is exactly what you want before you understand what is on it.
Capture from power-on: the initialisation burst enumerates every device the firmware expects to find, which is more informative than anything that happens later.
Worked example: decoding a capture by hand
A decoded burst from a board’s power-on sequence, on a board carrying an ST LSM303DLHC:
1 S 0x32 ACK 0x20 ACK 0x27 ACK P
2 S 0x3C ACK 0x00 ACK 0x10 ACK P
3 S 0x30 NAK P
4 S 0x3C ACK 0x0A ACK Sr 0x3D ACK 0x48 NAK P
Reading it:
- Line 1.
0x32is address0x19with the write bit. Writing0x27to register0x20. Cross-referenced against the LSM303DLHC datasheet,0x20isCTRL_REG1_Aand0x27selects a 10 Hz output rate with all three axes enabled — the accelerometer is being brought out of power-down. - Line 2. A different device:
0x3Cis address0x1E. Writing0x10to register0x00,CRA_REG_M. Same package, but the magnetometer is a second I2C target with its own address — which you would not guess from the board, only from the bus. - Line 3. Address
0x18, NAKed. The firmware looked for a device at0x18and nothing answered. Either an optional peripheral is absent, or the firmware supports several board variants and probes for all of them. This is a finding: it tells you about hardware that could be there. - Line 4. The read pattern. Write the register index
0x0A, repeated START, turn the bus around with0x3D(the same0x1E, now with the read bit), and read back0x48. That isIRA_REG_M, the identification register — so this is the firmware confirming what it is talking to. Read all three of0x0A–0x0Cand they return0x48 0x34 0x33, ASCIIH43.
The NAK on the last byte of line 4 is not an error. On a read, the controller drives the acknowledge bit, and it NAKs the final byte to tell the target to stop sending. A NAK after an address byte means “nobody there”; a NAK after the last data byte of a read means “done”. Confusing the two is the second most common decoding mistake after the address shift.
From four transactions you have: one confirmed device with its identity, one absent device the firmware expects, and two configuration values you can look up. No board tracing required.
Interacting with a bus
Reading is safe. Writing is not, and there is a real risk of bricking: configuration EEPROMs on I2C frequently hold calibration constants that the device cannot regenerate.
To become a controller you need the original one out of the way — hold the SoC in reset — and a tool that can drive the bus. The Bus Pirate and Tigard both do this.
An address scan walks every valid address and records which ACK:
$ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- 18 -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
...
40: -- -- -- -- -- -- -- -- -- -- 4a -- -- -- -- --
i2cdetect is from i2c-tools and works when you have Linux on the device
itself — which you may, after getting a shell over UART.
From outside, the Bus Pirate’s (1) macro in I2C mode does the same scan.
⚠️ A scan is not entirely passive. It writes an address byte to every address on the bus, and a device that interprets a bare write as a command may act on it. Rare, but it happens with some power-management ICs. Sniff first; scan only when you need to.
Where the secrets are
Devices on I2C worth attention in an assessment:
| Device type | Typical addresses | Why you care |
|---|---|---|
| EEPROM (24Cxx) | 0x50–0x57 |
Serial numbers, calibration, provisioning data, sometimes keys |
| RTC (DS1307, PCF8523) | 0x68 |
Battery-backed RAM often used as scratch storage |
| Sensors | Various | Rarely security-relevant, useful for fingerprinting |
| Audio codecs | 0x1A, 0x4A |
Not sensitive; useful as a known-good calibration target |
| MEMS sensors | 0x19, 0x1E, 0x68, 0x6B |
Not sensitive either, but they ACK reliably — the easiest way to prove your wiring and decode settings are right before chasing something that matters |
| Power management | 0x08–0x0F |
Can be dangerous to write to |
A 24C-series EEPROM at 0x50 is the one to read first. They are small, easy to
dump, and vendors put things in them that they would not put in flash because
“nobody looks at the EEPROM”.
Key takeaways
- I2C carries the target address in band, so one capture enumerates the bus — the property that makes it the most informative bus to sniff.
- The byte on the wire is
address << 1 | R/W;0x32on the wire is device0x19, and0x33is the same device being read. Most decoding errors are this. - A NAK after an address means nobody answered; a NAK after the last byte of a read is the controller ending the transfer normally.
- Nine-bit groupings are the signature of I2C: eight data bits plus an acknowledge.
- A NAK during a firmware’s power-on scan tells you about hardware the vendor’s other SKUs have.
- Open-drain means any device can wedge the bus, and slow rise times are the usual cause of a bus that intermittently fails.
- Read freely; write with care. EEPROM contents are often unrecoverable.
References
- NXP UM10204, I2C-bus specification and user manual (Rev. 7.0, October 2021) — https://www.pololu.com/file/0J435/UM10204.pdf
- sigrok I2C protocol decoder — https://sigrok.org/wiki/Protocol_decoder:I2c
- Linux
i2c-tools— https://i2c.wiki.kernel.org/index.php/I2C_Tools - ST LSM303DLHC datasheet, accelerometer + magnetometer — https://www.st.com/resource/en/datasheet/lsm303dlhc.pdf
- Bus Pirate I2C guide — https://buspirate.com/
- Texas Instruments, Understanding the I2C Bus (SLVA704) — https://www.ti.com/lit/an/slva704/slva704.pdf
Related course pages: Protocols · Schedule · UART · SPI · Tools of the Trade · Dumping flash
🛠️ Maintenance note: UM10204 Rev 7.0 (2021) is current and the controller/target terminology it introduced has not yet reached most tools — expect decoder UIs and student-facing tutorials to say master/slave for years yet, and teach both. Device addresses in the table are conventions, not guarantees; always confirm against the datasheet for the part in front of you.