ARM Linux IIC tools - i2c-tools-4.3

 

/* Copyright 夜流冰 */

因为要在ARM Linux上开发IIC设备,为了方便调试,需要工具支持。

Google搜索Linux IIC tool,找到:

https://i2c.wiki.kernel.org/index.php/I2C_Tools

发现Linux Kernel Repository里就有IIC toolset:

https://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git/

可以直接git clone:

git clone git://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git

也可以在当前页面下载某个版本。

也可以搜索到其他网站下载:

这个网站是kernel相关内容的各个版本都有: https://mirrors.kernel.org/

网上搜索就会指向下面连接,能下载i2c-tools的地方:https://mirrors.kernel.org/pub/software/utils/i2c-tools/

i2c-tools-4.3.tar.xz                               27-Jul-2021 13:34     79K

然后把这个文件Copy到Ubuntu虚拟机里。解压缩:

$ tar -xf i2c-tools-4.3.tar.xz  

解压完成后,这里面是一个完成的可编译的项目。

打开README看一下。

不需要Configure,直接make就能编译。

运行make install会将这些工具安装到/usr/local里。

可以指定使用动态库还是静态库。

$ make BUILD_DYNAMIC_LIB=1 BUILD_STATIC_LIB=0

$ make USE_STATIC_LIB=1

先运行make strip能减小二进制程序大小。

这样使用下载的方法得到I2C tools,在Ubuntu里,也可以通过apt-get直接安装,在APT repository里的软件,直接使用apt-get安装二进制程序和文档,这样会更快捷。

当然,使用APT-GET的安装方法,通过设置也可以下载源码,后面有时间发个博文详细介绍下。

$sudo apt-get update

$sudo apt-get install i2c-tools

我们要编译Embedded ARM Linux的版本,所以要使用源码自己重新编译。

另外一种方法,本文不多做介绍:

如果我们的开发板程序是用Yocto构建的,可以在构建时加上i2c-tool的package,这样将rootfs烧写到目标板上后,板子上就有i2c-tools了。

使用Yocto,操作更加自动化,更方便,就是需要重新编译bsp,然后重新烧写。

举个例子修改如下:

/recipes-core/images/core-image-scanning.bb

IMAGE_INSTALL_append = " \
        mtd-utils-ubifs \
        ethtool \
        i2c-tools \
        dropbear openssh-sftp-server gdbserver \

这个i2c已经是个OpenEmbedded记录在案的一个Recipe,有自己的bb文件,可以自动构建。

查询某个package是否有现成的recipe:https://layers.openembedded.org/layerindex/branch/master/recipes/

废话不多说,开搞。

================================= 

先直接make一下,build成功。

在tools文件夹下,各个工具已经创建,尝试运行下,在Ubuntu下可以运行。

ubuntu@ubuntu20:~/work/i2ctool/i2c-tools-4.3$make USE_STATIC_LIB=1

ubuntu@ubuntu20:~/work/i2ctool/i2c-tools-4.3$cd tools

ubuntu@ubuntu20:~/work/i2ctool/i2c-tools-4.3/tools$ ./i2cdetect

Error: No i2c-bus specified!

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.

然后我们要更改toolchain,build ARM能运行的程序。

打开MakeFile进行编辑。

看到了三行我们要修改的内容:

CC    ?= gcc

AR    ?= ar

STRIP    ?= strip

这里我们直接替换成:

CC      = /usr/bin/arm-linux-gnueabihf-gcc

AR      = /usr/bin/arm-linux-gnueabihf-ar

STRIP   = /usr/bin/arm-linux-gnueabihf-strip

这里可以根据自己的tool chain的路径进行替换。

然后make。

再去tools下找到自己需要的程序。

将得到的IIC tool的工具程序,用scp方式copy到ARM Linux target machine上,就可以来对IIC进行操作了。

================================= 

关于如何使用,在tools文件夹里面,有.c源文件,注意到还有.8文件,这个就是man page里的内容,不用make install可以直接查看。

如果make install成功, 可以直接man命令查看。

不然就上网搜索相关命令的man page内容。

文件后缀.8的意思,使man page的类别number是8。

ubuntu@ubuntu20:~/work/i2ctool/i2c-tools-4.3/tools$ man -f i2cdetect

i2cdetect (8)        - detect I2C chips

ubuntu@ubuntu20:~/work/i2ctool/i2c-tools-4.3/tools$ man i2cdetect

