从经典 CAN 到 CAN FD 的演进

我们平时说的「CAN FD 标准」,其实是一对兄弟——ISO 11898‑1:2015 和 ISO 11898‑2:2016。前者管的是链路层和协议,后者管的是物理层和收发器。我刚开始接触 CAN FD 时,也以为只有一个标准,结果在选型时发现收发器居然有好多版本…

说白了,这两个标准合在一起才构成了完整的 CAN FD 规范。2015 年 ISO 把 CAN FD 的协议部分正式纳入 ISO 11898‑1,2016 年又更新了物理层标准 ISO 11898‑2,新增了 CAN FD 所要求的更高速率通讯能力。你想想看,如果只拿 11898‑1 去设计,硬件的时序根本跑不动 8 Mbps 的仲裁速率,肯定会出问题。

⚠️ 注意: 千万不要混用经典 CAN 的收发器和 CAN FD 控制器。我曾在一个项目中因为用了便宜的 TJA1050(只支持 1 Mbps),结果 CAN FD 数据段跑到 4 Mbps 时总线上一片啸叫……后来换了 TJA1463 才消停。

ISO 11898‑1:2015 —— 数据链路层与协议

这条标准定义了 CAN FD 的数据链路层,包括帧格式、错误检测、位填充、仲裁机制等等。经典 CAN 用的是 11 位或 29 位 ID,而 CAN FD 在控制场里加了 EDL、BRS、ESI 三个新位。其中 EDL(Extended Data Length)专门用来区分是经典帧还是 FD 帧。

我记得有一次调试时,逻辑分析仪抓到的报文里 EDL 位老被解析成 0,结果是配置库的宏定义写错了。所以我的建议是:在初始化代码里显式设置 CAN FD 使能位,不要依赖默认值。

💡 小技巧: 读取 ID 寄存器时,顺手把 EDL 和 BRS 的状态也打印出来。我用这个办法快速定位过好几回「该发 FD 帧却发了经典帧」的 bug。
  • 帧格式新增: CAN FD 允许数据场长度从 8 字节扩展到 64 字节。
  • CRC 区变化: 大于 16 字节的数据场使用 21 位 CRC,其余用 17 位 CRC。
  • 采样点与位时序: FD 模式下数据段的位时间比仲裁段压缩很多,需要重新计算 TSEG1 和 TSEG2。

ISO 11898‑2:2016 —— 物理层与收发器

这一版主要升级了收发器的对称性和共模范围,支持数据段速率最高到 8 Mbps(甚至更高,看具体实现)。与经典 CAN 相比,CAN FD 物理层对总线电压的压摆率和信号对称性要求更严格。说白了,线束上的寄生电容和电缆长度直接影响你能跑多快。

我曾经在一条 3 米长的双绞线上试过 5 Mbps 通讯,结果误码率高达 2%。后来看了 TI 的应用手册才发现:CAN FD 的物理层需要更短的 stub(分支)长度,最好小于 0.3 米。实测把分支剪到 10 cm,误码率直接降为 0。

参数经典 CAN (ISO 11898‑2:2003)CAN FD (ISO 11898‑2:2016)
最大数据段速率1 Mbps≥ 2 Mbps(典型 5~8 Mbps)
收发器对称性± 5%± 2%
总线共模范围-2 V ~ 7 V-12 V ~ 12 V
上升/下降时间一般 50 ~ 150 ns需控制在 15 ~ 50 ns

两个标准的实际协同

ISO 11898‑1 和 ISO 11898‑2 就像一对配合默契的搭档:链路层负责把数据包组织好,物理层负责把信号发出去。如果你只实现了协议部分却选了慢速的收发器,那么 CRC 校验没问题但信号已经被反射和振铃吃掉了,总线照样报错。

我通常在设计初期就按照下面的分层图把标准责任划清楚,然后分别选择支持 CAN FD 的 MCU 和对应速率等级的收发器。这样一来,评审时也不会漏掉物理层的约束。

CAN FD 协议栈与 ISO 标准对应关系 应用层 (通常由用户或高层协议定义) 数据链路层 帧格式 · 错误检测 · 位填充 ISO 11898‑1:2015 物理层 收发器 · 总线电平 · 时序 ISO 11898‑2:2016 介质(双绞线 / 线束) 电缆 · 终端电阻 · 分支 链路层 & 物理层 共同决定通讯可靠性 收发器要支持 目标数据段速率

初始化配置示例(基于 STM32 G4 的 CAN FD)

下面是一段典型的 CAN FD 初始化代码片段,重点在设置 FDCAN 模式和位时序。注意数据段速率和仲裁段速率分开配置:

/* 使能 CAN FD 功能 */
hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_BRS;
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;

/* 仲裁段:500 kbps */
hfdcan1.Init.NominalSyncJumpWidth = 2;
hfdcan1.Init.NominalTimeSeg1 = FDCAN_NOMTSEG1_10TQ;
hfdcan1.Init.NominalTimeSeg2 = FDCAN_NOMTSEG2_5TQ;

/* 数据段:4 Mbps */
hfdcan1.Init.DataSyncJumpWidth = 2;
hfdcan1.Init.DataTimeSeg1 = FDCAN_DATATSEG1_4TQ;
hfdcan1.Init.DataTimeSeg2 = FDCAN_DATATSEG2_1TQ;

if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
{
    Error_Handler();
}

我个人习惯在配置完后,先发一个只含 8 字节数据的 FD 帧,再发一个 64 字节的帧,看回环模式下的 CRC 是否一致。这样能快速验证硬件层和链路层是否握手成功。

✅ 记住: 数据段速率越高,TSEG1 和 TSEG2 的比值越要靠近 80% / 20% 的采样点经验值。我曾经因为随手改了个 50% / 50% 导致通讯时好时坏,排查了整整两天。

避坑指南:测试 CAN FD 标准的两个常见误区

  1. 以为所有 CAN 收发器都支持 FD: 看数据手册的「CAN FD capable」标记,否则高速时会出现位错误。
  2. 忽略物理层共模范围: 在恶劣环境(比如重型车辆)中,共模干扰会使收发器输出误码。这时候选 ±12 V 范围的 FD 收发器就很有必要。

这些规范说起来简单,但实际落地时每个细节都可能变成瓶颈。把 ISO 11898‑1 和 11898‑2 当作你的设计伴侣,一条一条验证,就不会在原型阶段熬夜了。