1. CAN FD 协议基础:从 CAN 2.0 到 CAN FD 的进化

各位同学,咱们直接进入正题。CAN FD 这玩意儿,说白了就是 CAN 2.0 的升级版。我最早接触 CAN 总线是在做车载网关项目的时候,那时候用的还是经典 CAN,跑 500kbps 的波特率,一帧数据最多带 8 个字节。后来项目要求升级固件 OTA,8 个字节一帧地传,那速度真是让人抓狂。嗯,CAN FD 就是来解决这个痛点的。

1.1 CAN FD 与 CAN 2.0 的核心区别

先看一张对比表,把差异摆到台面上来:

对比项 CAN 2.0(经典 CAN) CAN FD
最大数据段长度 8 字节 64 字节
最大波特率(数据段) 1 Mbps(固定) 最高 8 Mbps(可切换)
帧格式 标准帧 / 扩展帧 兼容 CAN 2.0 + FD 帧
位速率切换 不支持 支持(BRS 位控制)
错误状态指示 无 支持(ESI 位)
CRC 校验 15 位 / 17 位 17 位 / 21 位(更强)

你看,最直观的变化就是数据段从 8 字节跳到了 64 字节。我在做电池管理系统(BMS)的时候,一包电池数据有 48 个单体电压,用经典 CAN 得拆成 6 帧发,用 CAN FD 一帧搞定。这不仅仅是省时间,更重要的是数据一致性——你想想看,6 帧数据在总线上传输时,中间可能被其他节点打断,数据完整性就打了折扣。

1.2 CAN FD 帧结构详解

CAN FD 的帧结构,我建议你把它拆成三段来理解:仲裁段、控制段、数据段。咱们以数据帧为例,画个结构图:

CAN FD 数据帧结构(标准帧格式) SOF ID (11 bit) 仲裁段 RTR IDE EDL (FDF) BRS ESI DLC (4 bit) 数据段 (0~64 字节) 高速率传输区 CRC 17/21 bit ACK EOF 仲裁段 控制段 数据段 CRC 关键说明: • SOF ~ IDE 段:与 CAN 2.0 完全兼容,波特率固定为仲裁段速率 • EDL (FDF) 位:=1 表示 FD 帧,=0 表示经典 CAN 帧 • BRS 位:=1 时数据段切换到高速率,=0 时保持仲裁段速率 仲裁段速率(典型 500 kbps) 数据段速率(典型 2~5 Mbps)

我的经验之谈:刚开始用 CAN FD 时,我犯过一个低级错误——把 EDL 位和 BRS 位搞混了。EDL 位决定这是不是 FD 帧,BRS 位决定数据段要不要跑高速。这两个位是独立的,你可以发一个 EDL=1、BRS=0 的帧,那就是 FD 帧但数据段不加速。我曾经在调试时发现总线一直报错,查了半天,原来是 EDL 位没置 1,接收端把它当经典 CAN 帧解析了,CRC 校验当然过不了。

1.3 数据段长度编码(DLC)

DLC 在 CAN FD 里和经典 CAN 不一样了。经典 CAN 的 DLC 直接对应字节数,0~8。CAN FD 的 DLC 编码做了扩展,但并不是线性映射到 64 的。看这张表:

DLC 值(4 bit) 经典 CAN 数据长度 CAN FD 数据长度
0 ~ 8 0 ~ 8 字节 0 ~ 8 字节
9 8 字节 12 字节
10 8 字节 16 字节
11 8 字节 20 字节
12 8 字节 24 字节
13 8 字节 32 字节
14 8 字节 48 字节
15 8 字节 64 字节

注意看,DLC 值 9~15 在经典 CAN 里都表示 8 字节,但在 CAN FD 里分别对应 12、16、20、24、32、48、64 字节。这个设计是为了向后兼容——经典 CAN 控制器收到 DLC=9 的帧,依然按 8 字节处理,不会出错。

避坑指南:我曾经在配置 STM32H7 的 CAN FD 外设时,直接写了 DLC=15 想发 64 字节,结果发现发送缓冲区只传了 8 个字节出去。后来查手册才发现,DLC 寄存器写入的是编码值,但数据长度寄存器(比如 FDCAN_DLC)需要配合数据字节数寄存器一起设置。嗯,细节决定成败。

1.4 位速率切换(BRS)

BRS 位是 CAN FD 最实用的特性之一。它允许你在同一帧内使用两种波特率:

  • 仲裁段:使用较低波特率(典型 500 kbps),保证总线仲裁的可靠性
  • 数据段:切换到较高波特率(典型 2~5 Mbps),提升数据传输效率

为什么会这样设计?你想想看,仲裁段需要所有节点以相同速率监听总线,如果速率太高,信号在长距离传输时反射和衰减会严重影响仲裁的准确性。但数据段不一样,它只涉及发送节点和接收节点,只要收发器支持,跑快点完全没问题。

我在实际项目中测试过,用 500 kbps 仲裁 + 4 Mbps 数据段,传输 64 字节数据的时间从经典 CAN 的约 1.2 ms 降到了约 0.25 ms,效率提升了近 5 倍。这对于需要实时传输大量数据的场景(比如激光雷达点云、高分辨率图像)来说,意义重大。

注意:BRS 位只在 FD 帧(EDL=1)中有效。如果你在经典 CAN 帧里置了 BRS=1,接收端会忽略这个位,不会切换速率。另外,数据段速率不能超过收发器的物理限制,比如 TJA1044T 最高支持 5 Mbps,而 TJA1463 可以到 8 Mbps。选型时一定要看数据手册。

1.5 错误状态指示(ESI)

ESI 位是 CAN FD 新增的,用来指示发送节点的错误状态。它的逻辑很简单:

  • ESI = 0:发送节点处于 Error Active 状态,可以正常发送和接收
  • ESI = 1:发送节点处于 Error Passive 状态,只能发送被动错误帧

这个位有什么用?我举个例子。在经典 CAN 里,如果一个节点频繁出错,它会进入 Bus Off 状态,完全脱离总线。但在 CAN FD 里,ESI 位让接收节点提前知道发送节点的健康状况。如果收到 ESI=1 的帧,接收节点可以主动减少与该节点的通信,或者触发诊断流程。

我记得有一次在产线测试中,一批 ECU 频繁报错,排查后发现是某个节点的 CAN 收发器虚焊,导致信号质量差。那个节点反复进入 Error Passive 状态,发出的帧 ESI 位一直为 1。通过监控 ESI 位,我们快速定位了问题批次,避免了大规模返工。

总结一下:CAN FD 不是颠覆性的新技术,它是在 CAN 2.0 基础上的增量升级。核心变化就四点——更大的数据段、可切换的速率、更灵活的帧结构、更智能的错误指示。掌握了这些基础,后面配置 STM32 的 CAN FD 外设时,你就能理解每个寄存器位是干什么用的了。