这几个都是user space的程序,使用这些工具时也要注意,可能会对现有的正在运行的I2C的应用程序产生副作用或冲突。

-------------------------------------------------------------------------  

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.

这里的I2CBUS用来指定扫描的I2C bus,举例设备节点名是“/dev/i2c-1”或“/dev/i2c/1”。
它可以是一个整数值,表示I2C设备的minor number。
# ll /dev/i2c-0
crw-rw----    1 root     root       89,   0 Jan  1 00:03 /dev/i2c-0
这里的i2c-0 device的major number是89,minor number是0.

也可以是一个设备名,比如“21a4000.i2c”。
# cat /sys/class/i2c-dev/i2c-1/name
21a4000.i2c
# i2cdetect -y 21a4000.i2c

有些设备里,使用“i2c-1”这样设备名也可以,不过这需要/proc/bus/i2c这个文件存在。


显示所有可用的I2C bus:
# i2cdetect -l
i2c-0   i2c             21a0000.i2c                             I2C adapter
i2c-1   i2c             21a4000.i2c                             I2C adapter
i2c-3   i2c             21f8000.i2c                             I2C adapter
这里就显示了i2c bus的设备名。

$i2cdetect -y 1
不需要用户确认,直接看是扫描I2C bus 1 (i2c-1)

输出结果:
# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- 0e --
10: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

需要确认:
# i2cdetect 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 0x08-0x77.
Continue? [Y/n]

指定start和end地址:
# i2cdetect -a -y 1  0x00 0x7F
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00: 00 -- -- -- -- -- -- -- -- -- -- -- -- -- 0e --
10: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
I2C地址是7位,正常是128个,0-0x7F。但I2C标准里保留了两套8位地址:1111XXX和0000XXX。
也就是说一般可用范围是0x08 - 0x77。所以要使用更大范围,需要-a参数,Force scanning of non-regular addresses.


查询I2C bus所支持功能:
# 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

输出结果解释:
--:表示没有应答
UU:探测未执行,因为当前地址被某驱动占用。这很大可能是此地址有I2C外设。
数值:表示被发现的芯片地址,十六进制表示。

注:

1,保留的I2C地址:

2,关于I2C设备的查找。

在Linux里,有两个内核的内存虚拟文件系统,/proc和/sys,里面存储有关于设备的信息。

所以在里面可以查询i2c设备信息。

而文件系统信息,可以通过#cat /proc/mouts查询。

# cat /proc/mounts
ubi0:rootfs / ubifs rw,relatime 0 0
devtmpfs /dev devtmpfs rw,relatime,size=49244k,nr_inodes=12311,mode=755 0 0
proc /proc proc rw,relatime 0 0
sysfs /sys sysfs rw,relatime 0 0
none /sys/kernel/config configfs rw,relatime 0 0
tmpfs /dev tmpfs rw,relatime,size=64k,mode=755 0 0
devpts /dev/pts devpts rw,relatime,mode=600 0 0
tmpfs /run tmpfs rw,nosuid,nodev,mode=755 0 0
tmpfs /var/volatile tmpfs rw,relatime 0 0

----------------------------------------------------------------------------------------------------------------   

i2cdump

这个是用来在I2C bus上读取某个地址的I2C设备的寄存器的值。适用I2C设备的寄存器地址是8bit的。

        "Usage: i2cdump [-f] [-y] [-r first-last] [-a] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]\n"
        "  I2CBUS is an integer or an I2C bus name\n"
        "  ADDRESS is an integer (0x08 - 0x77, or 0x00 - 0x7f if -a is given)\n"
        "  MODE is one of:\n"
        "    b (byte, default)\n"
        "    w (word)\n"
        "    W (word on even register addresses)\n"
        "    s (SMBus block, deprecated)\n"
        "    i (I2C block)\n"
        "    c (consecutive byte)\n"
        "    Append p for SMBus PEC\n"

读取i2c-3上的,地址为0x6a的设备的寄存器的值,-y不用输入Y进行确认。
# i2cdump -y 3 0x6a
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: 1e 0a 91 12 40 87 e6 4c 65 80 80 2c 65 ff ff ff    ????@??Le??,e...
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................

指定寄存器读取范围, 0x00-0x20:
# i2cdump -y -r 0x00-0x20 3 0x6a

