Microcontrollers · #11 of 20
I²C Communication
Addressing, ACK/NAK, Clock Stretching
Why it matters
I²C lets you connect many peripherals (IMUs, OLEDs, environmental sensors) using only two wires.
The idea
The core idea
I²C (Inter-Integrated Circuit) is a two-wire bus protocol that lets you connect many devices to a microcontroller:- SDA (Serial Data): Carries the actual data bits
- SCL (Serial Clock): Synchronizes data transfer
<h3>Why Open-Drain?</h3>
Open-drain means devices can only pull the line LOW, never HIGH. The pull-up resistor pulls it HIGH when no device is pulling LOW.
This allows multiple devices to share the same bus safely:
<ul>
<li>Any device can pull the line LOW (wired-AND logic)</li>
<li>If one device pulls LOW, the whole bus goes LOW</li>
<li>All devices must release for the bus to go HIGH</li>
<li>No conflicts — devices can't fight over the bus</li>
</ul>
<h3>Addressing: How Devices Are Selected</h3>
Each I²C device has a unique 7-bit address (0x08 to 0x77). The master sends the address first:
<ul>
<li>7 address bits identify the device</li>
<li>1 R/W bit: 0 = write (master→slave), 1 = read (slave→master)</li>
<li>Combined into one 8-bit byte on the wire</li>
</ul>
Example: Address 0x3C (0b0111100) + Write (0) = byte 0x78 (0b01111000)
<h3>Protocol Flow</h3>
<div class=
Demo
Top line is SCL, bottom is SDA. Watch for:
- START: SDA falls while SCL is high
- STOP: SDA rises while SCL is high
- ACK/NACK: the 9th clock after each byte
Key takeaways
- I²C uses two wires (SDA, SCL) with open-drain outputs requiring pull-up resistors
- 7-bit addresses (0x08–0x77) + 1 R/W bit = 8 bits on wire
- START: SDA falls while SCL high; STOP: SDA rises while SCL high
- ACK (SDA LOW) = success; NACK (SDA HIGH) = error or end of read
- Clock stretching lets slow slaves pause the master by holding SCL LOW
- Multiple devices share the bus; addressing selects which responds
- Standard speed: 100 kHz; Fast: 400 kHz; bus capacitance limits max speed
Going deeper
Troubleshooting I²C Issues
- No response (NACK): Check address, power, wiring, pull-ups
- Garbled data: Reduce bus speed, check for loose connections
- Bus stuck LOW: A device may be holding SDA/SCL LOW; power cycle
- Address conflicts: Some devices have address-select pins (A0, A1)
<h4>Address Scanning</h4>
Scan addresses 0x08–0x77: send START + address + R/W, check for ACK.
This identifies all devices on the bus — essential for debugging.
<h4>Pull-up Resistor Selection</h4>
<ul>
<li>Too weak (high resistance): Bus rises slowly, limits speed</li>
<li>Too strong (low resistance): High current when pulled LOW, wastes power</li>
<li>Sweet spot: 2.2kΩ–10kΩ for 3.3V (depends on bus capacitance)</li>
<li>Long wires need stronger pull-ups (lower resistance)</li>
</ul>
<h4>Reading vs Writing</h4>
<ul>
<li><strong>Write</strong>: Master sends data bytes, slave ACKs each</li>
<li><strong>Read</strong>: Master sends address+R, slave sends data, master ACKs (or NACKs last byte)</li>
<li>Some devices need register writes before reads (e.g.,
Math details
I²C frame (write, 7-bit address):
START
[A6 A5 A4 A3 A2 A1 A0 W]
ACK
[D7 D6 D5 D4 D3 D2 D1 D0]
ACK
STOP