Linux 5.10 CAN/CANFD机制详解
1. 版本背景
- 发布时间:2020年12月13日
- CAN支持状态:CANFD支持完全稳定,成为主流应用方案
- 关键里程碑:
- CANFD协议栈完全生产就绪
- 支持ISO 11898-1:2015标准
- 新增多种CANFD控制器驱动
- 网络命名空间支持完善
2. 子系统架构
架构演进
+---------------------+
| 用户空间 |
| SocketCAN API |
| + CANFD扩展 |
+----------+----------+
|
+----------v----------+
| 内核空间 |
| CAN协议栈核心 |
| + CANFD协议层 |
+----------+----------+
|
+----------v----------+
| CAN/CANFD设备驱动 |
+----------+----------+
|
+----------v----------+
| CAN硬件 |
+---------------------+
新增核心组件
- canfd core:
net/can/canfd.c处理CANFD帧 - flexible data-rate:位速率切换机制
- 增强过滤器:支持CANFD特定过滤
- 新驱动:
c_can,m_can,xilinx_can等支持CANFD
3. 源码深度解析
CANFD初始化流程
// net/can/canfd.c
int canfd_register(void)
{
can_proto_register(&canfd_proto);
register_netdevice_notifier(&canfd_notifier);
return 0;
}
static struct can_proto canfd_proto = {
.type = SOCK_RAW,
.protocol = CAN_RAW,
.ops = &canfd_ops,
.prot = &canfd_prot,
};
- 关键数据结构:
struct canfd_frame { canid_t can_id; /* 仲裁ID */ __u8 len; /* 数据长度 (0-64) */ __u8 flags; /* 帧标志 */ __u8 __res0; /* 保留 */ __u8 __res1; /* 保留 */ __u8 data[CANFD_MAX_DLEN]; /* 数据 (64字节) */ };
位速率切换机制
// drivers/net/can/m_can/m_can.c
static int m_can_set_bittiming(struct net_device *dev)
{
struct m_can_priv *priv = netdev_priv(dev);
struct can_berr_counter *bec = &priv->bec;
/* 数据段位定时设置 */
priv->regs->DBTP = (priv->dbtp.arbitration & DBTP_DSJW_MASK) |
(priv->dbtp.dpropseg << 16) |
(priv->dbtp.dphase_seg1 << 20) |
(priv->dbtp.dphase_seg2 << 24);
/* 同步跳跃宽度 */
priv->regs->CCCR |= CCCR_BRSE;
return 0;
}
- 关键参数:
arbitration_baudrate:仲裁段波特率data_baudrate:数据段波特率sample_point:采样点位置
4. CANFD实现细节
帧格式差异
| 特性 | CAN 2.0 | CANFD |
|---|---|---|
| 数据长度 | 0-8字节 | 0-64字节 |
| 位速率 | 单一速率 | 双速率 (仲裁/数据段) |
| CRC算法 | 15位 | 17/21位 |
| 帧类型标识 | RTR位 | FDF位 |
CANFD帧处理流程
用户空间 → socket(PF_CAN, SOCK_RAW, CAN_RAW)
→ can_raw_sendmsg()
→ canfd_send()
→ can_get_berr_counter()
→ 硬件驱动 → CAN控制器
- 关键区别:
canfd_send()处理64字节数据- 位速率切换在帧开始后自动触发
- 增强的CRC校验算法
5. 性能特性
基准测试数据
| 指标 | CAN 2.0 | CANFD |
|---|---|---|
| 最大数据长度 | 8字节 | 64字节 |
| 最大波特率 | 1Mbps | 5Mbps (数据段) |
| 吞吐量 | 6500帧/秒 | 18000帧/秒 |
| 传输延迟 | 120μs | 65μs |
性能优化技术
- 批量传输:
canfd_sendmsg()支持批量发送 - 零拷贝:
CONFIG_CAN_FD_RAW配置选项 - 中断合并:
priv->can.ctrlmode |= CAN_CTRLMODE_BERR_REPORTING
6. 安全机制
增强安全特性
-
CANFD过滤:
struct can_filter filter[] = { {.can_id = 0x123 | CAN_EFF_FLAG, .can_mask = 0x7FF | CAN_EFF_MASK, .can_fd_frames = 1} }; -
命名空间隔离:完整支持网络命名空间
-
错误监控增强:
- 详细错误计数器:
/sys/class/net/can0/can_berr_counter - 实时错误报告:
ip -d -s link show can0
- 详细错误计数器:
7. 版本对比
| 特性 | Linux 4.19 | Linux 5.10 |
|---|---|---|
| CANFD支持 | 实验性 | 生产就绪 |
| 最大数据长度 | 64字节 | 64字节 |
| 最大波特率 | 2Mbps | 5Mbps |
| 网络命名空间 | 部分支持 | 完整支持 |
| can-utils工具 | 基础支持 | 完整CANFD支持 |
8. 实战配置示例
配置CANFD接口
# 设置CANFD接口 (500kbps仲裁, 2Mbps数据段)
ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on
ip link set can0 up
# 使用candump查看CANFD流量
candump -L can0 # -L 参数显示CANFD帧
# 发送CANFD帧
cansend can0 123##21.22.23.24.25.26.27.28.29.30.31.32
CANFD编程示例
int s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
int enable_canfd = 1;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd));
struct canfd_frame frame;
frame.can_id = 0x123;
frame.len = 64; // CANFD最大长度
for (int i = 0; i < 64; i++) {
frame.data[i] = i;
}
write(s, &frame, CANFD_FRAME_SIZE);
9. 故障排查指南
CANFD特有问题
-
位速率不匹配
- 检查仲裁/数据段速率:
ip -d link show can0 - 确认硬件支持:
dmesg | grep m_can
- 检查仲裁/数据段速率:
-
帧截断问题
- 确认启用了CANFD:
can_raw_setsockopt(s, CAN_RAW_FD_FRAMES, ...) - 检查驱动支持:
ethtool -i can0
- 确认启用了CANFD:
-
高错误率
- 使用
candump -e can0查看错误帧 - 检查终端电阻和线缆质量
- 调整采样点:
ip link set can0 bitrate 500000 sample-point 0.875
- 使用
10. 参考资料
- 内核源码:
net/can/canfd.c,drivers/net/can/* - SocketCAN文档:https://www.kernel.org/doc/html/latest/networking/can.html
- CANFD规范:ISO 11898-1:2015
- Linux CAN邮件列表:https://vger.kernel.org/vger-lists.html#linux-can

浙公网安备 33010602011771号