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 corenet/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特有问题

  1. 位速率不匹配

    • 检查仲裁/数据段速率:ip -d link show can0
    • 确认硬件支持:dmesg | grep m_can
  2. 帧截断问题

    • 确认启用了CANFD:can_raw_setsockopt(s, CAN_RAW_FD_FRAMES, ...)
    • 检查驱动支持:ethtool -i can0
  3. 高错误率

    • 使用candump -e can0查看错误帧
    • 检查终端电阻和线缆质量
    • 调整采样点:ip link set can0 bitrate 500000 sample-point 0.875

10. 参考资料

posted @ 2026-06-29 15:52  Jaosn_chen  阅读(26)  评论(0)    收藏  举报