第一次接触嵌入式Linux的I2C调试时,我对着开发板上密密麻麻的芯片引脚发愁——怎么确认传感器是否正常通信?后来发现i2c-tools这套神器,就像给硬件调试装上了"显微镜"。但要把这个工具移植到ARM开发板上,得先过交叉编译这一关。
交叉编译就像在Windows电脑上编译一个只能在Mac上运行的程序。我常用的工具链是Linaro提供的aarch64-linux-gnu-gcc,具体版本选择要与开发板内核匹配。最近在调试瑞芯微RK3588时,就遇到过因glibc版本不兼容导致工具运行报错的情况。正确的做法是先通过readelf -a /bin/busybox | grep "Shared library"查看目标板的动态库版本。
编译环境搭建有三个关键步骤:
bash复制export CC=aarch64-linux-gnu-gcc
export STRIP=aarch64-linux-gnu-strip
export AR=aarch64-linux-gnu-ar
make clean,特别是当切换不同架构工具链时把编译好的i2c-tools搬到开发板时,我踩过的坑能写满一张A4纸。最典型的是权限问题——直接运行i2cdetect会报"Can't open /dev/i2c-1"错误。这是因为普通用户没有访问I2C设备的权限,有两种解决方案:
sudo chmod 666 /dev/i2c-*/etc/udev/rules.d/90-i2c.rules,内容为:code复制KERNEL=="i2c-[0-9]*", MODE="0666"
动态库链接也是高频故障点。当看到"error while loading shared libraries: libi2c.so.0"时,需要检查:
bash复制ln -s libi2c.so.0.1.1 libi2c.so.0
ln -s libi2c.so.0 libi2c.so
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/custom_lib_path添加了库搜索路径i2cdetect就像I2C总线的"雷达",但新手常被其输出搞懵。当执行i2cdetect -l看到类似下面输出时:
code复制i2c-1 unknown i2c-mux-pca9548a N/A
i2c-4 unknown DesignWare HDMI N/A
说明系统有4组I2C总线,其中1号总线接了PCA9548A多路复用器。这时候用i2cdetect -r -y 1扫描,可能会出现三种情况:
有个实用技巧是结合dmesg | grep i2c查看内核识别的设备,我曾用这个方法发现某HAT板的I2C地址与文档标注不符的问题。
i2cdump、i2cget、i2cset这三个命令就像硬件调试的"瑞士军刀"。在调试某款音频编码器时,我通过以下组合拳快速定位问题:
先用i2cdump全寄存器扫描:
bash复制i2cdump -f -y 2 0x1a
发现0x0E寄存器值异常后,用i2cget单独读取验证:
bash复制i2cget -f -y 2 0x1a 0x0e
确认问题后通过i2cset写入修正值:
bash复制i2cset -f -y 2 0x1a 0x0e 0x80
对于16位寄存器操作,i2ctransfer才是终极武器。读取0x1234地址的示例:
bash复制i2ctransfer -f -y 2 w2@0x1a 0x12 0x34 r2
这里要注意字节序问题,有些设备要求先发高位字节(0x12),有些则相反。我曾因此浪费半天时间,后来养成先查器件手册再操作的习惯。
当需要频繁操作I2C设备时,可以编写shell脚本提高效率。比如这个自动扫描并记录所有I2C设备的脚本:
bash复制#!/bin/bash
LOG_FILE=i2c_scan_$(date +%Y%m%d).log
for bus in $(i2cdetect -l | awk '{print $1}' | cut -d- -f2)
do
echo "Scanning i2c-$bus..." | tee -a $LOG_FILE
i2cdetect -y $bus | tee -a $LOG_FILE
echo "---------------------" | tee -a $LOG_FILE
done
对于需要批量配置寄存器的情况,可以制作配置模板文件reg.cfg:
code复制0x01 0xA0
0x02 0x30
0x03 0x1F
然后用awk配合i2cset批量写入:
bash复制awk '{system("i2cset -y 2 0x1a "$1" "$2)}' reg.cfg
在工业级应用中,I2C操作稳定性至关重要。通过实测发现两个优化点:
sleep 0.1,给设备足够响应时间安全方面要特别注意:
有一次我误操作修改了某传感器的校准寄存器,导致整个模块报废。现在养成了重要设备必先读三次确认再写的习惯。