**前言:**由于工作需要,笔者近期完成了基于OpenHarmony 5.0的CAN驱动底层移植工作,使用的开发板是飞凌嵌入式OKT527(芯片为全志T527)。在刚上手这项工作时,笔者发现网上几乎查不到针对OpenHarmony + 全志平台的SocketCAN移植教程,自己摸索着踩了许多坑。于是整理了这篇移植踩坑笔记,希望能帮助到面临同样需求的开发者,也方便自己进行技术复盘。
注意: 本教程侧重于Linux内核层面的SocketCAN驱动使能以及上层测试工具的交叉编译。前提是读者已经搭建好Ubuntu 20.04编译环境,并能成功编译烧录OpenHarmony 5.0系统。
1 CAN驱动使能
由于OpenHarmony 5.0为了精简系统体积,在默认的内核defconfig配置文件中没有使能SocketCAN功能,所以工作的第一步是去设备树重新使能CAN驱动。全志T527的设备树dtsi文件名称为sun55iw3p1.dtsi,找到该文件后在其中添加如下代码:
cpp
1. /* can驱动相关配置 */
2. awlink0: awlink@0x0{
3. #address-cells = <1>;
4. #size-cells = <0>;
5. compatible = "allwinner,t527-awlink";
6. device_type = "awlink0";
7. awlink-pin = <1>;
8. id = <0>;
9. status = "okay";
10. };
11.
12. awlink1: awlink@0x1{
13. #address-cells = <1>;
14. #size-cells = <0>;
15. compatible = "allwinner,t527-awlink";
16. device_type = "awlink1";
17. awlink-pin = <0>;
18. id = <1>;
19. status = "okay";
20. };
全志芯片的CAN接口名称为awlink,awlink0和awlink1便是我们需要开启的CAN。
之后找到t527_standard_defconfig文件,添加如下代码来配置CAN驱动:
cpp
1. # can驱动相关配置
2. CONFIG_CAN=y
3. CONFIG_CAN_DEV=y
4. CONFIG_CAN_RAW=y
5. CONFIG_AW_AWLINK_SUN55I=y
6. CONFIG_CAN_CALC_BITTIMING=y
内核层的修改只有这么多,现在可以编译并烧录进开发板。使用hdc shell指令进入开发板Shell中,输入ifconfig -a便可以看到两个awlink:

2 CAN工具移植
想要使用CAN,就必须移植canutils和iproute这两个工具,其中canutils提供了cansend(发送CAN信息)和candump(接受CAN信息)这两个工具,而iproute提供了ip工具(波特率设置、CAN启停设置)。
需要注意的是,在vendor/forlinx/okt527/config.json文件中可以看到target_cpu = "arm"这一项,说明用户态按32位ARM编;若是64位用户态,这里一般是"arm64"。所以在进行编译的时候一定要指定32位编译器,否则会报错!

2.1 canutils
正常使用交叉编译即可,指定--host=arm-linux-gnueabi编译器,并使用-static进行静态编译即可(OpenHarmony砍掉了许多动态链接库,为了避免缺少动态链接库需要采用静态编译)。
2.2 iproute
这个CAN工具在编译的时候遇到了许多坑,笔者在这里只列举几个我有印象的:
(1)xtables-version.h缺失导致编译中断
解决方法:在同路径下config.mk文件中添加TC_CONFIG_NO_XT:=y。
(2)ip link set type ca报"Garbage instead of arguments"
解决方法:在同路径下config.mk文件中添加CFLAGS += -DNO_SHARED_LIBS。
(3)板子上运行报"No such file or directory"
解决方法:在同路径下config.mk文件中添加SHARED_LIBS=n和LDFLAGS += -static。
(4)找不到libmnl、libbsd、libcap
解决方法:在编译iproute之前先编译这三个依赖库文件
如果还遇到其他问题,大概率都是编译器未指定、某个库文件缺失等问题,可自行上网查阅或问ai。
2.3 移植CAN工具到开发板
在完成了上一步后,理论上应该已经获取到了编译好的cansend、candump和ip工具文件,先传到电脑上,再在电脑上使用使用hdc file send指令将这三个文件传送到开发板上,笔者选择的路径为/data/local/tmp。
cpp
1. hdc file send ip /data/local/tmp/
2. hdc file send cansend /data/local/tmp/
3. hdc file send candump /data/local/tmp/
使用hdc shell进入开发板Shell界面,进入/data/local/tmp路径,之后在该路径给三个工具文件赋予可执行权限:
cpp
1. hdc shell
2. cd /data/local/tmp
3. chmod +x ip cansend candump
之后执行ls,便可以看到移植的三个工具文件:

3 CAN功能验证
3.1 awlink开启
进入/data/local/tmp路径,使用如下指令打开两个awlink:
cpp
1. ./ip link set awlink0 type can bitrate 500000 # 设置awlink0波特率为500kbps
2. ./ip link set awlink1 type can bitrate 500000 # 设置awlink1波特率为500kbps
3. ./ip link set awlink0 up # 开启awlink0
4. ./ip link set awlink1 up # 开启awlink1
此时使用ifconfig,便可以看到打开的两个awlink:

3.2 回环验证
首先使用回环来验证awlink能否自发自收。在切换为回环模式前需要先使用如下指令来关闭两个awlink:
cpp
1. ./ip link set awlink0 down # 关闭awlink0
2. ./ip link set awlink1 down # 关闭awlink1
使用如下指令将awlink0设置为回环模式:
cpp
1. ./ip link set awlink0 type can bitrate 500000 loopback on
使用如下指令来启动监听接收:
cpp
1. ./candump awlink0 &
打开另一个终端,同样进入/data/local/tmp路径,使用如下指令来发送一帧数据:
cpp
1. ./cansend awlink0 123#DEADBEEF

可以看到回环测试成功了。
3.3 互ping测试
接下来测试两个awlink互发消息,看能否收发。由于涉及到两个awlink的信息传输,所以需要使用导线将两个awlink的H和H、L和L、GND和GND相连。
使用如下指令在awlink1上启动监听接收:
cpp
1. ./candump awlink1 &
使用如下指令使用awlink0发送一帧数据:
cpp
1. ./cansend awlink0 123#DEADBEEF

互ping测试成功,awlink1能收到awlink0发送的数据。
至此,基于OpenHarmony 5.0的CAN驱动移植完成,CAN已经能正常使用。
4 总结
虽然笔者使用的是全志T527芯片,但不同平台下Linux底层CAN移植的思路可谓"换汤不换药":
设备树开启 CAN 节点 -> defconfig 开启 SocketCAN 协议栈和底层驱动 ->交叉编译 32/64 位测试工具(避坑动态库) -> 板端启停与回环/物理验证
笔者对于OpenHarmony底层架构仍在不断学习中,发布本文旨在帮助填补相关领域的资料空白。文章如有纰漏或技术疑问,欢迎大家在评论区指正与交流!