5. I2C操作指南

5.1. 操作准备

I2C的操作准备如下:

  • 使用SDK发布的kernel。

5.2. 操作过程

  • 加载内核。默认I2C相关模块已全部编入内核,不需要再执行加载命令。

  • 在控制台下运行I2C读写命令或者自行在内核态或者用户态编写I2C读写程序,就可以对挂载在I2C控制器上的外围设备进行读写操作。

5.3. 接口速率设置说明

如果要更改接口速率,需要修改build/boards/default/dts/cv180x/cv180x_base.dtsi或

build/boards/default/dts/cv181x/cv181x_base.dtsi中i2c node里的clock_frequency,如下所示,并重新编译内核。

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. I2C读写命令示例:

可在linux终端上发iic相关命令detect总线设备和对总线上i2c设备进行读写。

  1. i2cdetect -l

检测系统中的iic总线(在cv180x中可为i2c-0, i2c-1,i2c-2,i2c-3,i2c-4)

  1. i2cdetect -y -r N 检测接到i2c-N总线上的所有设备地址,如下检测i2c-2上有哪些设备:

_images/I2COpe002.png
  1. i2cdump -f -y N M 查看i2c-N上地址为M的设备中所有寄存器的值

  2. i2cget -f -y 0 0x3c 0x00//读取i2c-0上地址为0x3c的设备上0x00寄存器的值

  3. i2cset -f -y 0 0x3c 0x40 0x12//写入i2c-0上地址为0x3c的设备上0x40寄存器

5.3.2. 内核态I2C读写程序示例:

此示例说明在内核态下如何通过I2C读写程序对I2C外围设备进行读写操作。

步骤 1. 假设已知外围设备挂载在I2C控制器0上,调用i2c_get_adapter()函数以获得I2C控制器结构体 adapter:

adapter = i2c_ger_adapter(0);

步骤 2. 透过i2c_new_device()函数关连I2C控制器与I2c外围设备,以得到I2C外围设备的客户端结构体 client:

client = i2c_new_device(adapter, &info)

备注:info结构体提供i2c外围设备的设备地址

步骤 3. 调用I2C核心层提供的标准读写函数对外围设备进行读写操作:

ret = i2c_master_send(client, buf, count);

ret = i2c_master_recv(client, buf, count);

备注:client为步骤2所得之客户端结构体,buf为需要读写的寄存器地址以及数据,count为buf的长度。

代码示例如下:

//宣告一个外围设备名字叫做”dummy”,设备地址为0x3c
static struct i2c_board_info info = {
               I2C_BOARD_INFO("dummy", 0x3C),
};
static struct i2c_client *client;

static int cvi_i2c_dev_init(void) {
   //分配 i2c控制器指针
   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读写程序示例:

此操作示例在用户态下通过I2C读写程序实现对I2C外围设备的读写操作。

步骤 1. 打开I2C总线对应的设备文件,获取文件描述符:

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

步骤 2.
进行数据读写:
ret = ioctl(file, I2C_RDWR, &packets);
   if (ret < 0) {
      perror("Unable to send data");
      return ret;
   }

备注:需于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;