Accessing I2C Devices in Linux Print


This application note explains how to use the I2C Master interface in Linux (uClinux) BSP (Board Support Package) for the STM32H7 device.

The Linux kernel provides a device driver for the I2C controller of the STM32H7 BSPs, enabled in the kernel with the CONFIG_I2C_STM32F7 build-time option. Another kernel configuration option that you will require is CONFIG_I2C_CHARDEV. This option enables the kernel API that allows accessing I2C devices from user-space application code. These kernel configuration options are enabled by default in the rootfs project.

The STM32H7 device provide four I2C bus controllers. The parameters of each bus controller are specified in the i2c* child nodes properties in the corresponding linux/arch/arm/boot/dts/stm32h743.dtsi file:

i2c1: i2c@40005400 { compatible = "st,stm32f7-i2c"; #address-cells = <1>; #size-cells = <0>; reg = <0x40005400 0x400>; interrupts = <31>, <32>; resets = <&rcc STM32H7_APB1L_RESET(I2C1)>; clocks = <&rcc I2C1_CK>; status = "disabled"; }; i2c2: i2c@40005800 { compatible = "st,stm32f7-i2c"; #address-cells = <1>; #size-cells = <0>; reg = <0x40005800 0x400>; interrupts = <33>, <34>; resets = <&rcc STM32H7_APB1L_RESET(I2C2)>; clocks = <&rcc I2C2_CK>; status = "disabled"; }; i2c3: i2c@40005c00 { compatible = "st,stm32f7-i2c"; #address-cells = <1>; #size-cells = <0>; reg = <0x40005C00 0x400>; interrupts = <72>, <73>; resets = <&rcc STM32H7_APB1L_RESET(I2C3)>; clocks = <&rcc I2C3_CK>; status = "disabled"; }; i2c4: i2c@58001c00 { compatible = "st,stm32f7-i2c"; #address-cells = <1>; #size-cells = <0>; reg = <0x58001C00 0x400>; interrupts = <95>, <96>; resets = <&rcc STM32H7_APB4_RESET(I2C4)>; clocks = <&rcc I2C4_CK>; status = "disabled"; };

Assignment of the I2C signals to specific pins is described in the i2c*_pins* child nodes of the pinctrl node in linux/arch/arm/boot/dts/stm32h7-pinctrl.dtsi:

i2c1_pins_a: i2c1-0 { pins { pinmux = <STM32_PINMUX('B', 6, AF4)>, /* I2C1_SCL */ <STM32_PINMUX('B', 7, AF4)>; /* I2C1_SDA */ bias-disable; drive-open-drain; slew-rate = <0>; }; }; i2c4_pins_a: i2c4-0 { pins { pinmux = <STM32_PINMUX('D', 12, AF4)>, /* I2C4_SCL */ <STM32_PINMUX('D', 13, AF4)>; /* I2C4_SDA */ bias-disable; drive-open-drain; slew-rate = <0>; }; };

The rootfs.dts.STM32H7 file defines the I2C interface reference with additional properties, which enable the appropriate I2C bus controller and connect it to the specified pins:

&i2c1 { pinctrl-0 = <&i2c1_pins_a>; pinctrl-names = "default"; status = "okay"; }; &i2c4 { pinctrl-0 = <&i2c4_pins_a>; pinctrl-names = "default"; status = "okay"; ... };

The Emcraft uClinux distribution includes the Linux run-time tools that can be used to access I2C devices from user space. The following lines in the rootfs.initramfs file add these tools to the target file system:

file /usr/sbin/i2cdump ${INSTALL_ROOT}/A2F/root/usr/sbin/i2cdump 755 0 0
file /usr/sbin/i2cdetect ${INSTALL_ROOT}/A2F/root/usr/sbin/i2cdetect 755 0 0
file /usr/sbin/i2cset ${INSTALL_ROOT}/A2F/root/usr/sbin/i2cset 755 0 0
file /usr/sbin/i2cget ${INSTALL_ROOT}/A2F/root/usr/sbin/i2cget 755 0 0

The functionality described above is enabled by default in the rootfs project. So, just run the rootfs.uImage binary on your target and observe the kernel messages about the I2C bus being enabled:

[ 2.962391] stm32f7-i2c 40005400.i2c: STM32F7 I2C-0 bus adapter
[ 2.989212] stm32f7-i2c 58001c00.i2c: STM32F7 I2C-1 bus adapter

Run the Linux I2C tools to examine I2C devices on your target. For instance, the following command scans the I2C-0 bus and reports any devices it detects on the bus:

/ # i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- 14 -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
/ #

Refer to the documentation available from the Internet for detailed manuals on the Linux I2C tools, for instance: https://linuxhint.com/i2c-linux-utilities. Sometimes your I2C device is already supported in the Linux kernel, and you want to utilize it in some standard way. To provide such access to the I2C device you need:

  • Enable the appropriate I2C device driver in your Linux kernel configuration;
  • Add information about your I2C device into the appropriate i2c node reference in the rootfs.dts.STM32H7 file.

As an example, let's connect the Altitude 2 Click board with the MS5607 pressure sensor to the J4 Click connector on the STM32H7-BSB Rev 4A baseboard.

After connection, provide the user with a simple interface to it:

  • Enable the MS5611_I2C driver in the Linux kernel configuration (Device Drivers -> Industrial I/O support -> Pressure sensors -> Measurement Specialties MS5611 pressure sensor driver -> support I2C bus connection):
  • $ make kmenuconfig

  • Add information about the MS5607 pressure sensor into rootfs.dts.STM32H7:
  • &i2c4 { ... pressure@77 { compatible = "meas,ms5607"; reg = <0x77>; status = "okay"; }; };

  • Build rootfs.uImage:
  • $ make

  • Run the resultant image on the target, and validate access to the MS5607 pressure sensor via the standard interfaces defined by the kernel drivers:
  • / # cat /sys/bus/iio/devices/iio:device0/name
    ms5607
    / # cat /sys/bus/iio/devices/iio:device0/in_temp_input
    21880
    / #