RK3568 CAN驱动配置与调试实战指南
1. 从零开始:认识RK3568的CAN控制器
大家好,我是老张,一个在嵌入式圈子里摸爬滚打了十多年的老码农。今天咱们不聊那些虚头巴脑的理论,直接上手干点实在的——给RK3568这颗国产“网红”芯片配好CAN总线驱动。我知道,很多刚接触工业控制或者汽车电子的朋友,一听到“驱动配置”、“设备树”这些词就有点发怵,觉得是Linux内核大佬们才玩得转的东西。别怕,今天我就用最“小白”的方式,带你一步步走通整个流程,保证你跟着做一遍,就能让你的RK3568板子跟其他CAN设备“对上话”。
首先,咱们得搞清楚RK3568的CAN控制器到底是个啥。简单来说,CAN(Controller Area Network)就是一种在汽车、工业自动化领域用得特别多的通信总线,它抗干扰能力强,能一根线上挂很多设备。RK3568芯片内部通常集成了两个CAN控制器,也就是我们常说的CAN1和CAN2。这两个控制器在硬件上是独立的,你可以把它们想象成两个独立的“对讲机”,可以同时跟不同的设备群组通信。我们软件工程师要做的,就是告诉Linux内核:芯片里的这两个“对讲机”硬件在哪里、怎么用、用多快的语速(波特率)说话。这个“告诉”的过程,主要就是通过修改设备树(Device Tree)文件来实现的。设备树就像一份给内核的“硬件接线图”,内核启动时按图索骥,就知道该去哪里初始化哪个硬件了。
所以,整个配置过程的核心思路非常清晰:改设备树,告诉内核CAN控制器在哪 → 编译内核,让改动生效 → 在系统里配置并测试CAN接口。听起来是不是没那么复杂了?咱们接下来就按这个思路,一步步拆解。我会把我在实际项目中踩过的坑、遇到的怪现象以及怎么解决的,都毫无保留地分享出来。你可能会发现,有些步骤跟官方文档写得不太一样,那是因为文档往往只告诉你理想路径,而实战中总会遇到点“惊喜”。准备好了吗?咱们先从最基础的硬件引脚确认开始。
2. 实战第一步:硬件引脚与设备树配置详解
配置驱动的第一步,永远是从硬件出发。你手头的RK3568开发板,CAN接口是通过哪些物理引脚引出来的?这个问题必须搞清楚,否则设备树配置就是空中楼阁。通常,核心板上的CAN控制器信号会通过排针或者连接器引到底板上,你需要找到底板原理图,确认CAN_TX(发送)和CAN_RX(接收)这两个关键信号连接到了RK3568的哪两个GPIO引脚上。
2.1 确认引脚与复用功能
这是我踩过的第一个坑:想当然地以为引脚定义是固定的。实际上,RK3568的引脚功能非常灵活,一个物理引脚可以通过内部寄存器配置成多种功能,比如普通GPIO、UART的TX,或者就是我们需要的CAN_TX。这个配置过程就叫“引脚复用”(Pin Mux)。
在你的内核源码目录下(比如linux-rockchip/arch/arm64/boot/dts/rockchip/),找到对应你板子的设备树源文件(.dts或.dtsi)。我们需要在里面找到关于CAN引脚配置的部分。通常,它会被定义成一个叫pinctrl的节点。根据你提供的原始文章线索,关键信息是can1m1_pins和can2m0_pins这两个东西。
can1m1_pins这个命名就很有讲究:“can1”指控制器1,“m1”很可能指的是复用功能选项1(Mux Function 1)。不同的复用选项(m0, m1, m2…)对应着不同的引脚。你必须根据你的实际硬件连接,去核对这个复用组(pinctrl group)里定义的引脚号,是否真的连接到了你底板上的CAN收发器芯片上。如果对不上,通信肯定失败。怎么核对?打开你的原理图,找到CAN收发器(比如TJA1050)的TXD和RXD脚,看它们连到了主控的哪个引脚,比如GPIO3_B1。然后去设备树里看can1m1_pins的定义,检查它包含的引脚是不是GPIO3_B1。这个步骤千万不能省,我见过太多人因为引脚复用没配对,调试了半天软件却发现是硬件连接没对应上。
2.2 编写与修改设备树节点
确认好引脚后,我们就可以正式修改设备树了。设备树里关于CAN控制器的节点通常已经由芯片厂商定义好了基础框架,我们需要做的是“启用”它,并设置正确的参数。下面我结合一个更详细的例子来解释:
/* 首先,确保在文件开头或包含的头文件里,有CAN控制器的定义 */ #include "rk3568-pinctrl.dtsi" // 通常引脚定义在这里面 /* 在 &i2c3, &spi1 这类同级位置,找到或添加CAN节点 */ &can1 { /* 最关键的一步:指定时钟。CAN控制器工作需要稳定的时钟源 */ assigned-clocks = <&cru CLK_CAN1>; /* 引用CAN1的时钟 */ assigned-clock-rates = <100000000>; /* 设置时钟频率为100MHz,这是CAN控制器工作的核心时钟,波特率基于此计算 */ /* 引脚控制配置,这里就用到我们之前确认的 pinctrl 组 */ pinctrl-names = "default"; /* 状态名,默认就够用 */ pinctrl-0 = <&can1m1_pins>; /* 将 can1m1_pins 这个引脚配置组应用给CAN1 */ /* 驱动兼容性设置,告诉内核用哪个驱动来匹配这个硬件 */ compatible = "rockchip,can-1.0"; // 或 "rockchip,canfd-1.0",取决于你用的驱动 /* 状态设为 okay,表示启用这个设备。如果设为 disabled,内核就会忽略它 */ status = "okay"; }; &can2 { assigned-clocks = <&cru CLK_CAN2>; assigned-clock-rates = <100000000>; pinctrl-names = "default"; pinctrl-0 = <&can2m0_pins>; // 注意,这里是 m0,可能和CAN1用的复用组不同 status = "okay"; };这里有几个容易出错的点:
- 时钟设置:
assigned-clock-rates = <100000000>;这行里的100MHz是常见值,但不是波特率。CAN通信的波特率(比如125kbps, 500kbps)是软件后期配置的,这个100MHz是控制器的输入工作时钟,必须正确,否则后续波特率计算会全错。有些板子可能需要不同的时钟频率,务必参考核心板的硬件设计手册。 - compatible属性:这个属性像是一个“暗号”,内核会根据这个字符串去驱动程序列表里寻找匹配的驱动。如果写错了,内核就找不到驱动,设备就无法初始化。通常,瑞芯微的CAN驱动支持
"rockchip,can-1.0"(标准CAN)和"rockchip,canfd-1.0"(CAN FD)。用哪个取决于你的硬件和驱动选择,后面会详细讲。 - status属性:一定要是
"okay",写错一个字母或者写成"disabled",这个设备就不会被激活。
修改完设备树源文件后,需要重新编译设备树二进制文件(.dtb),并更新到开发板上。编译命令通常在内核构建目录下,比如make dtbs。把生成的.dtb文件替换掉板子上/boot目录下的旧文件,然后重启。重启后,你可以通过dmesg | grep can或者ls /sys/class/net/命令查看内核是否成功识别到了CAN设备。如果看到了can0或can1这样的网络接口,恭喜你,硬件配置这关就过了。
3. 驱动选择与内核配置:标准CAN vs. CAN FD
设备树配置好,相当于给硬件搭好了舞台。接下来该演员(驱动程序)上场了。RK3568的Linux内核通常提供了两种CAN驱动,这可能是让很多新手困惑的地方:rockchip_can.c和rockchip_canfd.c。该用哪个?这不是一个随便二选一的问题,选错了可能会导致各种诡异的通信问题。
3.1 两种驱动的本质区别
简单来说,rockchip_can.c是标准的CAN控制器驱动,支持经典的CAN 2.0A/B协议。而rockchip_canfd.c,顾名思义,是支持CAN FD(Flexible Data-rate)协议的驱动。CAN FD是CAN的升级版,主要特点是数据传输速率更快,且一帧数据里能携带的字节数从8个最多可以扩展到64个。
但这里有个非常重要的实战细节:根据瑞芯微的文档和一些社区反馈(包括你提供的原始文章里提到的),即使你只使用标准的CAN通信(不启用FD的高速模式),在某些情况下,也可能需要使用rockchip_canfd.c这个驱动。为什么呢?因为rockchip_canfd.c驱动可能包含了针对某些芯片版本或特定通信问题的修复补丁(Patch)。你原文里提到的“对can发送扩展帧概率性变成标准帧,导致接收方存在丢帧”就是一个典型问题,而解决这个问题可能需要应用一个特定的补丁,这个补丁往往就集成在rockchip_canfd.c驱动里。
所以,我的选择建议是这样的:
- 如果你确定项目只使用经典CAN,且对稳定性要求极高,不想引入任何复杂因素:优先尝试使用
rockchip_can.c驱动。它更简单,可能更稳定。 - 如果你遇到奇怪的丢帧、帧格式错误问题,或者未来有升级到CAN FD的可能:直接使用
rockchip_canfd.c驱动。这个驱动是向下兼容标准CAN的,用它来跑标准CAN通信一般没问题,而且它可能已经修复了一些已知的硬件缺陷。
3.2 内核配置与编译
选好了驱动,我们得确保内核编译时把它包含进去。进入你的内核源码目录,执行make menuconfig(或make nconfig)打开配置界面。
- 导航到CAN总线子系统:
-> Networking support -> CAN bus subsystem support - 确保
CAN bus subsystem support被选中(按Y键,变成<*>)。 - 进入
CAN Device Drivers。 - 在这里找到瑞芯微的驱动选项。它们可能叫:
Rockchip CAN controller support(对应rockchip_can.c)Rockchip CAN FD controller support(对应rockchip_canfd.c)
- 根据你的选择,将对应的驱动编译进内核(
<*>)或者编译为模块(<M>)。对于嵌入式产品,我强烈建议直接编译进内核(<*>),这样系统启动后驱动就直接加载好了,省事。如果选为模块,你还需要手动insmod加载。 - 保存配置,退出,然后重新编译内核和模块:
make -j$(nproc)和make modules_install。
编译完成后,将新的内核镜像(比如Image)和设备树文件一起更新到开发板并重启。使用lsmod | grep can可以查看加载的CAN驱动模块,如果驱动编译进内核了,这个命令可能看不到,但可以通过dmesg日志来确认驱动初始化是否成功。
4. 系统配置与基础测试:让CAN接口动起来
内核成功识别了CAN控制器,驱动也加载了,现在我们终于可以在用户空间操作CAN接口了。在Linux系统中,CAN设备被抽象成了网络接口,就像eth0、wlan0一样,名字通常是can0、can1。我们需要用一些工具来配置和测试它。
4.1 安装CAN工具包
首先,确保你的文件系统里安装了iproute2和can-utils这两个工具包。iproute2是现代Linux管理网络接口(包括CAN)的主力工具,can-utils则提供了一系列专门用于CAN测试的命令行工具,如candump,cansend等。
在基于Debian/Ubuntu的系统上,可以这样安装:
sudo apt update sudo apt install iproute2 can-utils如果是Buildroot或Yocto等嵌入式构建系统,需要在系统配置菜单里选中这些包并重新构建根文件系统。
4.2 配置CAN接口参数
假设我们识别到的接口是can0。在通信之前,必须设置它的波特率和启动。这里我们用ip命令(来自iproute2)来操作,它比老旧的ifconfig和canconfig更强大和推荐。
- 停止接口(如果之前已启动):
sudo ip link set can0 down - 设置比特率(波特率):这是最关键的一步,通信双方(发送和接收设备)的波特率必须严格一致。
这里把sudo ip link set can0 type can bitrate 500000can0的波特率设置为 500kbps(即 500000 bps)。常见的波特率还有 125000 (125k), 250000 (250k), 1000000 (1M) 等。具体用多少,要看你的其他CAN节点设备支持多少。 - 启动接口:
sudo ip link set can0 up - 查看接口状态:
这个命令会输出详细状态,仔细看,里面应该会显示ip -details link show can0state UP(接口已启动),以及bitrate 500000(波特率设置正确)。如果状态是DOWN或者波特率不对,就需要检查前面的步骤。
4.3 最简单的自发自收测试
为了验证CAN通道本身是否通畅,我们可以做一个“自发自收”的环回测试。这需要将同一个CAN控制器的CAN_H和CAN_L短接起来(注意:是同一个控制器的H和L短接,形成环回,不是两个控制器对接)。但更常见的测试方法是,如果你板子上有两个CAN控制器(如can0和can1),可以把它们的CAN_H连到一起,CAN_L连到一起,让它们互相通信。
假设我们连接了can0和can1:
- 打开一个终端,启动
candump监听can1接口:
这个命令会阻塞在这里,等待并打印所有从candump can1can1接口接收到的CAN帧。 - 打开另一个终端,用
cansend通过can0发送一帧数据:
这帧数据的含义是:标准帧ID为cansend can0 123#11223344556677880x123,数据为8个字节0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88。 - 如果一切正常,你会在第一个终端(运行
candump的)看到类似下面的输出:
这表示can1 123 [8] 11 22 33 44 55 66 77 88can1成功接收到了来自can0的数据。恭喜,你的CAN通信链路基本打通了!
5. 进阶调试与疑难杂症排查
基础测试通过了,但实际项目往往没这么顺利。下面我分享几个我实际遇到过的“坑”以及排查思路,希望能帮你节省大量时间。
5.1 常见问题与排查命令
问题:
ip link命令根本看不到can0或can1接口。- 排查:这说明内核根本没识别到这个设备。第一步,检查
dmesg | grep -i can的内核启动日志。看看有没有CAN控制器初始化的成功或失败信息。常见的失败原因有:- 设备树配置错误:
status不是"okay",pinctrl引脚配置错误,compatible字符串不匹配。 - 时钟配置错误:
assigned-clock-rates设置的值不对,导致驱动初始化失败。可以尝试在设备树里暂时去掉时钟频率设置,让驱动用默认值试试。 - 驱动未编译:确认内核配置中确实选中了对应的CAN驱动并已编译。
- 设备树配置错误:
- 排查:这说明内核根本没识别到这个设备。第一步,检查
问题:接口能看到(
state UNKNOWN),但无法up,或up后很快又down。- 排查:这通常是物理层问题。执行
ip -details -statistics link show can0,关注输出里的错误计数,比如RX errors,TX errors,bus-error等。如果bus-error在疯狂增长,几乎可以断定是波特率设置错误,或者物理连接有问题(终端电阻、线缆)。CAN总线两端(最远的两个节点)必须各接一个120欧姆的终端电阻,测量CAN_H和CAN_L之间的电阻应该在60欧姆左右。
- 排查:这通常是物理层问题。执行
问题:能
up,candump也能看到自己发的数据,但连上其他CAN设备后收不到对方数据,或者对方收不到我的数据。- 排查:
- 波特率一致性:这是最最常见的原因!用示波器或者专业的CAN分析仪,测量一下总线上的实际波形,计算一下比特时间,看看和你软件设置的波特率是否一致。毫厘之差,通信即断。
- 帧格式:你发送的是标准帧(11位ID)还是扩展帧(29位ID)?接收方是否配置了相应的过滤器?在
cansend命令中,标准帧ID直接写,扩展帧ID需要在后面加个点,如cansend can0 12345678#11。 - 硬件问题:CAN收发器芯片(如TJA1050)是否损坏?电源是否正常?可以用万用表测量CAN_H和CAN_L对地的电压。当总线空闲时,CAN_H约2.5V,CAN_L约2.5V;有显性位时,CAN_H约3.5V,CAN_L约1.5V。
- 排查:
5.2 性能测试与压力测试
基础通信没问题后,你可能需要测试一下CAN总线的稳定性和性能极限。can-utils工具包里的cangen和canbusload就派上用场了。
- 生成随机流量:用
cangen在后台持续生成随机的CAN帧,模拟总线负载。
这个命令会在cangen can0 -g 10 -I i -L 8 &can0上以10毫秒间隔(-g 10)发送随机ID(-I i)、8字节数据(-L 8)的帧。 - 监控总线负载率:在另一个终端运行
canbusload,可以实时查看总线的利用率。
这里需要指定你设置的波特率(如500000)。它会计算当前总线上的数据量占理论最大带宽的百分比。长时间运行,观察负载率是否稳定,有没有错误帧激增。canbusload can0 500000 - 测试高负载下的稳定性:逐步减小
cangen的间隔(比如到1ms),增加数据长度,观察在接近总线理论带宽时,是否会出现大量错误帧或系统卡顿。这能帮你评估当前软硬件配置的稳定性边界。
6. 深入理解:CAN FD配置与高级应用
如果你的项目对数据吞吐量有更高要求,或者需要连接支持CAN FD的新设备,那么配置CAN FD就很有必要了。CAN FD的配置比标准CAN稍复杂一些,因为涉及到两个比特率:仲裁段波特率(和标准CAN类似,用于竞争总线)和数据段波特率(用于实际传输数据,可以更高)。
6.1 设备树与驱动准备
首先,确保你使用的是rockchip_canfd.c驱动,并且在设备树中,compatible属性要设置为"rockchip,canfd-1.0"。时钟配置通常和标准CAN一样。
6.2 使用 ip 命令配置CAN FD参数
配置CAN FD接口的命令格式如下:
# 先关闭接口 sudo ip link set can0 down # 设置FD模式、仲裁段波特率(500k)和数据段波特率(2M) sudo ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on # 启动接口 sudo ip link set can0 up关键参数解释:
bitrate 500000:仲裁段比特率,设为500kbps。dbitrate 2000000:数据段比特率,设为2Mbps。这个值可以比仲裁段高很多,但具体上限取决于你的硬件和收发器支持。fd on:启用CAN FD模式。
6.3 CAN FD数据收发测试
can-utils工具同样支持CAN FD。发送CAN FD帧需要使用-f参数,并且可以指定超过8字节的数据(最多64字节)。
# 发送一帧CAN FD数据,ID为0x555,数据为16个字节 cansend can0 -f 555#00112233445566778899AABBCCDDEEFF # 接收CAN FD帧,也需要使用 -f 参数来正确解析 candump can0 -f在candump的输出中,CAN FD帧会有特殊的标记。同时,强烈建议使用支持CAN FD的硬件分析仪(如Pcan, Vector等)进行对比测试,以确保帧格式和时序完全正确。切换到FD模式后,物理信号质量要求更高,布线干扰等问题会被放大,因此稳定性测试需要更充分。
整个配置和调试过程,从硬件引脚确认到高级FD功能测试,每一步都需要耐心和细致。嵌入式开发就是这样,大部分时间都在和细节较劲。但当你看到candump终端上稳定地滚动着来自其他设备的数据时,那种成就感是非常实在的。希望这份指南能成为你手上的RK3568与外界可靠对话的一块坚实垫脚石。如果在实际操作中遇到了上面没覆盖到的问题,不妨多看看内核的dmesg日志,那里面往往藏着最直接的线索。
