news 2026/4/24 10:38:08

Android硬件调试踩坑记:手把手教你编译i2c-tools并搞定16位寄存器读写

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android硬件调试踩坑记:手把手教你编译i2c-tools并搞定16位寄存器读写

Android硬件调试实战:从源码编译i2c-tools到16位寄存器读写全解析

当你在调试一块搭载Android系统的定制硬件板时,突然发现预装的i2c-tools缺少关键的i2ctransfer工具,而你的IMU传感器偏偏需要使用16位寄存器地址——这种场景对于嵌入式开发者来说再熟悉不过了。本文将带你完整走通从源码编译到实战调试的全流程,解决那些官方文档从未提及的"坑"。

1. 为什么需要自己编译i2c-tools

大多数Android设备预装的i2c-tools都是精简版本,通常只包含基础的i2cdetect、i2cget等工具。但当你面对以下场景时,系统自带的工具就显得力不从心了:

  • 16位寄存器访问:现代传感器(如BMI160 IMU、AT24C512 EEPROM)普遍采用16位地址空间,而i2cget/i2cset仅支持8位地址
  • 批量数据传输:需要连续读取多个寄存器时,i2ctransfer的单次事务特性可以避免多次I2C起停带来的时序问题
  • 特殊传输模式:某些设备要求特定的I2C时序,只有i2ctransfer提供足够的灵活性

更棘手的是,直接从Linux系统拷贝的预编译二进制文件在Android上运行时,往往会遇到not executable: 64-bit ELF file错误。这是因为Android的bionic libc与glibc不兼容,且ABI差异导致直接移植的二进制无法执行。

2. 搭建Android编译环境

2.1 准备NDK或AOSP环境

根据你的开发场景,可以选择两种编译路径:

NDK独立编译方案(适合快速验证):

# 下载NDK工具链 wget https://dl.google.com/android/repository/android-ndk-r25b-linux.zip unzip android-ndk-r25b-linux.zip # 设置工具链路径 export TOOLCHAIN=$PWD/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64 export TARGET=aarch64-linux-android export API=28 # 配置环境变量 export AR=$TOOLCHAIN/bin/llvm-ar export CC=$TOOLCHAIN/bin/$TARGET$API-clang export AS=$CC export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++ export LD=$TOOLCHAIN/bin/ld export RANLIB=$TOOLCHAIN/bin/llvm-ranlib export STRIP=$TOOLCHAIN/bin/llvm-strip

AOSP集成编译方案(适合产品级开发):

# 下载AOSP源码 repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r1 repo sync -c -j8 # 设置编译环境 source build/envsetup.sh lunch aosp_arm64-eng

2.2 获取i2c-tools源码

建议直接从kernel.org获取最新稳定版:

wget https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/i2c-tools-4.3.tar.gz tar xvf i2c-tools-4.3.tar.gz cd i2c-tools-4.3

对于AOSP集成,建议将解压后的代码放在external/i2c-tools目录下。

3. 编写Android.mk编译脚本

无论是NDK还是AOSP环境,都需要适配Android的构建系统。以下是完整的Android.mk示例:

LOCAL_PATH := $(call my-dir) # 静态库部分 include $(CLEAR_VARS) LOCAL_MODULE := libi2c-tools LOCAL_SRC_FILES := \ tools/i2cbusses.c \ tools/util.c \ lib/smbus.c LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(BUILD_STATIC_LIBRARY) # i2ctransfer模块 include $(CLEAR_VARS) LOCAL_MODULE := i2ctransfer LOCAL_SRC_FILES := tools/i2ctransfer.c LOCAL_STATIC_LIBRARIES := libi2c-tools LOCAL_SHARED_LIBRARIES := libc LOCAL_CFLAGS := -DANDROID -Wno-unused-parameter include $(BUILD_EXECUTABLE) # 其他工具同理添加...

关键配置说明:

  • BUILD_STATIC_LIBRARY:将公共代码编译为静态库避免重复
  • -DANDROID:定义宏适配Android环境
  • -Wno-unused-parameter:屏蔽Android严格模式下的警告

4. 解决64-bit ELF不可执行问题

当遇到not executable: 64-bit ELF file错误时,通常有三个潜在原因:

  1. ABI不匹配:编译时未指定正确的目标架构
  2. 动态链接问题:Android不支持glibc的动态链接
  3. 文件权限错误:打包/推送过程中权限丢失

