在Android底层开发中,I2C总线调试是硬件工程师和嵌入式开发者经常面临的挑战。当我们需要与各种传感器、EEPROM或其他I2C设备交互时,一套可靠的调试工具至关重要。本文将带你从零开始构建完整的Android平台I2C调试环境,解决编译过程中的典型问题,并深入解析16位寄存器地址的读写技巧。
要在Android平台上使用i2c-tools,首先需要搭建合适的编译环境。与Linux桌面环境不同,Android系统需要特殊的交叉编译工具链。
必备条件:
source和lunch)获取i2c-tools源码有两种推荐方式:
bash复制# 方式一:从kernel.org官方镜像下载稳定版
wget https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/i2c-tools-4.3.tar.gz
# 方式二:使用git克隆开发版(推荐)
git clone git://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git
提示:建议将源码放在AOSP的
external目录下,保持项目结构清晰。例如:aosp/external/i2c-tools/
标准的i2c-tools使用Makefile构建,但在Android环境中需要转换为Android.mk。以下是一个完整的配置示例:
makefile复制LOCAL_PATH := $(call my-dir)
################### 核心库 #########################
include $(CLEAR_VARS)
LOCAL_MODULE := i2c-tools
LOCAL_SRC_FILES := \
tools/i2cbusses.c \
tools/util.c \
lib/smbus.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH) \
$(LOCAL_PATH)/include
include $(BUILD_STATIC_LIBRARY)
################### i2ctransfer #######################
include $(CLEAR_VARS)
LOCAL_MODULE := i2ctransfer
LOCAL_SRC_FILES := tools/i2ctransfer.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := libc
LOCAL_STATIC_LIBRARIES := i2c-tools
LOCAL_CPPFLAGS += -DANDROID
include $(BUILD_EXECUTABLE)
关键配置说明:
BUILD_STATIC_LIBRARY:构建静态库供其他工具共享BUILD_EXECUTABLE:生成可执行文件LOCAL_CPPFLAGS += -DANDROID:定义Android平台宏注意:必须删除或备份原始Makefile,否则可能导致编译冲突。
配置好Android.mk后,按照以下步骤进行编译:
bash复制# 进入AOSP根目录
cd /path/to/aosp
# 设置编译环境
source build/envsetup.sh
lunch aosp_arm-eng # 根据目标设备选择
# 单独编译i2c-tools
mmm external/i2c-tools/
# 打包系统镜像(可选)
make snod
编译成功后,可执行文件位于:
out/target/product/[设备名]/system/bin/
部署到设备的几种方式:
bash复制adb push out/target/product/generic/system/bin/i2ctransfer /system/bin/
bash复制make snod && adb reboot bootloader
fastboot flash system out/target/product/generic/system.img
bash复制adb sync system
i2ctransfer是处理16位寄存器地址的关键工具,其命令格式比i2cget/i2cset更灵活但也更复杂。
写入16位地址+数据:
bash复制i2ctransfer -f -y 1 w3@0x50 0x00 0x80 0x1A
-f:强制访问-y:禁用交互确认1:I2C总线编号w3:写入3个字节(2字节地址+1字节数据)0x50:设备7位地址0x00 0x80:16位寄存器地址0x1A:写入数据读取16位地址数据:
bash复制i2ctransfer -f -y 1 w2@0x50 0x01 0x80 r4
w2:先写入2字节地址r4:然后读取4字节数据同时写入配置并读取状态:
bash复制i2ctransfer -f -y 1 w3@0x68 0x10 0x20 0x55 w2@0x68 0x30 0x40 r2
bash复制adb root
adb remount
bash复制i2ctransfer -f -y -m 100 1 w2@0x48 0xF0 0x00 r1
-m:增加超时时间(ms)这个错误通常由以下原因导致:
bash复制file i2ctransfer
# 应显示:ELF 32-bit LSB executable, ARM...
解决方案:
lunch选择了正确的目标架构在Android.mk中添加:
makefile复制LOCAL_LDFLAGS += -static
bash复制adb shell setenforce 0 # 临时禁用
| 工具 | 地址位数 | 主要功能 | 典型用例 |
|---|---|---|---|
| i2cget | 8位 | 读取单个寄存器 | 读取状态寄存器 |
| i2cset | 8位 | 写入单个寄存器 | 配置设备参数 |
| i2cdump | 8位 | 批量读取寄存器 | 设备寄存器映射探查 |
| i2cdetect | - | 总线设备扫描 | 检测连接的I2C设备 |
| i2ctransfer | 16位 | 复杂读写操作 | 大容量存储设备访问 |
以常见的24LC256 EEPROM为例(16位地址):
写入数据:
bash复制# 在地址0x1234写入2字节数据0xAA55
i2ctransfer -f -y 1 w4@0x50 0x12 0x34 0xAA 0x55
读取数据:
bash复制# 从地址0x5678读取16字节
i2ctransfer -f -y 1 w2@0x50 0x56 0x78 r16
批量写入技巧:
bash复制# 生成测试数据
dd if=/dev/urandom of=data.bin bs=64 count=1
# 分段写入(每页64字节)
for i in {0..63}; do
addr=$((i*64))
aH=$((addr>>8))
aL=$((addr&0xFF))
dd if=data.bin bs=1 skip=$i count=64 | \
xxd -p -c 1 | awk '{print "0x"$1}' | \
xargs i2ctransfer -f -y 1 w66@0x50 0x$aH 0x$aL
done
查看当前速度:
bash复制adb shell cat /sys/bus/i2c/devices/i2c-1/of_node/clock-frequency
临时修改速度(需驱动支持):
bash复制echo 400000 > /sys/bus/i2c/devices/i2c-1/of_node/clock-frequency
当遇到信号完整性问题时:
启用详细日志:
bash复制echo 1 > /sys/module/i2c_core/parameters/debug
dmesg | grep i2c
在项目中使用这些技巧时,建议先在小规模测试环境中验证。不同厂商的I2C设备可能有特殊要求,如需要额外的控制字节或非标准的地址编码方式。