I2C (Linux)
Introduction
I2C (Inter-Integrated Circuit) is a low-speed, two-wire communication protocol, used to communicate between several peripherals and a (generally) single controller device. In the I2C protocol, each peripheral has a set of registers, which the controller can read from or write to. In an I2C bus, every peripheral has a unique, hardware-defined address, and the controller makes requests to read or write to each device. The I2C electrical interface consists of only two control signals:
- SDA (Serial Data Line): Data signal. Used by both the controller (to specify addresses and send commands) and the peripherals (to send data back to the controller).
- SCL (Serial Clock Line): Clock signal. Generated by the controller and used to synchronize the data transfer between the devices.
This article will guide you on how to use i2c-tools to control I2C buses on Toradex's System on Modules (SoMs).
Keep in mind that Torizon OS is preferred for controlling I2C buses due to its ease of use and smoother application development experience. For controlling I2C buses using Torizon, refer to How to Use I2C on Torizon OS.
Additional I2Cs
Depending on the module type, additional I2C buses might be available as alternate functions of other pins given the kernel gets configured accordingly in the device tree or the platform data. Read the Computer on Module datasheet carefully and check the Pinout Designer Tool for more information about extra I2C buses and the impact on the default pinout of the module.
Find the I2C Buses of Your Module
The tables below display the I2C enumeration adopted on Toradex Reference Images. If you enable extra I2C controllers or disable existing ones, the index numbers may change, and you will need to get the correct I2C index is from the controller address. The controller address is the hardware-defined register address of the I2C controller, and does not change.
I2C buses should be accessed via i2cdev device nodes named with the module family and matching the signal name used in the module's datasheet.
On all the families of modules, the SoM's interface numbering is different from the SoC. From the BSP 5 onwards, you can access the interfaces following the SoM's interface names, which enables software compatibility between members of the same family.
The Aquila modules feature the following always compatible I2C interfaces, according to the Aquila Family Specification:
| SoM Interface | Pins on Aquila Standard | Device nodes names | Recommended usage |
|---|---|---|---|
| I2C1 | D07/D08 | /dev/aquila-i2c1 | USB-C PD (Power Delivery) |
| I2C2 | C16/C17 | /dev/aquila-i2c2 | General Purpose |
Some modules may feature additional interfaces reserved for the DSI display, HDMI output, and the CSI camera.
To obtain the device node names for the Aquila module family:
# ls -l /dev/aquila-i2c*
It will display the available Aquila pin-compatible I2Cs and their corresponding names used by the BSP. Those corresponding names are important because the Linux kernel logs will print the real device names (e.g. /dev/i2c-4), not the Aquila symlinks (e.g. /dev/aquila-i2c1).
For non-standard interfaces, consult the specific SoM datasheet.
The Verdin modules feature the following always compatible I2C interfaces, according to the Verdin Family Specification:
| SoM Interface | Pins on Verdin Standard | Device nodes names | Recommended usage |
|---|---|---|---|
| I2C1 | SODIMM_12/14 | /dev/verdin-i2c1 | General Purpose |
Some modules may feature additional interfaces reserved for the DSI display, HDMI output, and the CSI camera.
To obtain the device node names for the Verdin module family:
# ls -l /dev/verdin-i2c*
It will display the available Verdin pin-compatible I2Cs and their corresponding names used by the BSP. Those corresponding names are important because the Linux kernel logs will print the real device names (e.g. /dev/i2c-4), not the Verdin symlinks (e.g. /dev/verdin-i2c1).
For non-standard interfaces, consult the specific SoM datasheet.
The Apalis modules feature the following always compatible I2C interfaces, according to the Apalis Family Specification:
| SoM Interface | Pins on Apalis Standard | Device nodes names | Recommended usage |
|---|---|---|---|
| I2C1 | MXM_209/211 | /dev/apalis-i2c1 | General Purpose |
| I2C2 | MXM_205/207 | /dev/apalis-i2c2 | Display Data Channel (DDC) |
| I2C3 | MXM_201/203 | /dev/apalis-i2c3 | Camera Interface |
To obtain the device node names for the Apalis module family:
# ls -l /dev/apalis-i2c*
It will display the available Apalis pin-compatible I2Cs and their corresponding names used by the BSP. Those corresponding names are important because the Linux kernel logs will print the real device names (e.g. /dev/i2c-4), not the Apalis symlinks (e.g. /dev/apalis-i2c1).
For non-standard interfaces, consult the specific SoM datasheet.
The Colibri module standard features only one generic I2C interface:
| SoM Interface | Pins on Colibri Standard | Device nodes names | Recommended usage |
|---|---|---|---|
| I2C1 | SODIMM_194/196 | /dev/colibri-i2c1 | General Purpose |
Some of the members of the Colibri family may feature an additional I2C interface for DDC.
To obtain the device node names for the Colibri module family:
# ls -l /dev/colibri-i2c*
It will display the available Colibri pin-compatible I2Cs and their corresponding names used by the BSP. Those corresponding names are important because the Linux kernel logs will print the real device names (e.g. /dev/i2c-4), not the Colibri symlinks (e.g. /dev/colibri-i2c1).
For non-standard interfaces, consult the specific SoM datasheet.
Get Controller Address of an I2C Bus
The default values from the tables above may change if you enable extra I2Cs, for example, to use a MIPI-CSI2 camera, an LVDS or MIPI-DSI display - or for any other reason you enable or disable I2Cs.
To make sure that you are using the correct I2C bus, you can get the I2C controller address (which does not change) using i2cdetect, as shown below.
As an alternative, you can also get the address of each controller with ls -la /sys/class/i2c-dev.
# i2cdetect -l
i2c-0 i2c 30a20000.i2c I2C adapter
i2c-1 i2c 30a30000.i2c I2C adapter
i2c-2 i2c 30a40000.i2c I2C adapter
i2c-3 i2c 30a50000.i2c I2C adapter
From this example, the i2c-3 bus controller's address is 30a50000. This address matches the one specified in the Device Tree include file of the i.MX 8M Plus SoC, imx8mp.dtsi. If you disable an I2C bus or enable another one, the bus numbering may change, but you can still identify which controller maps to which bus on your board, by using the address defined in the device tree.
i2c4: i2c@30a50000 {
compatible = "fsl,imx8mp-i2c", "fsl,imx21-i2c";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x30a50000 0x10000>;
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_I2C4_ROOT>;
status = "disabled";
};
I2C Tools
I2C Tools is a collection of command-line utilities that allow you to interact with devices on an I2C bus connected to your device. It allows you to detect, read and write to devices connected to the bus. Our Reference Multimedia Image includes the i2c-tools package, which you can use to control your module's I2C interface.
Note that the Reference Minimal Image does not include i2c-tools
To control the I2C interfaces of your device with i2c-tools, see the different use cases below. The examples shown here are taken from a Verdin iMX8M Plus, with an external I2C device, of address 0x68, connected to the I2C_1 interface.
List the I2C buses of your board. Adapt this command according to your module as instructed in Find the I2C Buses of Your Module.
# ls -l /dev/verdin-i2c*
lrwxrwxrwx 1 root root 5 May 29 18:48 /dev/verdin-i2c-on-module -> i2c-0
lrwxrwxrwx 1 root root 5 May 29 18:48 /dev/verdin-i2c1 -> i2c-3
lrwxrwxrwx 1 root root 5 May 29 18:48 /dev/verdin-i2c2 -> i2c-1
lrwxrwxrwx 1 root root 5 May 29 18:48 /dev/verdin-i2c4 -> i2c-2
From the previous output, the I2C_1 Verdin-Standard I2C bus (where the external device is connected) is mapped to the /dev/i2c-3 bus, from the point of view of the kernel. You can list all the I2C buses as seen by the kernel with ls -l /dev/i2c-*. Due to this mapping, the next examples will all be run on the bus number 3, which the device is connected to.
Detect I2C Devices
Detect devices on an I2C bus with i2cdetect. In the example below, the -y flag makes the output silent, and the -r flag specifies that the command should read from the /dev/i2c-3 bus. Keep in mind the following points:
- In the output,
UUdenotes a device which is used by a kernel driver, and you are not recommended to interfere with it. - Depending on the I2C device it may not get discovered by i2cdetect.
# i2cdetect -y -r 3
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- --
20: -- UU -- -- -- -- -- -- -- -- -- -- UU -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- UU
50: -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Dump the Contents of an I2C Device
Dump the I2C device register content with i2cdump. The example below opens the device at the 0x68 address of the /dev/i2c-3 bus, and displays the content from the register 0x07 to 0x2f. The b option tells i2cdump to set its read size to a single byte. For more information, refer to the i2cdump manpage.
# i2cdump -r 0x07-0x2f 3 0x68 b
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-3, address 0x68, mode byte
Probe range limited to 0x07-0x2f.
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: b4 e7 91 05 62 28 6f 6e 95 ????b(on?
10: 56 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 V...............
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Read from an I2C Device
Read a single byte from a register from the device with i2cget. The example below opens the device at the 0x68 address of the /dev/i2c-3 bus, and displays the content from the register 0x0e in byte format. For more information, refer to the i2cget manpage
# i2cget 3 0x68 0x0e b
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will read from device file /dev/i2c-3, chip address 0x68, data address
0x0e, using read byte data.
Continue? [Y/n] y
0x6e
Write to an I2C Device
Write a single byte to a register from the device with i2cset. The example below opens the device at the 0x68 address of the /dev/i2c-3 bus, and sets the content of the register 0x0e to 0x50. For more information, refer to the i2cset manpage
# i2cset 3 0x68 0x0e 0x50 b
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will write to device file /dev/i2c-3, chip address 0x68,
data address 0x0e, data 0x50, mode byte.
Continue? [Y/n] y