解决方案对照表:

问题类型检查方法解决方案
ABI不匹配file i2ctransfer查看ELF头确保-target aarch64-linux-android
动态链接readelf -d i2ctransfer添加-static编译选项
权限问题ls -l /system/bin/i2c*chmod 755 /system/bin/i2ctransfer

推荐使用静态编译确保兼容性:

# 在Android.mk中添加 LOCAL_LDFLAGS := -static

5. i2ctransfer实战:16位寄存器操作

5.1 基础命令格式

i2ctransfer使用一种特殊的语法来描述I2C事务:

i2ctransfer -f -y <i2c_bus> [r|w]<length>@<address> <data...>

参数说明:

  • -f:强制访问可能被驱动占用的设备
  • -y:禁用交互确认
  • <i2c_bus>:I2C总线编号(如1对应i2c-1)
  • w2@0x50:向0x50设备写入2字节
  • r4:读取4字节数据

5.2 典型操作示例

读取16位寄存器(如地址0x1A3B)

# 写入寄存器地址 + 读取3字节数据 i2ctransfer -f -y 1 w2@0x36 0x1A 0x3B r3

写入16位寄存器

# 写入寄存器地址0x2C01和值0x55 i2ctransfer -f -y 1 w3@0x36 0x2C 0x01 0x55

连续读写操作

# 先设置页寄存器,再读取数据 i2ctransfer -f -y 1 w2@0x50 0x00 0x80 && \ i2ctransfer -f -y 1 w1@0x50 0xA0 r16

5.3 调试技巧

  • 地址验证:先用i2cdetect确认设备地址
  • 权限检查:确保/dev/i2c-*设备有读写权限
  • 时序调试:通过逻辑分析仪捕获实际波形
  • 错误处理
    • Remote I/O error:检查设备是否上电
    • Permission denied:需要root权限或SELinux策略调整

6. 系统集成与优化

6.1 预编译二进制集成

对于产品级部署,建议将编译好的工具集成到系统镜像:

# 在AOSP device.mk中添加 PRODUCT_COPY_FILES += \ device/xxx/i2c-tools/i2ctransfer:$(TARGET_COPY_OUT_SYSTEM)/bin/i2ctransfer

6.2 SELinux策略调整

新建i2ctools.te文件:

type i2ctools_exec, exec_type, file_type; allow i2ctools i2c_device:chr_file rw_file_perms;

6.3 性能优化建议

  • 批量操作时合并多次操作为一个transfer命令
  • 对高频访问的寄存器考虑编写内核驱动
  • 使用i2c_smbus_*API替代直接IOCTL

7. 进阶:编写自动化测试脚本

结合shell脚本实现自动化测试:

#!/system/bin/sh # 寄存器定义 REG_STATUS=0x00 REG_CONFIG=0x01 # 读取设备状态 i2ctransfer -f -y 1 w1@0x28 $REG_STATUS r1 status=$? # 检查状态寄存器第3位 if [ $((status & 0x04)) -ne 0 ]; then echo "Sensor is in error state" # 尝试复位 i2ctransfer -f -y 1 w2@0x28 $REG_CONFIG 0x80 fi

调试这类底层硬件问题时,最宝贵的经验是:永远先验证最基本的通信链路。我曾在凌晨三点的实验室里花了四个小时调试一个"不工作"的传感器,最终发现只是电源线上的一个虚焊点。从i2cdetect开始,逐步验证每一层假设,这才是硬件调试的王道。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 10:36:21

从零到一:PyQt应用打包、spec文件定制与UPX极致压缩实战

1. PyQt应用打包基础入门 第一次把PyQt程序打包成exe的经历让我记忆犹新。当时我花了两天时间才搞明白为什么程序在IDE里运行正常&#xff0c;打包后却总是崩溃。如果你也在经历类似的困扰&#xff0c;别担心&#xff0c;跟着我的步骤走&#xff0c;能少踩很多坑。 PyInstaller…

作者头像 李华
网站建设 2026/4/24 10:36:21

AEUX:免费的Figma到AE转换工具终极指南

AEUX&#xff1a;免费的Figma到AE转换工具终极指南 【免费下载链接】AEUX Editable After Effects layers from Sketch artboards 项目地址: https://gitcode.com/gh_mirrors/ae/AEUX 你是否曾为将Figma设计稿转换为After Effects动画而烦恼&#xff1f;从设计到动画的转…

作者头像 李华