CAN/CAN-FD 驱动
本文档介绍 RK3588 内置 CAN 控制器在 Linux 6.1 内核中的驱动配置和设备树绑定,以及用户态 can-utils(SocketCAN 框架配套的一组命令行收发工具)的使用。在 Linux 里 CAN 总线被当成一种网络接口(SocketCAN 框架),用 ip 命令配置、用 socket 收发。
适用范围: RK3588 Linux 6.1 Debian 12 / Ubuntu 22.04 系统,C-3588LQ V1.0 + SHIMETAPI-M5-R2A V1.0 底板。
1. 概念基础
1.1 CAN 是什么
CAN(Controller Area Network)是一种多主串行通信总线,用 CAN_H、CAN_L 两根线上的电压差(差分信号)表示逻辑电平,抗干扰能力强,广泛用于车载和工业控制。RK3588 内置 3 路 CAN 控制器,支持:
- CAN 2.0B(11/29 位 ID)
- CAN FD(数据段最高 8 Mbps、最多 64 字节)
- 经典帧与 FD 帧并存
| 帧类型 | 数据速率 | 数据长度 |
|---|---|---|
| CAN 2.0B | 最高 1 Mbps | 最多 8 字节 |
| CAN FD | 数据段最高 8 Mbps | 最多 64 字节 |
1.2 应用场景
- 车载 OBD 诊断、CAN 仪表盘
- 工业总线传感器 / 执行器
- 机器人伺服电机
- BMS 储能管理
1.3 控制器基地址
| 控制器 | 基地址 |
|---|---|
| CAN1 | 0xfea80000 |
| CAN2 | 0xfea90000 |
| CAN3 | 0xfeaa0000 |
2. 准备工作
2.1 硬件清单
| 组件 | 型号/规格 | 数量 | 备注 |
|---|---|---|---|
| 主控板 | C-3588LQ 核心板 + SHIMETAPI-M5-R2A 底板 | 1 | |
| 调试串口线 | USB 转 TTL(3.3V) | 1 | 波特率 1500000 |
| CAN 收发器 | TJA1050 / SN65HVD230 | 1 | 3.3V CAN 收发器 |
| CAN 分析仪(可选) | PCAN / CANalyst-II | 1 | 用于 CAN 通信调试 |
| 杜邦线 | 母对母 | 若干 | |
| 120Ω 终端电阻 | 1/4W | 2 | CAN 总线两端各一个 |
2.2 引脚连接
以 CAN1 为例:
| 主控板引脚 | CAN 收发器 | 功能 |
|---|---|---|
| CAN1_TX(底板标注) | TXD | CAN TX |
| CAN1_RX(底板标注) | RXD | CAN RX |
| 3.3V | VCC | 电源 |
| GND | GND | 共地 |
注意:CAN 收发器的 TXD / RXD 与 SoC 交叉(SoC TX 接收发器 RX,反之亦然)。CAN_H / CAN_L 走线注意双绞。
2.3 总线终端电阻
注意:CAN 总线两端必须各接一个 120Ω 终端电阻,用于吸收信号、防止反射;中间节点不可再加终端。
3. 软件准备
3.1 内核配置
CONFIG_CAN=y
CONFIG_CAN_VCAN=y /* 虚拟 CAN(测试用) */
CONFIG_CAN_RAW=y /* RAW 协议 */
CONFIG_CAN_BCM=y /* BCM 协议 */
CONFIG_CAN_GS_CAN=y /* 通用 SocketCAN */
CONFIG_CAN_ROCKCHIP=y /* RK CAN 控制器驱动 */
CONFIG_OF=y驱动源码
drivers/net/can/rockchip/rockchip-canfd.c。
3.2 设备树
can1: can@fea80000 {
compatible = "rockchip,rk3588-can", "rockchip,rk3568-can";
reg = <0x0 0xfea80000 0x0 0x1000>;
interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru CLK_CAN1>, <&cru PCLK_CAN1>;
clock-names = "can", "apb_pclk";
resets = <&cru SRST_CAN1>, <&cru SRST_H_CAN1>;
reset-names = "can", "can-apb";
status = "okay"; /* 需在板级 dts enable */
};4. 设备端 CAN 操作
4.1 当前内核是否已使能 CAN
ip link show type can实机输出如下:
(空)本机出厂镜像未自动 enable CAN 控制器。如需使用,需 PC 端 DTS enable 后重编译烧录。
4.2 加载驱动并使能(PC 端)
[电脑端] 编辑板级 .dts:
&can1 {
status = "okay";
pinctrl-0 = <&can1m0_xfer &can1m0_txen>;
pinctrl-names = "default";
/* 时钟源(0 = osc, 1 = pclka);与硬件 BOM 匹配 */
rockchip,can-clk-Source = <0>;
};电脑端 重新编译烧录后,设备端再次运行 ip link show type can,能看到 can0 之类的接口就说明生效了。
5. CAN 接口配置(设备端,需先 enable)
5.1 经典 CAN 启动
# 设置 500 kbps 并 up
ip link set can0 type can bitrate 500000
ip link set can0 up
# 查看接口详情
ip -details link show can05.2 CAN FD 启动
# 仲裁段 500 kbps、数据段 2 Mbps、启用 FD
ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on
ip link set can0 up5.3 关闭接口
ip link set can0 down6. 收发 CAN 帧
6.1 安装 can-utils
apt install -y can-utils6.2 发送帧
# 标准帧:ID = 0x123,3 字节数据
cansend can0 123#112233
# 扩展帧(29 位 ID)
cansend can0 12345678#1122334455667788
# CAN FD 帧(双 # 分隔 BRS=1 与 64 字节 payload)
cansend can0 123##1.1122334455667788AABBCCDDEEFF006.3 接收帧
# 持续监听
candump can0
# ID 过滤 + 掩码
candump can0,123:7FF
# 保存日志
candump -L can0 > can_log.txt6.4 查看统计
cat /sys/class/net/can0/statistics/tx_bytes
cat /sys/class/net/can0/statistics/rx_bytes
cat /sys/class/net/can0/statistics/tx_errors
cat /sys/class/net/can0/statistics/rx_errors7. 内核调试接口
# CAN 控制器状态
cat /sys/kernel/debug/can/registers
# 控制器时钟
cat /sys/kernel/debug/clk/clk_can/clk_rate8. 代码解读
8.1 驱动注册
// drivers/net/can/rockchip/rockchip-canfd.c(简化)
static struct platform_driver rockchip_can_driver = {
.probe = rockchip_canfd_probe,
.remove = rockchip_canfd_remove,
.driver = {
.name = "rockchip-canfd",
.of_match_table = rockchip_canfd_match,
},
};
static const struct of_device_id rockchip_canfd_match[] = {
{ .compatible = "rockchip,rk3588-can" },
{ /* sentinel */ }
};8.2 调用链
用户空间: cansend can0 123#112233
→ socket(PF_CAN, SOCK_RAW, CAN_RAW)
→ bind() 绑定 can0
→ write() CAN 帧
→ can_send()
→ rockchip_canfd_start_xmit()
→ 写入 CAN 控制器发送 FIFO9. 故障排除
9.1 CAN 接口不存在
ip link show type can
# 空输出 → 设备树未 enable 内核未加载再检查内核日志和节点状态:
dmesg | grep -i can
cat /proc/device-tree/soc/can@fea80000/status9.2 启动失败 / 报错
# 时钟异常最常见
cat /sys/kernel/debug/clk/clk_can/clk_rate
# 终端电阻不对(常见:未接或错接)
# 收发器 TX/RXD 交叉顺序9.3 无数据 / 错误帧
# 看错误统计
cat /sys/class/net/can0/statistics/rx_errors
# 复位接口
ip link set can0 down
ip link set can0 type can bitrate 500000
ip link set can0 up如果仍然不通,再检查终端电阻、收发器供电、差分信号波形以及收发方向的接线。