关于Mode,默认是字节输出。
root@lark-n6703:/usr/bin# i2cdump -y -r 0x00-0x1F 3 0x6a b
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 1e 0a 91 12 40 87 e6 4c 65 00 80 2c 65 ff ff ff    ????@??Le.?,e...
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
root@lark-n6703:/usr/bin# i2cdump -y -r 0x00-0x1F 3 0x6a w
     0,8  1,9  2,a  3,b  4,c  5,d  6,e  7,f
00: 0a1e 910a 1291 4012 8740 e687 4ce6 654c
08: 0065 8000 2c80 652c ff65 ffff ffff ffff
10: ffff ffff ffff ffff ffff ffff ffff ffff
18: ffff ffff ffff ffff ffff ffff ffff ffff
使用b表示字节,w表示按字为单位来查询寄存器值。


其他参数:
-f: 强制读取,即使设备忙(被kernel driver占用)。有一定风险。
-a: 可以读取0x00-0x07和0x78-0x7F的地址

注意,这个i2cdump的功能,是读取的是单个字节的地址的寄存器的值,最大256个寄存器。

如果你的I2C设备,如果是个EEPROM,里面可访问地址超过256字节,是2个字节的地址,那i2cdump这个命令就不适用。

---------------------------------------------------------------------------------------------------------------- 

 i2cset

        "Usage: i2cset [-f] [-y] [-m MASK] [-r] [-a] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]\n"
        "  I2CBUS is an integer or an I2C bus name\n"
        "  ADDRESS is an integer (0x08 - 0x77, or 0x00 - 0x7f if -a is given)\n"
        "  MODE is one of:\n"
        "    c (byte, no value)\n"
        "    b (byte data, default)\n"
        "    w (word data)\n"
        "    i (I2C block data)\n"
        "    s (SMBus block data)\n"
        "    Append p for SMBus PEC\n"

i2c-1 bus的0x2d地址的设备,写入0x11寄存器的值为0x42. 这个设备寄存器地址是8bit的。
# i2cset 1 0x2d 0x11 0x42

i2c-1 bus的0x2d地址的设备,写入0x11寄存器,将最低的3位数据清除。这个设备寄存器地址是8bit的。
-m 是mask,表示读取此地址寄存器的数据,然后根据mask值为1的位的数据会写入。
# i2cset -y -m 0x07 1 0x2d 0x11 0x00

把0x5000写入0x02位置的16-bit寄存器。I2C-1设备的地址0x48的设备。这个设备寄存器地址是16bit的。
# i2cset 1 0x48 0x02 0x5000 w

设备寄存器地址是16bit时,也可以用下面方法,直接写如数据。
# i2cset -f -y <i2cbus number> <peripheral address> <MSB address> <LSB address> <MSB value> <LSB value> i
address 0x0300的操作:
# i2cset -y 0 0x1b 0x03 0x00 0x60 0x50 i
# i2cget -y 0 0x1b 0x3 w
0x5060

----------------------------------------------------------------------------------------------------------------   

i2cget

这个程序也是用来读取I2C设备寄存器值的。

        "Usage: i2cget [-f] [-y] [-a] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE [LENGTH]]]\n"
        "  I2CBUS is an integer or an I2C bus name\n"
        "  ADDRESS is an integer (0x08 - 0x77, or 0x00 - 0x7f if -a is given)\n"
        "  MODE is one of:\n"
        "    b (read byte data, default)\n"
        "    w (read word data)\n"
        "    c (write byte/read byte)\n"
        "    s (read SMBus block data)\n"
        "    i (read I2C block data)\n"
        "    Append p for SMBus PEC\n"
        "  LENGTH is the I2C block data length (between 1 and %d, default %d)\n"

i2c-1 bus的地址0x2d设备,读取8bit的地址为0x11的寄存器的值。这个设备寄存器地址是8bit的。
# i2cget 1 0x2d 0x11

i2c-1 bus的地址0x48设备,读取16bit的地址为0x00的寄存器的值。这个设备寄存器地址是16bit的。
# i2cget 1 0x48 0x00 w
注意:这里指定的地址,0x48这个参数是一个字节,而关于这个地址的解释依赖于具体设备,可能是0x4800,或者0x0048。
所以建议使用下面的i2cset地址指针后,再按顺序读取内容的方法读取值。

