Skip to main content

I2C

1. I2C Subsystem

In the Linux operating system, the I2C subsystem is a critical driver framework for managing and controlling various external devices connected through the I2C bus. More detailed information about the I2C subsystem can be found in the <Linux kernel source>/Documentation/i2c directory. Key components of the I2C subsystem include:

  1. sysfs Interface: The I2C subsystem provides a user-space interface through the sysfs filesystem, allowing users to access and configure information related to I2C devices. The /sys/bus/i2c/devices directory is used to manage and configure the attributes and status of I2C devices. Users can read and write sysfs files to obtain device information or control devices.
  2. I2C Device Nodes: In the /dev directory, character device nodes like /dev/i2c-3 are typically created. These nodes allow users to communicate with specific I2C devices or I2C adapters in user space. Through these nodes, users can send and receive data to operate I2C devices.

2. I2C Testing (Shell)

2.1 Pinout

  • Luckfox Lyra Ultra/Ultra W Pin Diagram:

2.2 View Devices

In the /sys/bus/i2c/devices directory, each I2C device has its own folder. The names of these folders usually contain i2c and the device number, for example, `/sys/bus/i2c/devices/i2c-1 represents the device with I2C bus number 1. If you want to view the I2C buses on the system, you can use the following command:

root@luckfox:~# ls /dev/i2c*
/dev/i2c-2 /dev/i2c-1

2.3 I2C Testing

  1. View devices on the i2c-1 interface.

    i2cdetect -a -y 1

    root@luckfox:/home/luckfox# i2cdetect -a -y 1
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: -- -- -- -- -- -- -- -- -- -- -- -- -- 3d -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
  2. Read the values of all registers of a specific device.

    i2cdump  -f -y 1 0x68
  3. Read a specific register value of a particular I2C device. For example, read register 0x01 from the device at address 0x3d.

    i2cget -f -y 1 0x68 0x01

3. I2C Communication (Python Program)

  1. 完整代码:

    import smbus
    import time

    # I2C Bus (choose 0 or 1 based on your device)
    I2C_BUS = 1

    # Slave device address
    I2C_ADDR = 0x3d

    # Register address (choose according to the register you need)
    REG_ADDR = 0x00 # For example, read the first register's data

    def i2c_read():
    # Create SMBus instance
    bus = smbus.SMBus(I2C_BUS)

    try:
    # Read the register value from the slave device
    data = bus.read_byte_data(I2C_ADDR, REG_ADDR)
    print(f"Data read from device 0x{I2C_ADDR:02x}: 0x{data:02x}")
    except Exception as e:
    print(f"Error reading from device: {e}")
    finally:
    bus.close()

    if __name__ == "__main__":
    i2c_read()
  2. Run the Program:

    root@luckfox:/home/luckfox# python3 i2c_test.py 
    Data read from device 0x3d: 0x41

4. I2C Communication (C Program)

  1. Complete Code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <linux/i2c-dev.h>
    #include <stdint.h>

    #define I2C_BUS "/dev/i2c-1" // I2C Bus (choose i2c-0 or i2c-1 based on your device)
    #define I2C_ADDR 0x3d // Slave device address

    int i2c_read(int file, uint8_t reg_addr) {
    uint8_t buf[1] = {0};

    // Write register address
    if (write(file, &reg_addr, 1) != 1) {
    perror("Failed to write register address");
    return -1;
    }

    // Read data from the slave device
    if (read(file, buf, 1) != 1) {
    perror("Failed to read from device");
    return -1;
    }

    printf("Data read from device 0x%02x: 0x%02x\n", I2C_ADDR, buf[0]);
    return buf[0];
    }

    int main() {
    int file;

    // Open the I2C bus
    if ((file = open(I2C_BUS, O_RDWR)) < 0) {
    perror("Failed to open I2C bus");
    return 1;
    }

    // Set the slave device address
    if (ioctl(file, I2C_SLAVE, I2C_ADDR) < 0) {
    perror("Failed to set I2C address");
    close(file);
    return 1;
    }

    // Read data from register 0x00
    i2c_read(file, 0x00);

    // Close the I2C device
    close(file);

    return 0;
    }

  2. Cross-compile and run the program. To build a cross-compilation environment, please refer to the "Program Compilation" or "GPIO" section.

    arm-none-linux-gnueabihf-gcc i2c_test.c  -o i2c_test

5. Device Tree Overview

  1. The device file path is located inkernel-6.1/arch/arm/boot/dts/rockchip/rk3506g-luckfox-lyra.dts,The following snippet enablesi2c1:

    &i2c1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&rm_io10_i2c1_scl &rm_io11_i2c1_sda>;
    };

    &pinctrl {
    rm_io10 {
    rm_io10_i2c1_scl: rm-io10-i2c1-scl {
    rockchip,pins =
    <0 RK_PB2 32 &pcfg_pull_up>;
    };
    };

    rm_io11 {
    rm_io11_i2c1_sda: rm-io11-i2c1-sda {
    rockchip,pins =
    <0 RK_PB3 33 &pcfg_pull_up>;
    };
    };
    };