Linux上的`i2c-tools`工具集的详细介绍;并利用它操作IMX6ULL的I2C控制器进而控制芯片AP3216C读取光照值和距离值
I²C-Tools 工具集介绍
i2c-tools
是 Linux 下用于 I²C 设备调试 的用户空间工具集(你也可以把它看成是一个库,类似于之前自己用过的触摸屏库tslib库、FreeType矢量字符库),它提供了一系列命令行工具,可以扫描、读取、写入 I²C 设备,非常适合嵌入式开发和调试 I²C 设备,如 传感器、EEPROM、GPIO 扩展器 等。
1. i2c-tools
的主要工具
i2c-tools
工具集主要包含以下几个命令:
命令 | 作用 |
---|---|
i2cdetect | 扫描 I²C 总线,查找可用的设备地址 |
i2cdump | 读取 I²C 设备的全部寄存器数据 |
i2cget | 读取 I²C 设备某个寄存器的数据 |
i2cset | 向 I²C 设备某个寄存器写入数据 |
i2ctransfer | 发送更复杂的 I²C 读/写命令 |
2. i2c-tools
详细命令解析
(1)i2cdetect — 扫描 I²C 设备
功能
扫描 I²C 总线上的设备,显示哪些地址上有响应的 I²C 设备。
使用示例
i2cdetect -y 1
- 扫描 I²C 总线 1,并显示已连接设备的地址。
输出示例
0 1 2 3 4 5 6 7 8 9 A B C D E F
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77
48
和77
代表有设备响应。--
代表该地址无设备响应。
(2)i2cdump — 读取 I²C 设备所有寄存器
功能
读取 I²C 设备的全部寄存器内容,适用于调试寄存器数据。
使用示例
i2cdump -y 1 0x50
- 读取 I²C 总线 1 上 0x50 地址 设备的寄存器数据。
输出示例
0 1 2 3 4 5 6 7 8 9 A B C D E F
00: 12 34 56 78 90 AB CD EF 12 34 56 78 90 AB CD EF
10: 12 34 56 78 90 AB CD EF 12 34 56 78 90 AB CD EF
...
- 以 16 进制格式显示 I²C 设备的寄存器内容。
(3)i2cget — 读取单个寄存器
功能
读取 I²C 设备某个寄存器 的值。
使用示例
i2cget -y 1 0x50 0x10
- 读取 I²C 总线 1 上 0x50 设备 0x10 寄存器 的值。
输出示例
0xAB
- 说明 0x10 地址 处的值是
0xAB
。
(4)i2cset — 写入 I²C 设备寄存器
功能
向 I²C 设备某个寄存器 写入数据。
使用示例
i2cset -y 1 0x50 0x10 0xAB
- 向 I²C 总线 1 上 0x50 设备 0x10 寄存器 写入
0xAB
。
写入多字节
i2cset -y 1 0x50 0x10 0x12 0x34 i
- 以 I²C block 模式 写入
0x12 0x34
。
(5)i2ctransfer — 复杂 I²C 读/写
功能
因为i2ctransfer
是比较底层的命令,所以它灵活,所以它允许更复杂的 I²C 数据传输,例如:
- 一次性读/写多个字节
- 自定义 I²C 消息格式
- 精确控制 I²C 事务
写入 2 字节
i2ctransfer -y 1 w2@0x50 0x10 0xAB
- 向
0x50
设备 0x10 寄存器 写入 2 字节数据0xAB
。
读取 2 字节
i2ctransfer -y 1 r2@0x50
- 从 0x50 设备 读取 2 字节 数据。
3. i2c-tools
安装到Linux系统
在大多数 Linux 发行版中可以直接安装:
- Debian/Ubuntu
sudo apt install i2c-tools
- CentOS/RHEL
sudo yum install i2c-tools
- Yocto
在local.conf
添加:IMAGE_INSTALL_append = " i2c-tools "
- IMX6ULL_PRO等嵌入式开发板
和tslib库的安装类似,先在Ubuntu中编译出库文件,然后把相关文件复制到IMX6ULL_PRO嵌入式开发板上,同时还要把相关的头文件复制到交叉编译器的头文件搜索目录中,这些这程可参考tslib库的安装,相关博文 https://blog.csdn.net/wenhao_ir/article/details/144621008 【搜索“tslib的交叉编译”,然后开始看】
由于很多芯片的官方BSP都集成了i2c-tools
库,所以需要自己去编译安装i2c-tools
的时间不多,所以这里我就不去尝试自己编译安装了。
4. 查看自己的两个开发板的Linux系统中是否有i2c-tools
先说明一下,直接运行命令i2cdetect
,如果有提示这个命令怎么用,那么就证明当前Linux系统中已经集成了i2c-tools
。
i2cdetect
上面的运行结果表明当前Linux系统中已经集成了i2c-tools
。
IMX6ULL_PRO开发板出厂提供的Linux系统中包含有i2c-tools
1号开发板是开发板商出厂时提供的Linux内核和设备树文件。
在1号开发板上运行命令i2cdetect
的结果如下:
这证明IMX6ULL_PRO开发板出厂提供的Linux系统中包含有i2c-tools
。
NXP官方提供的BSP中包含有i2c-tools
2号开发板是我自己用NXP官方提供的BSP移植的Linux内核和设备树文件。
在2号开发板上运行命令i2cdetect
的结果如下:
这证明NXP官方提供的BSP中包含有i2c-tools
。
5. 小结
✔ i2c-tools
是 Linux 下的 I²C 调试工具集,适用于嵌入式设备调试。
✔ 提供 设备扫描、数据读取、数据写入 等命令:
i2cdetect
:扫描 I²C 设备。i2cdump
:读取设备所有寄存器。i2cget
:读取单个寄存器。i2cset
:写入单个寄存器。i2ctransfer
:高级 I²C 操作。
✔ 在 IMX6ULL 开发板、树莓派等嵌入式 Linux 设备上广泛使用。
i2c-tools
工具集使用的前提:存在相关的I2C控制器的设备文件
首先需要Linux的I2C子系统提供了相关的I2C控制器的设备文件。我猜 i2c-tools
也会像tslib那样去扫描获取相关的设备文件。我们可以用下面的命令查看系统的I2C子系统提供的I2C控制器的设备文件。
ls /dev/i2c-*
运行结果如下:
i2c-tools
在工作运行时,就会扫描获取到这两个I2C控制器的设备文件,然后用这两个设备文件进行相关操作。设备文件的名字末尾的数字就是i2c-tools
各命令中需要的I2C控制器的编号。
i2c-tools
工具集所使用的协议:SMBus协议和I2C协议
i2c-tools
工具集有部分命令是基于SMBus协议,有部分命令是基于SMBus协议。不过由于SMBus协议是I2C协议的子集,所以只要设备是I2C设备,就可以运行SMBus协议。
SMBus协议的详细介绍见博文 https://blog.csdn.net/wenhao_ir/article/details/146336623
检测扫描命令i2cdetect
的实操记录
查看当前Linux系统中有多少个I2C控制器
1号开发板的运行结果
可以用下面的命令来查看当前Linux系统中有多少个I2C控制器及各自的基本信息:
i2cdetect -l
[root@imx6ull:~]# i2cdetect -l
i2c-1 i2c 21a4000.i2c I2C adapter
i2c-0 i2c 21a0000.i2c I2C adapter
可见,有两个,其实IMX6ULL芯片上一共也只有两个I2C控制器,它们的设备文件名分别为i2c-1、i2c-0,它们被命令名I2C adapter,它们各自的内存地址为21a4000、21a0000。
2号开发板的运行结果
i2cdetect -l
检测某个I2C控制器上有哪些设备
编号为0的I2C控制器上的设备
1号开发板的运行结果
假设现在我要检测编号为0的I2C控制器上是否有设备,那么运行下面这条命令即可:
i2cdetect 0
运行之后会提示你这个操作可能会干扰该条I2C总线上目前正在工作的I2C设备,因为它要发送各设备的地址,然后让设备得到回应嘛。我们回答y
就是了。
当然你也可像下面这样写:
i2cdetect -y 0
这样就可以屏蔽命令运行过程中的交互,也就不用需要回答y了。
这个结果说明,在0x1e的地址上,有一个I2C设备,但是在内核中还不存在这个设备的驱动程序,所以显示为其地址值,如果在内核中存在这个设备的驱动程序,那么应该显示为UU
,如下图所示:
这里顺便说一下,地址为0x1e的I2C设备其实是芯片AP3216C,它能进行光照强度测量和距离检测、并且通信接口为I2C,它的详细介绍见博客 https://blog.csdn.net/wenhao_ir/article/details/146326884
2号开发板的运行结果
i2cdetect 0
编号为1的I2C控制器上的设备
1号开发板的运行结果
按照上面的方法,我们再顺便检测下编号为1的I2C控制器上的设备:
i2cdetect 1
可见,编号为1的I2C控制器上有四个设备,地址分别为0x1a、0x39、0x5d、0x60,前三个设备在内核中是有驱动程序的,最后一个地址为0x60的设备是在内核中没有驱动程序的。
2号开发板的运行结果
i2cdetect 1
1号开发板和2号开发板运行结果的分析
1号开发板是开发板商出厂时提供的Linux内核和设备树文件。
2号开发板是我自己用NXP官方提供的BSP移植的Linux内核和设备树文件。
这说明NXP官方提供的BSP里已经包含了IMX6ULL的I2C控制器的底层驱动,并且接入了Linux的I2C子系统。一旦一个I2C控制器被正确启用并被接入Linux的I2C子系统,那么就能使用i2c-tools
工具集检测并操作相关I2C总线上的I2C设备了。
写入数据命令i2cset
的格式的详解
可以直接在命令行中输入命令i2cset
来查看其格式:
i2cset
运行结果如下:
详细介绍如下:
i2cset
是 Linux 命令行工具,用于向 I²C 设备的寄存器写入数据。它属于 i2c-tools
工具集,常用于调试 I²C 设备。
1. 基本语法
i2cset [-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]
其中:
BUS
:I²C 总线号,通常对应/dev/i2c-X
设备中的X
。CHIP-ADDRESS
:I²C 设备地址(7 位地址,范围0x03
到0x77
)。DATA-ADDRESS
:要写入数据的寄存器地址(从设备内部的寄存器)。VALUE
(可选):要写入的数值。如果MODE
允许多个值,则可以写入多个数据。MODE
(可选):数据的传输模式(见下文)。- 额外的 选项(如
-f
、-y
)可用于控制操作方式。
2. 选项说明
-f
:强制访问设备,即使它可能正在使用(风险较高,谨慎使用)。-y
:禁用交互模式,不再要求用户确认写入(默认情况下会有提示以防误操作)。-r
:在写入后读取并比较结果(用于确认写入是否成功)。-m MASK
:使用掩码选择要写入的特定位。例如-m 0xF0
仅修改高 4 位,低 4 位保持不变。
3. MODE
参数
MODE
指定数据写入的方式,支持以下几种:
MODE | 说明 |
---|---|
c | 只写数据地址,不写入任何数据(通常用于触发某些设备的操作)。 |
b | 写入 1 字节(默认模式)。 |
w | 写入 2 字节(word)。 |
i | 以 I²C 块数据 方式写入多个字节(I²C block write)。 |
s | 以 SMBus 块数据 方式写入多个字节(SMBus block write)。 |
p | 追加 p 启用 SMBus 的 PEC(Packet Error Checking)校验。 |
4. 示例
#(1)写入一个字节
i2cset -y 1 0x50 0x10 0xAB
- 在 I²C 总线
1
上,向地址0x50
的设备写入数据:0x10
作为寄存器地址。0xAB
作为要写入的数据(默认b
模式,即 1 字节)。
#(2)写入 2 字节(word)
i2cset -y 1 0x50 0x10 0x1234 w
- 向
0x50
设备的0x10
寄存器写入0x1234
(2 字节)。
#(3)写入 SMBus 块数据
i2cset -y 1 0x50 0x10 0x01 0x02 0x03 s
- 向
0x50
设备0x10
寄存器写入0x01 0x02 0x03
(SMBus block write)。
#(4)使用掩码修改部分位
i2cset -y -m 0xF0 1 0x50 0x10 0xAB
- 仅修改
0x10
寄存器的高 4 位(0xF0
掩码)。
5. 注意事项
- 确保设备地址正确,误操作可能会影响 I²C 总线上的其他设备。
- 使用
-y
选项时要谨慎,否则i2cset
可能直接写入数据而不提示确认。 - 强制写入
-f
有风险,可能导致总线冲突或设备异常。
读数据命令i2cget
的格式的详解
可以直接在命令行中输入命令i2cset
来查看其格式:
i2cget
运行结果如下:
详细介绍如下:
i2cget
是 i2c-tools
工具集中的一个命令,用于读取 I²C 设备的寄存器数据。
🔹 语法解析
i2cget [-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]
参数 | 含义 |
---|---|
BUS | I²C 控制器编号(总线编号),比如 0 、1 ,可以通过 i2cdetect -l 查看 |
CHIP-ADDRESS | I²C 设备地址(7 位地址),通常在 0x03 ~ 0x77 之间 |
DATA-ADDRESS | 要读取的寄存器地址(可选),如果省略,则直接读取设备数据 |
MODE | 读取模式(可选),默认为 b (字节读取) |
🔹 选项说明
选项 | 作用 |
---|---|
-f | 强制访问 I²C 设备(忽略内核的安全检查) |
-y | 关闭交互模式,直接执行操作而不要求用户确认 |
🔹 读取模式
模式 | 含义 |
---|---|
b | 读取 1 字节数据(默认) |
w | 读取 2 字节(16-bit word)数据 |
c | 先写 1 字节数据,再读取 1 字节数据(适用于某些设备) |
p | 附加 SMBus PEC(Packet Error Checking)错误检测 |
🔹 示例
#✅ 1. 读取设备的整个数据(无指定寄存器)
i2cget -y 1 0x1E
- 读取 I²C 设备地址
0x1E
的数据(不指定寄存器)。 -y
选项表示不提示用户确认。
#✅ 2. 读取 AP3216C 传感器 0x00 寄存器的值
i2cget -y 1 0x1E 0x00
- 读取 设备
0x1E
的0x00
号寄存器(系统配置寄存器)。
#✅ 3. 读取 16-bit(word)数据
i2cget -y 1 0x1E 0x0C w
- 读取 设备
0x1E
的0x0C
号寄存器 的 16-bit 数据。 - 适用于返回 2 字节(word)的设备,如某些传感器。
#✅ 4. 先写 1 字节数据,再读取 1 字节数据
i2cget -y 1 0x1E 0x00 c
- 先写
0x00
到设备0x1E
,然后读取 1 字节数据。 - 适用于某些 需要寄存器索引 的设备。
🔹 小结
i2cget
用于从 I²C 设备的寄存器读取数据。- 默认读取 1 字节(可选
w
读取 2 字节)。 -f
强制访问,-y
关闭交互模式。- 可以配合
i2cset
进行写入操作。
使用读写命令行对I2C设备AP3216C进行读写操作
AP3216C是能进行光照强度测量和距离检测、并且通信接口为I2C的芯片,它的详细介绍见博客 https://blog.csdn.net/wenhao_ir/article/details/146326884
当它通过I2C挂接到我们的Linux系统的I2C总线上后,我们例可以用I2C总线对它进行读写操作了。在这里,我们用i2c-tools
工具集的命令对它进行读写操作,从而利用AP3216C读出光照强度和距离值。
第01条命令-写数据:软复位AP3216C
i2cset -f -y 0 0x1e 0 0x4
前面已经详细介绍了命令i2cset
,这里就不再详细赘述。
-f
:表示强制访问设备,即使它可能正在使用。
-y
:禁用交互模式,不再要求用户确认写入(默认情况下会有提示以防误操作)。
第1个0
:表示使用第0个I2C控制器,也可以看成是I2C总线的编号嘛。
0x1e
:表示AP3216C这个I2C设备的地址。
第2个0
:表示AP3216C中要写入数据的寄存器地址。
0x4
:表示写入的值为0x4
,表示软复位AP3216C。
关于AP3216C的0号寄存器的详细介绍见博文 https://blog.csdn.net/wenhao_ir/article/details/146326884
第02条命令-写数据:启用AP3216C的光感和距离检测功能
i2cset -f -y 0 0x1e 0 0x3
前面已经详细介绍了命令i2cset
,这里就不再详细赘述。
-f
:表示强制访问设备,即使它可能正在使用。
-y
:禁用交互模式,不再要求用户确认写入(默认情况下会有提示以防误操作)。
第1个0
:表示使用第0个I2C控制器,也可以看成是I2C总线的编号嘛。
0x1e
:表示AP3216C这个I2C设备的地址。
第2个0
:表示AP3216C中要写入数据的寄存器地址。
0x3
:表示写入的值为0x3
,表示“ALS and PS+IR functions active”,即把AP3216C的ALS (Ambient Light Sensor)光感和Proximity (接近传感器) 都激活。
关于AP3216C的0号寄存器的详细介绍见博文 https://blog.csdn.net/wenhao_ir/article/details/146326884
第03条命令-读取光照强度数据
i2cget -f -y 0 0x1e 0x0c w
前面已经详细介绍了命令i2cget
,这里就不再详细赘述。
-f
:表示强制访问设备,即使它可能正在使用。
-y
:禁用交互模式,不再要求用户确认写入(默认情况下会有提示以防误操作)。
第1个0
:表示使用第0个I2C控制器,也可以看成是I2C总线的编号嘛。
0x1e
:表示AP3216C这个I2C设备的地址。
0x0c
:表示要读取AP3216C中的目标寄存器的地址。
w
:表示读取一个字,即两个字节的值。
关于AP3216C的0x0c号寄存器的详细介绍见下面这张截图:
由于我们附加了参数w
,所以这里其实我们这里读取的是0x0c和0x0d寄存器的值。
读取的结果如下:
我们再用手电筒照向这个芯片,然后再读这个值,看有没有变化:
可见,值从0x0000变成了0x24e2。
第04条命令-读取距离值
i2cget -f -y 0 0x1e 0x0e w
前面已经详细介绍了命令i2cget
,这里就不再详细赘述。
-f
:表示强制访问设备,即使它可能正在使用。
-y
:禁用交互模式,不再要求用户确认写入(默认情况下会有提示以防误操作)。
第1个0
:表示使用第0个I2C控制器,也可以看成是I2C总线的编号嘛。
0x1e
:表示AP3216C这个I2C设备的地址。
0x0e
:表示要读取AP3216C中的目标寄存器的地址。
w
:表示读取一个字,即两个字节的值。
关于AP3216C的0x0e号寄存器的详细介绍见下面这张截图:
其中第7位和第6位的详细说明见博文 https://blog.csdn.net/wenhao_ir/article/details/146326884 【搜索“其中第7位(Object detect)”】
由于我们附加了参数w
,所以这里其实我们这里读取的是0x0e和0x0f寄存器的值。
读取的结果如下:
这个值我们得转换成二进制然后翻译一下:
0xb18d = 0b 10110001 10001101
所以PS_Data_Low的值为 1000 1101,分析如下:
PS_Data_Low[7]的值为1,代表“The object closed”,意思是物体在检测范围内,PS_Data_Low[6]的值为0,代表数据有效。PS_Data_Low[3:0]代表测量出的距离值的低4位,具体的值为0b1101
。
所以PS_Data_High的值为 1011 0001,分析如下:
PS_Data_High[7]的值为1,代表“The object closed”,意思是物体在检测范围内,PS_Data_High[6]的值为0,代表数据有效。PS_Data_High[5:0]代表测量出的距离值的高6位,具体的值为0b11 0001
。
把PS_Data_Low[3:0]和PS_Data_High[7]的值组合起来为:
0b11 0001 1101
= 0d797
现在我用我的手指靠近AP3216C,再去读PS_Data寄存器的值,结果如下:
可见值变成了0xbf8f
= 0b10111111 10001111
此时把PS_Data_Low[3:0]和PS_Data_High[7]的值组合起来为:
0b1111111111
= 1023 ,因为我的指头几乎快挨着AP3216C了,所以距离值变了最大值1023,可见,对于AP3216C,距离越近,传感得到的距离值越大。