CAN FD 协议概述

大家好。这一章我们先聊聊 CAN FD 的来龙去脉,以及它和传统 CAN 2.0 到底差在哪。

我个人最早接触 CAN 2.0 是在几年前的一个车载控制器项目里。那时候总线负载率一高,数据就得拆成好几帧发,还得算好优先级。后来发现国外同行已经开始用 CAN FD 了,我才开始系统琢磨这个升级版协议。说实话,刚开始看帧结构时有点懵 —— 多了不少位,跟我印象中的 CAN 差挺多。今天就按我的理解,带大家把基础打牢。

1.1 发展历程:从 CAN 2.0 到 CAN FD

CAN(Controller Area Network)由 Bosch 在 1986 年提出,1991 年确定了 CAN 2.0(分 A 和 B 两个版本)。CAN 2.0B 的 29 位扩展标识符加上每帧最多 8 字节数据,在很长时间里都是汽车 ECU 通信的主力。

问题出在哪?

  • 带宽不足:CAN 2.0 最高支持 1 Mbit/s(实际常用 500 kbit/s),做 OTA 升级或大数据量诊断时,一包数据要拆几十帧,延迟感人。
  • 有效载荷太小:每帧 8 字节,传个 4KB 的固件要发 500 多帧,浪费大量总线时间。

2011 年,Bosch 与业界伙伴推出了 CAN FD(CAN with Flexible Data-Rate)。我跟进的第一个项目就是移植一款 MCU 的 CAN FD 驱动库,摸爬滚打几个月,总算把收发器配置、位时序调通。

关键时间节点:

年份事件备注
1991CAN 2.0 标准确定8 字节 / 帧,1 Mbit/s
2011Bosch 公开 CAN FD 初版数据段可以跑更高比特率
2012标准化提交 CiA经多个组织测试验证
2015ISO 11898-1:2015 发布CAN FD 正式国际标准
2018ISO 11898-1:2015 更新补充了错误状态机等细节

有些芯片手册上把 CAN FD 和 TTCAN 放在一起提,但 TTCAN 是时间触发模式,CAN FD 是灵活数据率,两者定位完全不同。我一开始也搞混过。

1.2 帧结构差异:多出来的那些位

CAN FD 和 CAN 2.0 的帧结构很像,但仔细比较会发现几处关键变化。下面这张表是个人总结的差异点,项目开发时可以当备忘用。

字段/特性CAN 2.0(标准帧)CAN FD(标准帧)说明
控制段 bit6IDE(隐性=1)EDL(隐性=1 表示 FD 帧)二者占用同一位,接收方根据该位识别帧类型
控制段 bit0DLC(4 位,0~8)DLC(4 位,0~15)CAN FD 中 DLC 对应实际数据长度(见后表)
控制段保留位1 个 r0BRS(位速率切换标志)+ ESI(错误状态指示)CAN FD 占用了原来的 r0 和 r1 位
数据段最大长度8 字节64 字节这是最直观的升级
CRC 段15 位 CRC + 1 位 CRC 界定符17/21 位 CRC + 1 位 CRC 界定符根据数据长度选择 17 或 21 位 CRC
ACK 槽之后7 个隐性位(EOF)同 CAN 2.0,但位填充规则有差异数据段采用新的填充机制

我举个实际例子:CAN FD 的控制段中,原来 CAN 2.0 的 r0 位被改造成了 BRS 位。当 BRS = 显性时,仲裁段用标准速率,数据段切换到高速率;BRS = 隐性时,全程用仲裁速率。这个设计很巧妙 —— 仲裁段继续用传统速率保证总线仲裁稳定性,数据段才提速。

注意:CAN FD 帧里 DLC 不再是 0~8 直接对应字节数。DLC=9 对应 12 字节,10 对应 16,11 对应 20,12 对应 24,13 对应 32,14 对应 48,15 对应 64。我第一次写解码时没查表,直接把 DLC 当字节数用,结果一直丢帧。

