10. CAN通信

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

CAN总线协议(Controller Area Network), 控制器局域网总线,是德国BOSCH(博世)公司研发的一种串行通讯协议总线, 它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。

支持CAN总线的鲁班猫板卡如下:

  • LubanCat-1HS

  • LubanCat-2

  • LubanCat-2N

  • LubanCat-2IO

  • LubanCat-3

  • LubanCat-3IO

  • LubanCat-4-V1

  • LubanCat-5-V2

10.1. CAN引脚使能

核心板加底板款板卡 默认使能了CAN接口, 一体板款板卡 默认没有使能CAN接口

一体板款板卡 用户参考“40pin引脚对照图”章节,查看需要使用的CAN引脚, 需要修改设备树源码来使能,并重新编译镜像

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

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

1
2
3
4
5
6
7
&can0 {
    status = "okay";
    assigned-clocks = <&cru CLK_CAN0>;
    assigned-clock-rates = <200000000>;
    pinctrl-names = "default";
    pinctrl-0 = <&can0m0_pins>;
};
  • assigned-clock-rates时钟频率可以修改,RK356x和RK3588系列如果CAN的波特率1M建议修改CAN时钟到300M,信号更稳定,低于1M比特率的,时钟设置200M就可以,默认使用的是200M。RK3576系列如果CAN的波特率小于等于3Mbps,建议CAN时钟修改为100M,这样信号更稳定,如果高于3Mbps,则可以将时钟设置为200M。

提示

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

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

can节点

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

10.2. 检查CAN设备

可以通过以下命令查看CAN接口有没有开启,存在can0则开启成功。

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

#查看网络接口
ifconfig -a

默认CAN编号从0开始,如果使能2个CAN接口,如CAN0_M0、CAN2_M0将会顺序注册为can0、can1。

10.3. 连接CAN设备

以连接CAN分析仪为例, 一体板款板卡40pin上的can为芯片原生接口,没有通过can收发器,使用的时候需要外接can收发器模块, 核心板加底板款板卡底板默认带can收发器,不需要额外接。

CAN收发器购买参考链接: 野火CAN收发器模块

一体板款板卡和外部设备CAN接线如下:

1
2
3
4
5
6
板卡         对接        CAN收发器   CAN收发器     对接    USB CAN分析仪
CAN_TX     ------        CAN_TX       H        ------        H
CAN_RX     ------        CAN_RX       L        ------        L
5V         ------           5V
GND        ------           GND
3.3V       ------           EN

核心板加底板款板卡和外部设备CAN接线如下:

1
2
3
板卡    连接  USB CAN分析仪
CAN_L ------- CAN_L
CAN_H ------- CAN_H

10.4. 使用shell收发数据

10.4.1. 配置CAN接口

CAN接口会注册成网络接口,可以使用ip命令进行配置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
查询当前网络设备:
ifconfig -a

CAN启动:
    关闭CAN:
    ip link set can0 down

    设置比特率500KHz:
    ip link set can0 type can bitrate 500000

    打印can0信息:
    ip -details link show can0

    启动CAN:
    ip link set can0 up

10.4.2. 收发CAN数据

使用shell收发CAN数据需要使用can-utils工具,镜像默认集成了其中的cansend和candump工具(旧镜像没有)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
CAN发送:
    发送(标准帧,数据帧,ID:123,date:DEADBEEF):
    cansend can0 123#DEADBEEF

    发送(标准帧,远程帧,ID:123):
    cansend can0 123#R

    发送(扩展帧,数据帧,ID:00000123,date:DEADBEEF):
    cansend can0 00000123#12345678

    发送(扩展帧,远程帧,ID:00000123):
    cansend can0 00000123#R

CAN接收:
    开启打印,等待接收:
    candump can0

发送数据:
    cansend can0 --identifier=ID+数据

使用滤波器接收ID匹配的数据:
    candump can0 --filter=ID:mask

如果系统没有cansend和candump命令,可访问资料网盘/6-开发软件获取can-utils-android.tar.gz, 该压缩包是野火交叉编译好的can-utils工具集,其中还包含can-utils的其他工具,如果需要也可自行集成到系统。