i2c-9 bus的地址0x50设备,先将内部的寄存器地址指针指向0x00,然后接连读取2个字节的值。这个设备寄存器地址是8bit的。
读取内容时,会读取当前内部指针的值,读完后地址会加1。
大部分EEPROM设置支持这种用法,但还要保证没有其他人访问这个I2C地址的设备。    
# i2cset -y 9 0x50 0x00 ; i2cget -y 9 0x50 ; i2cget -y 9 0x50

i2c-9 bus的地址0x53设备,先将内部的寄存器地址指针指向0x0000,然后接连读取2个字节的值。这个设备寄存器地址是16bit的。
# i2cset -y 9 0x53 0x00 0x00 ; i2cget -y 9 0x53 ; i2cget -y 9 0x53

i2c-4 bus的地址0x50设备,读取最开始的8个字节。这个设备寄存器地址是8bit的。
# i2cget -y 4 0x50 0 i 8

---------------------------------------------------------------------------------------------------------------- 

i2ctransfer

这个命令可以把读写操作组合起来。还能通过一条命令控制多个字节的读写。

"Usage: i2ctransfer [-f] [-y] [-v] [-V] [-a] I2CBUS DESC [DATA] [DESC [DATA]]...\n"
        "  I2CBUS is an integer or an I2C bus name\n"
        "  DESC describes the transfer in the form: {r|w}LENGTH[@address]\n"
        "    1) read/write-flag 2) LENGTH (range 0-65535, or '?')\n"
        "    3) I2C address (use last one if omitted)\n"
        "  DATA are LENGTH bytes for a write message. They can be shortened by a suffix:\n"
        "    = (keep value constant until LENGTH)\n"
        "    + (increase value by 1 until LENGTH)\n"
        "    - (decrease value by 1 until LENGTH)\n"
        "    p (use pseudo random generator until LENGTH with value as seed)\n\n"
        "Example (bus 0, read 8 byte at offset 0x64 from EEPROM at 0x50):\n"
        "  # i2ctransfer 0 w1@0x50 0x64 r8\n"
        "Example (same EEPROM, at offset 0x42 write 0xff 0xfe ... 0xf0):\n"
        "  # i2ctransfer 0 w17@0x50 0x42 0xff-\n"

读取多字节数据:
# i2ctransfer -f -y <i2cbus number> r<number of bytes>@<peripheral address>
# i2ctransfer -f -y 0 r3@0x50 

写入多字节数据:
# i2ctransfer -f -y <i2cbus number> w<number of bytes>@<peripheral address> <byte value 1> <byte value 2> ... <byte value n>
# i2ctransfer -f -y 0 w2@0x50 0x12 0x34

先读再写:
# i2ctransfer -f -y <i2cbus number> w<number of bytes to write>@<peripheral address> <byte value 1> <byte value 2> ... <byte value n> r<number of bytes to read>
# i2ctransfer 0 w1@0x50 0x64 r8
w1的意思是写1个字节,指定内存指针为0x64,然后从这个位置读取8个字节。

在0x42的地址,写入0xff, 0xfe, 0xfd ..... 0xf0.
# i2ctransfer 0 w17@0x50 0x42 0xff-
这里“-”表示值递减1。
=: 值不变
+: 自加1
在上面注释有说明。


# i2ctransfer -f -y 0 w4@0x1b 0x03 0x00 0x60 0x50 -r2
# 0x60 0x50
"w4" for "write 4 bytes": the first 2 bytes for address (0x0300), the next 2 bytes for register address (0x6050)
"r2" for "read 2 bytes": the word register value

注:

虽然没有写入I2C标准,但是大部分I2C设备都有地址自增功能。这是为了方便操作大量寄存器,尤其是I2C RAM或EEPROM。

所以这些设备是有一个内部地址指针,每次读写操作都会自增1。

所以对同一个地址读取,会有不同的值:

$> i2cget -y 0 0x1b 0x00 w
0x9489
$> i2cget -y 0 0x1b 0x00 w
0x0000
$> i2cget -y 0 0x1b 0x00 w
0x0060

后两次执行是后面的地址值,所以要重新设置地址指针,就要写一次这个寄存器的值,然后再操作。

$> i2cset -y 0 0x1b 0x00 0x00
$> i2cget -y 0 0x1b 0x00 w
0x9489

参考:

https://wiki.st.com/stm32mpu/wiki/I2C_i2c-tools

https://www.mankier.com/8/i2cdetect

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜流冰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值