5. I2C Operation Guide

5.1. Operation Preparation

I2C is prepared for operation as follows:

  • Use the kernel released by SDK。

5.2. Operation Process

  • Load the kernel. The default I2C-related modules are all built into the kernel, and no install commands need to be executed.

  • The I2C devices mounted on the I2C controller can be read and written by running the I2C read and write command under the console or by writing the I2C read and write program in kernel or user mode.

5.3. Interface Rate Setting Instructions

If you want to change the interface rate, you need to modify the “clock_frequency” of i2c node in build/boards/default/dts/cv180x/cv180x_base.dtsi or

build/boards/default/dts/cv181x/cv181x_base.dtsi, and recompile the kernel.

i2c0: i2c@04000000 {
   compatible = "snps,designware-i2c";
   clocks = <&clk CV180X_CLK_I2C>;
   reg = <0x0 0x04000000 0x0 0x1000>;
   clock-frequency = <400000>;

   #size-cells = <0x0>;
   #address-cells = <0x1>;
   resets = <&rst RST_I2C0>;
   reset-names = "i2c0";
};

5.3.1. Examples of I2C Read and Write Commands:

You can send relevant iic commands in linux terminal to detect bus devices and read or write the i2c devices in bus.

  1. i2cdetect -l

    Detect iic buses in system. (It can be i2c-0, i2c-1,i2c-2,i2c-3,i2c-4 in cv180x)

  2. i2cdetect -y -r N

    Detect all the address of devices which are connected with i2c-N bus. The example below is used detect devices which are connected with i2c-2 bus.

_images/I2COpe002.png
  1. i2cdump -f -y N M

    View the values of all registers in the device with address M on i2c-N

  2. i2cget -f -y 0 0x3c 0x00//

    Reads the value of register 0x00 on a device at address 0x3c on i2c-0

  3. i2cset -f -y 0 0x3c 0x40 0x12//

    Write to register 0x40 on device at address 0x3c on i2c-0

5.3.2. I2C Read-Write Program Example with Kernel Mode:

This example demonstrates how to read and write I2C device in the kernel space.

Step 1. Assuming that the I2C device is known to be mounted on I2C controller 0, call i2c_get_adapter() function to get the I2C controller structure adapter:

adapter = i2c_ger_adapter(0);

Step 2. Through i2c_new_device() function to associate the I2C controller with the I2c device to obtain the client structure of the I2C device:

client = i2c_new_device(adapter, &info)

Note: The info structure provides the device address for i2c

Step 3. Call the standard read and write functions provided by the I2C core layer to read and write to device:

ret = i2c_master_send(client, buf, count);

ret = i2c_master_recv(client, buf, count);

Note: Client is the client structure obtained in step 2, buf is the register address and data to be read and written, count is the length of buf.

The code example is as follows:

// Announce a I2C device named "dummy" with device address 0x3c
static struct i2c_board_info info = {
      I2C_BOARD_INFO("dummy", 0x3C),
};
static struct i2c_client *client;

static int cvi_i2c_dev_init(void) {
// Assign I2C Controller Pointer
struct i2c_adapter *adapter;

adapter = i2c_get_adapter(0);
client = i2c_new_device(adapter, &info);
i2c_put_adapter(adapter);
return 0;
}

static int i2c_dev_write(char *buf, unsigned int count) {
int ret;

    ret = i2c_master_write(client, buf, count);
    return ret;
}

static int i2c_dev_read(char *buf, unsigned int count) {
int ret;

    ret = i2c_master_recv(client, buf, count);
    return ret;
}

5.3.3. I2C Read-Write Program Example with User Mode:

This operation example reads and writes I2C device through the I2C reader in the user space.

Step 1. Open the device file corresponding to the I2C bus and get the file descriptor:

i2c_file = open("/dev/i2c-0", O_RDWR);
   if (i2c_file < 0) {
      printf("open I2C device failed %d\n", errno);
      return -ENODEV;
   }

Step 2. Read and write data:

ret = ioctl(file, I2C_RDWR, &packets);
   if (ret < 0) {
      perror("Unable to send data");
      return ret;
   }

Note: Read and write operations need to be specified on flags

struct i2c_msg messages[2];
   int ret;

   /*
    * In order to read a register, we first do a "dummy write" by writing
    * 0 bytes to the register we want to read from.  This is similar to
    * the packet in set_i2c_register, except it's 1 byte rather than 2.
    */
   outbuf = reg;
   messages[0].addr = addr;
   messages[0].flags = 0;
   messages[0].len = sizeof(outbuf);
   messages[0].buf = &outbuf;

   /* The data will get returned in this structure */
   messages[1].addr = addr;
   /* | I2C_M_NOSTART */
   messages[1].flags = I2C_M_RD;
   messages[1].len = sizeof(inbuf);
   messages[1].buf = &inbuf;