以添加cansend和candump工具到系统为例,解压can-utils-android.tar.gz压缩包,进入其中的usr/local/bin目录:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#进入can-utils-android/usr/local/bin目录,在目录栏输入cmd,打开windows终端
cmd

#通过adb命令重新挂载板卡分区
adb root && adb remount

#将工具传送到板卡/system/bin/目录
adb push cansend /system/bin/
adb push candump /system/bin/

#添加执行权限
adb shell chmod 777 /system/bin/cansend
adb shell chmod 777 /system/bin/candump

以上操作完成后即可参照前面介绍的收发CAN数据步骤进行测试。

can-utils源码为以下链接,感兴趣的用户可自行研究。

https://github.com/linux-can/can-utils/tree/master

10.5. 使用安卓应用收发数据

野火提供的安卓综合测试应用能很方便的实现收发CAN数据。

10.5.1. 应用测试

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

can发送接收

10.5.2. 实现方式

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

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

ebf_android_app/app/src/main/java/com/example/ebf_android_app/CanTestActivity.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 打开CAN设备
public native boolean openCan(String ifname);
// 打开关闭设备
public native void closeCan();
// 发送CAN数据
public native boolean sendCanFrame(int canId, boolean isExtended, boolean isRemote, byte[] data);
// 获取CAN接口
public native List<String> getCanInterfaces();
// 接收CAN数据
public native void startReceiving();
// 停止接收CAN数据
public native void stopReceiving();

值得注意的是普通用户没有配置CAN接口的权限(jni接口也没有),所以需要通过root用户执行shell命令去配置CAN接口, 在野火应用源码的CanTestActivity.java中提供了executeRootCommand函数用来执行root命令, 通过executeRootCommand函数执行chmod命令配置CAN接口参数并使能。

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

那么CAN发送数据的流程为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 配置CAN参数并使能
boolean downResult = executeRootCommand("ip link set can0 down");
boolean baudResult = executeRootCommand("ip link set can0 type can bitrate 500000");
boolean upResult = executeRootCommand("ip link set can0 up");

// 打开CAN接口
boolean openSuccess = openCan(selectedCanInterface);

// 发送数据
boolean result = sendCanFrame(canId, isExtended, isRemote, data);

由于野火测试应用是不确定用户选择的CAN接口以及波特率是多少,那么必须在应用中根据用户选择调用root去配置, 如果自己的项目中明确使用哪些CAN接口以及波特率,也可以在系统shell脚本中提前配置,在Activity中省去配置的步骤。

系统自启动的shell脚本位于/system/bin/android_shell.sh,由/vendor/etc/init/init.rk3588.rc调用执行(如果是其他芯片则是[对应芯片名字].rc), 以提前设置can0波特率为500000并使能为例:

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

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



#电脑文本软件打开android_shell.sh,在其末尾添加权限命令
ip link set can0 down
ip link set can0 type can bitrate 500000
ip link set can0 up



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

#重启系统
adb reboot

#查看can0状态
adb shell ip -details link show can0
#信息输出如下
3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
link/can  promiscuity 0
can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 1
    bitrate 500000 sample-point 0.868
    tq 20 prop-seg 42 phase-seg1 43 phase-seg2 13 sjw 1
    rockchip_canfd: tseg1 1..128 tseg2 1..128 sjw 1..128 brp 1..256 brp-inc 2
    clock 198000000numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535

最终可以看到重启系统后,can0接口默认波特率为500000并且状态为up。

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

10.6. 修改CAN缓冲区

默认CAN缓冲区大小只有10,每秒最多发4000帧,如果帧率再高缓冲区将没有多余的空间,提示No buffer space available,增大缓冲区大小可以增加帧率上限。

执行下面命令可以查看或者修改CAN缓冲区大小:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#进入shell终端
adb shell

#切换root
su root

#查看CAN缓冲区大小
cat  /sys/class/net/can0/tx_queue_len

#修改CAN缓冲区大小为4096
echo 4096 > /sys/class/net/can0/tx_queue_len