一、通过命令 对i2c读写命令
hisi写的,封装的一个app应用程序,做成shell命令,在终端,通过命令 对i2c读写命令, 此操作示例通过 I2C 读写命令
实现对 I2C 外围设备的读写操作。
1、在控制台使用 i2c_read 命令对 I2C 外围设备进行读操作:
i2c_read <i2c_num> <device_addr> <reg_addr> <end_reg_addr><reg_width> <data_width> <reg_step>
i2c_num:I2C 控制器序号(对应《Hi35xx H.265 编解码处理器用户指南》中的 I2C 控制器
device_addr:外围设备地址(Hi35xx 支持标准地址(7bit)和扩展地址(10bit))
reg_addr:读外围设备寄存器操作的开始地址
end_reg_addr:读外围设备寄存器操作的结束地址
reg_width:外围设备的寄存器位宽(Hi35xx 支持 8/16bit)
data_width:外围设备的数据位宽(Hi35xx 支持 8/16bit)
reg_step:连续读外围设备寄存器操作时递增幅值,默认为 1,即连续读寄存器,读取单个寄存
例如读挂载在 I2C 控制器 0 上的 sil9024 设备的 0x8 寄存器:
i2c_read 0 0x72 0x8 0x8 0x1 0x1
2、在控制台使用 i2c_write 命令对 I2C 外围设备进行写操作:
i2c_write <i2c_num> <device_addr> <reg_addr> <value> <reg_width><data_width>
i2c_num:I2C 控制器编号(对应《Hi35xx H.265 编解码处理器用户指南》中的 I2C 控制器
device_addr:外围设备地址(Hi35xx 的 I2C 控制器支持标准地址(7bit)和扩展地址(10bit))
reg_addr:写外围设备寄存器操作的地址
value:写外围设备寄存器操作的数据
reg_width:外围设备的寄存器位宽(Hi35xx 的 I2C 控制器支持 8/16bit)
data_width:外围设备的数据位宽(Hi35xx 的 I2C 控制器支持 8/16bit)
例如向挂载在 I2C 控制器 0 上的 sil9024 设备的 0x8 寄存器写入数据 0xa5:
i2c_write 0 0x72 0x8 0xa5 0x1 0x1
这种方法,适合简单测试
二、此操作示例在用户态下,对 I2C 外围设备的读写操作。
步骤 1.
打开 I2C 总线对应的设备文件,获取文件描述符:
fd = open("/dev/i2c-0", O_RDWR);
步骤 2.
通过 ioctl 设置外围设备地址、外围设备寄存器位宽和数据位宽:
ret = ioctl(fd, I2C_SLAVE_FORCE, device_addr);
ioctl(fd, I2C_16BIT_REG, 0);
ioctl(fd, I2C_16BIT_DATA, 0);
设置寄存器位宽和数据位宽时,ioctl 的第三个参数为 0 表示 8bit 位宽,为 1 表示 16bit 位宽。
步骤 3.
使用 read/wite 进行数据读写:
read(fd, recvbuf, reg_width);
write(fd, buf, (reg_width + data_width));
代码示例如下:
unsigned int reg_width = 1;
unsigned int data_width = 1;
unsigned int reg_step = 1;
HI_RET i2c_read(int argc, char* argv[])
{
int fd = -1;
int ret;
unsigned int i2c_num, device_addr, reg_addr, reg_addr_end;
char data;
char recvbuf[4];
int cur_addr;
memset(recvbuf, 0x0, 4);
fd = open("/dev/i2c-0", O_RDWR);
if (fd<0)
{
printf("Open i2c dev error!\n");
return -1;
}
ret = ioctl(fd, I2C_SLAVE_FORCE, device_addr);
if (reg_width == 2)
ret = ioctl(fd, I2C_16BIT_REG, 1);
else{
ret = ioctl(fd, I2C_16BIT_REG, 0);
if (ret < 0) {
printf("CMD_SET_REG_WIDTH error!\n");
}
close(fd);
return -1;
}
if (data_width == 2)
ret = ioctl(fd, I2C_16BIT_DATA, 1);
else
ret = ioctl(fd, I2C_16BIT_DATA, 0);
if (ret < 0) {
printf("CMD_SET_DATA_WIDTH error!\n");
close(fd);
return -1;
}
for (cur_addr = reg_addr; cur_addr < reg_addr_end + reg_width;cur_addr += reg_step)
{
if (reg_width == 2) {
recvbuf[0] = cur_addr & 0xff;
recvbuf[1] = (cur_addr >> 8) & 0xff;
} else
recvbuf[0] = cur_addr & 0xff;
ret = read(fd, recvbuf, reg_width);
if (ret < 0) {
printf("CMD_I2C_READ error!\n");
close(fd);
return -1;
}
if (data_width == 2) {
data = recvbuf[0] | (recvbuf[1] << 8);
} else
data = recvbuf[0];
printf("0x%x 0x%x\n", cur_addr, data);
}
close(fd);
return 0;
}
HI_RET i2c_write(int argc , char* argv[])
{
int fd = -1;
int ret =0, index = 0;
unsigned int i2c_num, device_addr, reg_addr, reg_value;
char buf[4];
fd = open("/dev/i2c-0", O_RDWR);
if(fd < 0)
{
printf("Open i2c dev error!\n");
return -1;
}
ret = ioctl(fd, I2C_SLAVE_FORCE, device_addr);
if (reg_width == 2)
ret = ioctl(fd, I2C_16BIT_REG, 1);
else
ret = ioctl(fd, I2C_16BIT_REG, 0);
if (data_width == 2)
ret = ioctl(fd, I2C_16BIT_DATA, 1);
else
ret = ioctl(fd, I2C_16BIT_DATA, 0);
if (reg_width == 2) {
buf[index] = reg_addr & 0xff;
index++;
buf[index] = (reg_addr >> 8) & 0xff;
index++;
} else {
buf[index] = reg_addr & 0xff;
index++;
}
if (data_width == 2) {
buf[index] = reg_value & 0xff;
index++;
buf[index] = (reg_value >> 8) & 0xff;
index++;
} else {
buf[index] = reg_value & 0xff;
index++;
}
write(fd, buf, (reg_width + data_width));
if(ret < 0)
{
printf("I2C_WRITE error!\n");
return -1;
}
close(fd);
return 0;
}
三、 i2c-tools 命令测试i2c设备。
工具安装,i2c-tools工具是一个专门调试i2c的,开源,可获取挂载的设备及设备地址,还可以在对应的设备指定寄存器设置值或者获取值等功能。
从开源网站 http://dl.lm-sensors.org/i2c-tools/releases/
下载i2c-tools,
修改makefile文件,交叉编译,直接make,进行编译,安装:sudo make install
编译完成后在tools/文件夹下会有如下几个可执行文件,i2cdetect, i2cdump, i2cget, i2cset,将i2cdetect, i2cdump,
i2cget, i2cset push到设备就可以调试了
二、测试
1、错误认知;
i2c-tools使用之前需要修改设备树和配置相关驱动,其实,只要内核开启,设备树开启相关i2c总线,将设备挂载在硬件上,接上设备即可检测到该总线上i2c芯片。
2、命令介绍:
i2cdetect:检测i2c芯片
i2cdump:查看寄存器值
i2cget:获取单个寄存器值(8位寄存器)
i2cset:设置单个寄存器值(8位寄存器)
i2ctransfer:一次传输多字节数据(16位寄存器)
参数介绍:
-y:禁用交互模式。
-f:强制访问设备。
-r:写入后立即读回该值。
2.1、列出所有可用的i2c总线:i2cdetect -l
上图可以看到,总共注册了8条i2c总线
2.2、检测第7条总线上器件:i2cdetect -r -y 7
1,上面有UU和和数字显示,UU表示此地址已经加载了驱动,具体有没有设备不一定,显示有数字说明探测到设备了,也可能是系统的,不知是谁的。
2,不是所有的i2c设备都能探测到,有些16位寄存器i2c设备无法探测到,可以尝试使用i2ctransfer去尝试读写来判断当前地址是否存在设备;。
另外一种说法:
1、UU表示设备地址的两个从设备已经被驱动占用了,当你卸载掉对应的驱动后,此UU就会变成数据了。
2、数字是,这个地址被芯片使用并应答,dts已经配置了,但是没有加载驱动。
2.3、查看器件所有寄存器的值:i2cdump -f -y i2c总线 器件地址
列出所有存在的寄存器的值,如0x00=71,0x01=73,以此类推。
2.4 、获取单个寄存器的值:i2cget -y -f i2c总线 器件地址
读取i2c4总线上的,设备地址为0x4c的设备,寄存器0x00的值,为0x71
2.5、设置单个寄存器的值:i2cset -y -f i2c总线 器件地址
如图写0xa0的值
三、测试i2ctransfer
i2cdump、i2cget、i2cset只适用于读写8位的寄存器地址, 功能完全可由i2ctransfer代替
1、i2ctransfer写
如:i2ctransfer -f -y 1 w3@0x36 0x50 0x81 0x01
0x36为I2C设备的地址, 0x5081为要写的寄存器地址, 0x01为写入的值。
2、i2ctransfer读
i2ctransfer -f -y 1 w2@0x36 0x30 0x0A r3
0x36为I2C设备的地址, 0x300A为要读的寄存器地址, r3为连续读3Byte, 0x56 0x08 0x41 为读到的寄存器的值。
文章摘抄学习来自:https://blog.youkuaiyun.com/weixin_35367646/article/details/116593331