3. I2C通信

本章介绍在Android中使用I2C总线与外部设备的通讯。

3.1. I2C引脚使能

参考“40pin引脚对照图”章节,查看需要使用的I2C引脚, 大部分板卡的I2C复用功能默认是关闭的,需要修改设备树源码来使能I2C接口,并重新编译镜像

如果对设备树不熟悉的用户,请学习野火配套的《嵌入式Linux驱动开发实战指南》的 Linux设备树 章节内容。

以使能LubanCat-4-V1的I2C3_M1为例,修改SDK源码/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588s-lubancat-4-v1.dtsi (其他板卡修改板卡对应的设备树),在设备树中添加以下节点:

1
2
3
4
5
&i2c3 {
        pinctrl-names = "default";
        pinctrl-0 = <&i2c3m1_xfer>;
        status = "okay";
};

提示

如果不清楚选定的引脚节点怎么写,可以参考Linux内核对应的 设备树插件源码

修改为如下图所示,如果与其他节点冲突需关闭冲突节点再添加:

i2c节点

参考 编译 Android 镜像 章节重新编译镜像并将编译出来的镜像烧录到板卡。

3.2. 检查I2C设备

可以通过以下命令查看i2c总线有没有开启,存在/dev/i2c-3则开启成功。

1
2
3
4
5
#进入shell终端
adb shell

#查看i2c接口
ls /dev/i2c-*

3.3. 连接设备

将MPU6050接入到板卡i2c的总线上,接线如下所示:

1
2
3
4
5
6
7
#板卡与mpu6050连接

板卡  ------  mpu6050
3.3V  ------  VCC
GND   ------  GND
SCL   ------  SCL
SDA   ------  SDA

3.4. I2C第三方工具- i2c-tools

使用i2c-tools工具包提供了一些非常方便的工具来对系统的I2C总线进行调试, 在Android系统上,已经存在i2c-tools工具。

查看挂载在i2c-3上的器件情况,输出内容如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#查看i2c-3总线挂载情况
i2cdetect -a -y 3

#信息输出如下
        rk3588s_lubancat_4_v1_mipi1080p:/ # i2cdetect -a -y 3
        0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

其中 “68” 是为MPU6050的设备地址,常用的命令还有以下几个。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#检测当前系统有几组i2c总线
i2cdetect -l

#查看i2c-3接口上的设备
i2cdetect -a 3

#读取指定设备的全部寄存器的值。
i2cdump  -f -y 3 0x68

#读取指定IIC设备的某个寄存器的值,如下读取地址为0x68器件中的0x01寄存器值。
i2cget -f -y 3 0x68 0x01

3.5. 使用安卓应用读取MPU6050

野火提供的安卓综合测试应用能很方便的读取MPU6050的数据。

3.5.1. 应用测试

可参考“野火安卓综合测试应用”章节的“I2C测试”小节进行测试,如下图:

应用测试

3.5.2. 实现方式

I2C读取MPU6050数据调用jni接口方式,参考野火应用源码ebf_android_app/app/src/main/cpp/i2c_mpu6050.cpp

在Activity中声明JNI方法进行使用:

ebf_android_app/app/src/main/java/com/example/ebf_android_app/I2cTestActivity.java
1
2
3
4
// 打开接口并读取MPU6050数据
private native short[] readMpu6050(String devicePath);
// 关闭接口
private native void closeI2c();

值得注意的是普通用户没有读写I2C接口的权限,需要添加权限, 在野火应用源码的I2cTestActivity.java中提供了executeRootCommand函数用来执行root命令, 通过executeRootCommand函数执行chmod命令为I2C接口添加权限。

ebf_android_app/app/src/main/java/com/example/ebf_android_app/I2cTestActivity.java
1
private boolean executeRootCommand(String command)

那么I2C读取MPU6050数据流程为:

1
2
3
4
5
6
// 添加权限
boolean permResult = executeRootCommand("chmod 777 /dev/i2c-*");

// 打开接口并读取数据
String fullPath = "/dev/i2c-3";
short[] data = readMpu6050(fullPath);

由于野火测试应用是不确定用户选择的I2C接口是哪个,那么必须根据用户选择及时添加权限, 如果自己的项目中明确使用哪些I2C接口,也可以在系统shell脚本中提前添加权限,在Activity中省去添加权限步骤。

系统自启动的shell脚本位于/system/bin/android_shell.sh,由/vendor/etc/init/init.rk3588.rc调用执行(如果是其他芯片则是[对应芯片名字].rc),以提前添加/dev/i2c-3权限为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#重新挂载系统
adb root && adb remount

#拉取系统中的android_shell.sh
adb pull system/bin/android_shell.sh



#电脑文本软件打开android_shell.sh,在其末尾添加权限命令
chmod 777 /dev/i2c-3



#将修改后的android_shell.sh的覆盖到系统system/bin/
adb push android_shell.sh system/bin/

#重启系统
adb reboot

#查看目录权限
adb shell ls -l /dev/i2c-3
#信息输出如下
crwxrwxrwx 1 root   system 89,   7 2024-10-10 12:07 /dev/i2c-3

最终可以看到重启系统后,/dev/i2c-3文件普通用户也具有读写权限。

如需修改SDK源码来修改android_shell.sh,该文件位于SDK源码/device/rockchip/rk[具体芯片]/android_shell.sh,由SDK源码/device/rockchip/rk[具体芯片]/init.rk[具体芯片].rc中调用脚本, 由SDK源码/device/rockchip/rk[具体芯片]/device.mk中拷贝脚本进系统。