Skip to main content
Version: BSP 7.x.y

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.

tip

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 Verdin modules feature the following always compatible I2C interfaces, according to the Verdin Family Specification:

SoM InterfacePins on Verdin StandardDevice nodes namesRecommended usage
I2C1SODIMM_12/14/dev/verdin-i2c1General 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.

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.

warning

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, UU denotes 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
Send Feedback!