4. SPI通信

本章介绍在Android中使用SPI进行通讯。

4.1. SPI引脚使能

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

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
&spi0 {
    status = "okay";
    #address-cells = <1>;
    #size-cells = <0>;
    pinctrl-names = "default";
    pinctrl-0 = <&spi0m2_cs0 &spi0m2_cs1 &spi0m2_pins>;
    num-cs = <2>;

    spi_dev@0 {
        compatible = "rockchip,spidev";
        reg = <0>; //chip select 0:cs0  1:cs1
        spi-max-frequency = <24000000>; //spi output clock
    };

    spi_dev@1 {
        compatible = "rockchip,spidev";
        reg = <1>;
        spi-max-frequency = <24000000>;
    };
};

提示

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

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

spi节点

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

4.2. 检查SPI设备

可以通过以下命令查看SPI接口有没有开启,存在/dev/spidev*则开启成功。

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

#查看SPI接口
ls /dev/spidev*
#信息输出如下
/dev/spidev0.0  /dev/spidev0.1

注:spidev0.0和spidev0.1分别代表spidev0两个片选对应的接口。spi默认从编号0开始注册,系统存在2个spi是那么分别会注册为/dev/spidev0、/dev/spidev1

4.3. 使用安卓应用回环测试

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

4.3.1. 应用测试

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

应用测试

4.3.2. 实现方式

SPI收发数据调用jni接口方式,参考野火应用源码ebf_android_app/app/src/main/cpp/spi.cpp

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

ebf_android_app/app/src/main/java/com/example/ebf_android_app/SpiTestActivity.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 打开SPI设备
public native int open(String portPath, int speed, int mode);
// 关闭SPI设备
public native void close();
// 写入数据
public native int write(byte[] data);
// 读取数据
public native byte[] read(int maxLen);
// 双向传输(用于回环测试)
public native byte[] transfer(byte[] txData);

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

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

那么SPI回环测试流程为:

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

// 打开接口
int result = open(portPath, speed, 0);

// 发送数据并接收
byte[] recvBytes = transfer(dataBytes);

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

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

 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/spidev0.0



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

#重启系统
adb reboot

#查看目录权限
adb shell ls -l /dev/spidev0.0
#信息输出如下
crwxrwxrwx 1 root root 153,   0 2025-07-29 16:43 /dev/spidev0.0

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

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