在嵌入式开发仲,有时候需要确认硬件是否正常连接,设备是否正常工作,设备的地址是多少等等,这里我们就需要使用一个用于测试I2C总线的工具——i2c-tools。
i2c-tools工具是一个专门调试i2c的,开源,可获取挂载的设备及设备地址,还可以读写I2C设备寄存器。
下面我们就对这个工具的安装和使用做个简单介绍。
i2c-tools安装下载地址:https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/。本文使用的是4.3版本。
解压下载完成后,放到linux环境下解压。
tar -zxvf i2c-tools-4.3.tar.gz
cd i2c-tools-4.3
编译
使用以下命令进行编译
make CC=arm-linux-gnueabihf-gcc USE_STATIC_LIB=1
USE_STATIC_LIB 的意思是使用静态编译。编译完成后,会在tools目录下产生i2cdetect,i2cdump,i2cget,i2cset,i2ctransfer五个产物。将这些可执行文件拷贝到设备上。
i2c-tools使用方法 i2cdetect不加 USE_STATIC_LIB 编译选项,会使用动态链接的方式编译。编译完成后需要拷贝i2c-tools-4.3/lib 目录下的libi2c.so.0动态库到设备上的/usr/bin 目录下。
i2cdetect用來列举I2C bus和上面所有的设备,可接受的参数有
Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
i2cdetect -F I2CBUS
i2cdetect -l
I2CBUS is an integer or an I2C bus name
If provided, FIRST and LAST limit the probing range.
-V:输出当前版本号
debian@npi:/mnt/mnt$ ./i2cdetect -V
i2cdetect version 4.3
-l:输出所有 i2c 总线,如下总线编号有twi1和twi2,或者1和2
debian@npi:/mnt/mnt$ ./i2cdetect -l
i2c-0 unknown 21a0000.i2c N/A
i2c-1 unknown 21a4000.i2c N/A
debian@npi:/mnt/mnt$ ls -l /dev/i2c-*
crw------- 1 root root 89, 0 Mar 19 09:42 /dev/i2c-0
crw------- 1 root root 89, 1 Mar 19 09:42 /dev/i2c-1
I2CBUS:i2c总线编号
-F:此 i2c 支持的功能
root@npi:/mnt/mnt# ./i2cdetect -F 1
Functionalities implemented by /dev/i2c-1:
I2C yes
SMBus Quick Command yes
SMBus Send Byte yes
SMBus Receive Byte yes
SMBus Write Byte yes
SMBus Read Byte yes
SMBus Write Word yes
SMBus Read Word yes
SMBus Process Call yes
SMBus Block Write yes
SMBus Block Read yes
SMBus Block Process Call no
SMBus PEC yes
I2C Block Write yes
I2C Block Read yes
root@npi:/mnt/mnt#
-y:指令执行自动yes,否则会提示确认执行Continue? [Y/n] Y,不加参数y会有很多执行提示,可以帮助判断
-a:输出总线上所有地址(00-7f),没有 -a,只显示 08-77,UU 表示该设备在驱动中已使用。
如下0x1a,0x39的地址正在被使用。
root@npi:/mnt/mnt# ./i2cdetect -a 1
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-1.
I will probe address range 0x00-0x7f.
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- UU -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
root@npi:/mnt/mnt# ./i2cdetect -y -a 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- UU -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
root@npi:/mnt/mnt#
i2cdump
i2cdump读取设备上所有寄存器的值,可接受的参数有
Usage: i2cdump [-f] [-y] [-r first-last] [-a] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77, or 0x00 - 0x7f if -a is given)
MODE is one of:
b (byte, default)
w (word)
W (word on even register addresses)
s (SMBus block)
i (I2C block)
c (consecutive byte)
Append p for SMBus PEC
-V:输出当前版本号
-f:强制使用此设备地址,即使此设备地址已经被使用;若不添加此参数,地址可能写失败
-y:指令执行自动 yes,否则会提示确认执行Continue? [Y/n] Y,不加参数y会有很多执行提示,可以帮助判断
-r:读取从 first-last 之间的寄存器值
-a:读取0x00-0xff范围的地址
I2CBUS:i2c总线编号
ADDRESS:设备地址,建议使用十六进制
MODE:数据长度类型
root@npi:/mnt/mnt# ./i2cdump -f -y -a 1 0x39
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 00 00 00 00 00 00 00 00 70 00 00 00 00 00 00 00 ........p.......
10: 00 00 00 00 00 00 00 00 00 00 10 b0 02 03 02 00 ..........?????.
20: 95 00 00 00 00 00 40 00 00 00 00 fb ff dd c4 00 ?.....@....?.??.
30: 00 00 00 00 00 00 90 22 a0 00 00 00 01 10 00 00 ......?"?...??..
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
60: 04 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ??..............
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 .............?..
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
b0: 00 00 00 00 00 00 00 00 00 77 14 76 01 00 01 00 .........w?v?.?.
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
# 只读取0x50-0x7f寄存器范围的值
root@npi:/mnt/mnt# ./i2cdump -f -y -r 0x50-0x7f 1 0x39
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
60: 04 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ??..............
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 .............?..
root@npi:/mnt/mnt#
通过读取i2c设备寄存器的值与芯片手册的值进行比对,确认我们配置的是否正确。
i2cgeti2cget读取设备上寄存器的值,可接受的参数有
Usage: i2cget [-f] [-y] [-a] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77, or 0x00 - 0x7f if -a is given)
MODE is one of:
b (read byte data, default)
w (read word data)
c (write byte/read byte)
Append p for SMBus PEC
I2CBUS:i2c总线编号
CHIP-ADDRESS:设备地址
DATA-ADDRESS:要读取的寄存器地址
MODE:数据长度类型
# 0x39设备地址,0x04要读取的寄存器
root@npi:/mnt/mnt# ./i2cget -f -y 1 0x39 0x04
0x03
i2cset
i2cset设置设备上寄存器的值,可接受的参数有
Usage: i2cset [-f] [-y] [-m MASK] [-r] [-a] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77, or 0x00 - 0x7f if -a is given)
MODE is one of:
c (byte, no value)
b (byte data, default)
w (word data)
i (I2C block data)
s (SMBus block data)
Append p for SMBus PEC
I2CBUS:i2c总线编号
CHIP-ADDRESS:设备地址
DATA-ADDRESS:要写入的寄存器地址
VALUE:要写入的值
MODE:数据长度类型
root@npi:/mnt/mnt# ./i2cset -f -m 0xff -r 1 0x39 0x04 0x03
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will write to device file /dev/i2c-1, chip address 0x39,
data address 0x04, data 0x03 (masked), mode byte.
Continue? [Y/n] y
Old value 0x00, write mask 0xff, will write 0x03
Continue? [Y/n] y
Value 0x03 written, readback matched
root@npi:/mnt/mnt#
把写入寄存器的值读出来。确认与我们写入的值相同。
root@npi:/mnt/mnt# ./i2cdump -f -y -r 0x00-0x0f 1 0x39
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 00 00 00 00 03 00 00 00 70 00 00 00 00 00 00 00 ....?...p.......
root@npi:/mnt/mnt#
i2ctransfer
i2ctransfer通过一次传输发送用户定义的I2C消息,用于创建I2C消息并将其作为一次传输合并发送。
Usage: i2ctransfer [-f] [-y] [-v] [-V] [-a] I2CBUS DESC [DATA] [DESC [DATA]]...
I2CBUS is an integer or an I2C bus name
DESC describes the transfer in the form: {r|w}LENGTH[@address]
1) read/write-flag 2) LENGTH (range 0-65535) 3) I2C address (use last one if omitted)
DATA are LENGTH bytes for a write message. They can be shortened by a suffix:
= (keep value constant until LENGTH)
+ (increase value by 1 until LENGTH)
- (decrease value by 1 until LENGTH)
p (use pseudo random generator until LENGTH with value as seed)
Example (bus 0, read 8 byte at offset 0x64 from EEPROM at 0x50):
# i2ctransfer 0 w1@0x50 0x64 r8
Example (same EEPROM, at offset 0x42 write 0xff 0xfe ... 0xf0):
# i2ctransfer 0 w17@0x50 0x42 0xff-
I2CBUS:i2c总线编号
DESC:{r | w}
<消息长度>[@设备地址]
-
{r | w}
指定消息是读还是写 -
<消息长度>指定在此消息中读取或写入的字节数。它被解析为一个无符号的16位整数
-
[@设备地址]指定此消息要访问的芯片的7位地址,并且是整数。
#参数2为i2c2,w2表示写两个字节,@0x39为i2c设备(注意要7位地址),0x02 0xd3 为高低位地址,r1为读取的数据是一个byte。
root@npi:/mnt/mnt# ./i2ctransfer -f -y 1 w2@0x60 0x02 0xd3 r1
0x00
总结
本文只是抛砖引玉,i2c-tools还有更多的使用方法,需要大家在实际工作中去探索。