1.3 与 CAN 2.0 的兼容性:能混跑吗?

这个问题我项目中被问过很多次:总线上一半传统节点、一半 FD 节点,能不能正常通信?

答案是:可以,但有前提。

  • 物理层兼容:CAN FD 使用相同的差分信号、总线电平、收发器接口。大多数 CAN FD 收发器(如 TJA1044、SN65HVD255)和普通 CAN 收发器是 pin-to-pin 兼容的。
  • 协议层兼容:CAN FD 帧的 SOF、仲裁段(11 位或 29 位标识符)、控制段的前几位与 CAN 2.0 完全一致。传统节点接收 FD 帧时,会在解析到 EDL 位(原 IDE 位)时发现该位状态不是预期的显性,从而引发格式错误,产生错误帧 —— 但 FD 节点会自行处理,不会让传统节点“误操作”。
  • 混合通信策略:要保证传统节点不参与 FD 帧的接收,可以在系统设计上让 FD 节点发送的标识符在传统节点侧被屏蔽,或者仅让传统节点监听,不参与 ACK。通常建议:如果混用,传统节点必须能容忍 FD 帧的“隐形 ACK”以及多出来的数据段位。

我记得第一次在实验室测试混用场景,一台只支持 CAN 2.0 的示波器解不出 FD 帧的数据,但能看到它发了错误帧 —— 说明传统节点确实会检测到格式错误并主动报错。后来我调整了 FD 节点的位时序,让数据段速率不高于 2 Mbit/s,错误帧就很少出现了。

核心结论:CAN FD 节点向下兼容 CAN 2.0,但反之不行。传统节点无法正确解析 FD 帧,只能“容忍”它的存在。如果你要升级既有网络,必须确保所有新节点都用 CAN FD,老节点要么换掉,要么确保它们不会因为收到 FD 帧而频繁报错阻塞总线。

1.4 CAN FD vs CAN 2.0 帧结构对比图

下面这张 SVG 图是我自己梳理的,把两种帧在控制段之后的差异直观对比出来。箭头走向就是实际发送顺序,左边是仲裁段——两边完全相同,右边是差异区。

CAN 2.0 vs CAN FD 帧结构对比(标准帧) CAN 2.0 帧流 仲裁段 控制段 数据 CRC (15位) ACK CAN FD 帧流 仲裁段 控制段(EDL) BRS/ESI 数据段 64B CRC (17/21位) ACK 关键差异点 1. CAN FD 控制段中使用 EDL(IDE 位的位置)表示这是 FD 帧,CAN 2.0 节点看到该位为隐性可能报错。 2. BRS 位决定是否在数据段切换高速率;ESI 位指示发送节点是否主动错误。 3. 数据段最大 64 字节(DLC 值详见 DLC-字节映射表)。 4. CRC 改用 17 位或 21 位,覆盖的数据范围更大,保护性更强。 5. 如果 BRS=0(全程低速),CAN FD 帧与 CAN 2.0 帧在物理层波形上几乎一样,只是控制段编码不同。

1.5 小总结:为什么要关注 FIFO 溢出

你想想看,CAN FD 一帧能塞 64 字节,数据段速率还能飙到 5 Mbit/s 甚至更高。如果 MCU 的 CAN 控制器 FIFO 深度不够,或者 CPU 来不及取走帧,FIFO 很容易溢出。我记得有一次测试,总线负载率才 30% 就频繁丢帧,查来查去发现是 FIFO 深度只有 64 字节(基于 8 字节帧配置),而 CAN FD 每帧 64 字节,一次中断就把 FIFO 塞满了。

所以,理解 CAN FD 帧结构的差异,是后续定位 FIFO 溢出的基本功。下一章我们就深入到具体 FIFO 工作机制,看看溢出到底是怎么发生的。

嗯,先消化这些吧。有问题可以翻回来看这张表。