How to debug with i2c-tools
Introduction
This is a quick guide to use i2c-tools for i2c communication debugging. Find below information to detect buses, addresses and also to communicate with read and write commands. The follow sample steps were executed on an NVIDIA Jetson AGX ORIN.
Find I2C Buses
Find the available i2c buses from your system with the following command.
i2cdetect -l
Here is an example of the output for a Jetson AGX ORION system:
nvidia@ubuntu:~$ i2cdetect -l i2c-0 i2c 3160000.i2c I2C adapter i2c-1 i2c c240000.i2c I2C adapter i2c-2 i2c 3180000.i2c I2C adapter i2c-3 i2c 3190000.i2c I2C adapter i2c-4 i2c Tegra BPMP I2C adapter I2C adapter i2c-5 i2c 31b0000.i2c I2C adapter i2c-6 i2c 31c0000.i2c I2C adapter i2c-7 i2c c250000.i2c I2C adapter i2c-8 i2c 31e0000.i2c I2C adapter i2c-9 i2c NVIDIA SOC i2c adapter 0 I2C adapter
Find I2C Addresses
You can also get the information of the I2C devices wired to the specific I2C bus. With the following command you should be able to find the available i2C addresses to the chips/devices connected. You could also know if there's a Kernel I2C driver controlling the device.
i2cdetect -r -y <BUS NUMBER>
In the following example, we are checking bus number 2. You can see the numbers 40 and 48, this mean that the there are 2 devices wired to the I2C bus 2. These devices have an specific address that is used to communicate with the device, it's called the "I2C slave address". In this case there's one device available at address 0x40 and another at address 0x48
nvidia@ubuntu:~$ i2cdetect -r -y 2 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Sometimes, instead of seeing slave addresses at the bus, you'll see 'UU instead. That, means that there's an I2C driver loaded on the Kernel which is controlling the device at that specific address.
nvidia@ubuntu:~$ i2cdetect -r -y 2 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: UU -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Read Registers from Device
To read registers from a device, you can use i2ctransfer command:
i2ctransfer -y -f <I2C-BUS> w<REG-ADDR-BITS>@<I2C-ADDR> <REG-ADDR> r<REG-VAL-BITS>
Let's see the following example reading the register 0x0250 from a device at i2c-address 0x40 from bus 2. The register address size is 2 bits and we expect a value of 1 bit:
# I2C Bus = 2 # I2C Address = 0x40 # Register addresses size 2 bits # Register address = 0x0250 # Register values size 1 bit nvidia@ubuntu:~$ i2ctransfer -y -f 2 w2@0x40 0x02 0x50 r1 0xad
Write Registers to Device
To write registers to a device, you can use i2ctransfer command:
i2ctransfer -y -f <I2C-BUS> w<REG-ADDR/VAL-BITS>@<I2C-ADDR> <REG-ADDR> <REG-VAL>
Let's see the following example reading the register 0x0250 from a device at i2c-address 0x40 from bus 2. The register address size is 2 bits and we expect a value of 1 bit:
# I2C Bus = 2 # I2C Address = 0x40 # Register addresses size 2 bits # Register address = 0x0250 # Register values size 1 bit nvidia@ubuntu:~$ i2ctransfer -y -f 2 w3@0x40 0x02 0x50 0x43
Let's read back to make sure the value was updated:
nvidia@ubuntu:~$ i2ctransfer -y -f 2 w2@0x40 0x02 0x50 r1 0x43