Basics of I2C
Overview
- Synchronous, multi-master, multi-slave serial bus.
- Half-duplex communication (bidirectional SDA line).
- Uses 2 wires: SCL (clock), SDA (data).
- Speeds: Standard (100 kHz), Fast (400 kHz), High-Speed (3.4 MHz).
Physical Layer
- Open-drain outputs – requires pull-up resistors.
- 7-bit or 10-bit addressing (supports up to 128/1024 devices).
Data Frame Structure
- Start condition: SDA ↓ while SCL is high.
- Address frame: 7/10-bit address + R/W bit.
- ACK/NACK: Slave pulls SDA low to acknowledge.
- Data frames (8-bit chunks, MSB-first).
- Stop condition: SDA ↑ while SCL is high.
Start | Address | Read/Write | ACK/NACK | Data | Stop
Key Features
- Clock stretching: Slaves can hold SCL low to pause communication.
- Multi-master arbitration: Masters detect collisions via SDA monitoring.
- Speeds: Standard (100 kbps), Fast (400 kbps), High-Speed (3.4 Mbps).
Use Cases
- Sensors (temperature, accelerometers).
- EEPROMs, RTC (Real-Time Clock) modules.
Device Tree
- TODO
Writing client device drivers
- TODO
I2C-Tools Package in Userspace
- Useful for debugging, testing, some simple prototyping
- Accesses the I²C bus via
/dev/i2c-0
,/dev/i2c-1
… - Assume devices have registers, SMBus-like
i2cdetect
- scan an I2C bus for devices
- No guarantee it works (I²C is not discoverable by the spec)
[rishav] ➜ ~ i2cdetect -l
i2c-0 i2c i915 gmbus dpc I2C adapter
i2c-1 i2c i915 gmbus dpb I2C adapter
i2c-2 i2c i915 gmbus dpd I2C adapter
i2c-3 i2c AUX A/DDI A/PHY A I2C adapter
i2c-4 unknown Synopsys DesignWare I2C adapter N/A
i2c-5 unknown Synopsys DesignWare I2C adapter N/A
i2c-6 unknown SMBus I801 adapter at f040 N/A
[rishav] ➜ ~ i2cdetect -y 2
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- 28 -- -- -- -- -- -- --
30: -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
--
No response28
Response from address 28UU
Address in use (by driver)
i2cget, i2cset
i2cget
: read a register valuei2cset
: set a register value- Can use various types of SMBus and I2C transactions
- Limited to 8-bit register address
# i2cget -y 2 0x28 0x1b
0x21
# i2cset -y 2 0x28 0x55
#
i2cdump
- dump value of all registers
i2ctransfer
i2ctransfer
: the “swiss army knife of Linux I2C”, in userspace- Example: reimplement the i2cget -y 2 0x28 0x1b command:
# i2ctransfer -y 2 w1@0x28 0x1b r1@0x28
0x21
#
w1@0x28
Write transaction, 1 byte, client address 0x280x1b
Data to send in the write transactionr1@0x28
Read transaction, 1 byte, client address 0x28
Troubleshooting
- Return code from
i2c_*()
functions — Never ignore errors! - Kernel logs
- i2c-tools
- Oscilloscope or logic analyzer
No ACK from client - systematic
Problem: a client never responds to transactions
- i2c-tools symptom:
Error: Read failed
- Kernel internal APls symptom:
-ENXIO
i2cdetect
: a client at any unexpected address?
- Check address pins on client chip: datasheet, schematics
i2cdetect
: no client at any unexpected address?
- Client not powered, held in reset, broken, unsoldered pin
Oscilloscope: no activity on bus, SCL/SDA always high
- Pinmux (I2C adapter not reaching the pads)
- Device tree: device under wrong bus
Oscilloscope: no activity on bus, SCL/SDA always low
- Missing pull-up resistors (external or internal)
No ACK from client - sporadic(once in a while)
Problem: a client sporadically does not respond to transactions
- i2c-tools symptom:
Error: Read failed
- Kernel internal APls symptom:
-ENX10
Oscilloscope: SCL/SDA lines return to high level too slowly
- Weak pull-up
- Workaround: reduce
clock-frequency
in device tree
Oscilloscope: noise on SCL/SDA lines
- Hardware must be fixed
Oscilloscope: SCL/SDA delays incorrect
- Propagation delay in lines at high speed? Review PCB.
- Tune
i2c-scl-internal-delay-ns...
- Workaround: reduce
clock-frequency
in device tree
No ACK from client after reset
Problem: a client sporadically does not respond after unclean reset
- Symptom: driver fails to respond, fails to probe
No clean shutdown –> driver could not set client to idle state
- E.g. client left in the middle of a transaction, kernel starts a new one
Reset all clients during boot
- In hardware, if possible
- In the bootloader otherwise
TODO
- reg map (caching?) instead of i2c calls
References
- I2C on Linux: https://youtu.be/g9-wgdesvwA
- i2c-tools: https://i2c.wiki.kernel.org/index.php/I2C_Tools