3. CAN FD 帧结构:四种帧类型的归纳与实战
老规矩,咱们先看一张全景图,把 CAN FD 的四种帧放在一起看看。这四种帧就像交通信号灯——各有各的职责,搞混了总线就要出乱子。
3.1 数据帧——最常用的“信息快递”
数据帧占了我日常调试中 90% 的流量。它负责把一个节点产生的数据发给其他节点。CAN FD 的数据帧和经典 CAN 长得像,但加速段和后边数据场不一样。
标准数据帧(11 位 ID)结构:
- SOF(帧起始): 1 个显性位,所有节点同步的起点。我习惯管它叫“发令枪”。
- 仲裁段: 11 位 ID + RTR 位(数据帧固定为显性)+ IDE 位(显性表示标准帧)。
- 控制段: FDF 位(CAN FD 帧为隐性)+ BRS 位(决定是否加速)+ ESI 位 + DLC(数据长度码,4 位)。注意 CAN FD 的 DLC 可以编码 0~64 字节,不是经典 CAN 的 8 字节上限。
- 数据段: 0~64 字节,如果 BRS 为隐性,则这一段用更快的数据位速率传输。
- CRC 段: 17 位或 21 位 CRC(取决于数据长度),末尾加一位 CRC 分隔符。
- ACK 段: 2 位(ACK 槽 + 分隔符)。
- EOF(帧结束): 7 个隐性位。
扩展数据帧(29 位 ID): 仲裁段多出 18 位扩展 ID,IDE 位变为隐性,SRR 位替换原来的 RTR 位置。剩下的结构跟标准帧一样。
我个人习惯在配置 CAN FD 控制器时,把 BRS 位和 ESI 位搞清楚。BRS 位搞反了会导致数据场用低速传输,白白浪费 FD 优势。有一次我帮客户排查一个 2Mbps 波特率下丢帧的问题,最后发现是 BRS 位被强制写成了显性……
3.2 远程帧——“谁有数据,发给我”
远程帧跟数据帧长得几乎一样,唯一的区别是 RTR 位为隐性。远程帧本身不带数据场(DLC 是请求的数据长度,但实际帧里没有数据字节)。
你想想看,当一个节点想从另一个节点获取数据时,它就会发远程帧。比如传感器节点发一个远程帧请求“温度值”,负责采集温度的节点收到后,立即回复一个数据帧。
远程帧也分标准和扩展格式,仲裁过程跟数据帧完全一样。注意:远程帧的优先级低于同 ID 的数据帧,因为数据帧的 RTR 是显性,仲裁时获胜。
我曾经踩过一个坑:在 CAN FD 模式下,有些控制器不允许远程帧使用大于 8 字节的 DLC 值,否则会触发错误帧。所以即使 FD 支持 64 字节,远程帧的 DLC 最好还是限制在 0~8,兼容性更好。
3.3 错误帧——“总线出事了!”
错误帧不是由节点主动发送的,而是当节点检测到错误时自动发出的“警报”。它由两部分组成:
- 错误标志: 6 个连续显性位(主动错误节点)或 6 个连续隐性位(被动错误节点)。
- 错误界定符: 8 个连续隐性位。
为什么是 6 个显性位?因为标准协议规定,任何节点只要检测到显性位连续 6 个相同,就会视为位填充错误。主动错误节点发 6 个显性位,强制打破总线状态,迫使所有节点进入错误处理流程。
错误帧触发的常见原因:
- 位填充错误(连续 5 个相同电平后,第 6 个必须翻转)。
- CRC 错误(接收节点算出来的 CRC 跟帧里的不一样)。
- 形式错误(固定的隐性位被显性污染,比如 CRC 分隔符)。
- ACK 错误(发送节点没收到显性应答位)。
避坑指南: 我曾经在一个项目里发现 CAN FD 总线频繁报错误帧。抓波形一看,CRC 分隔符本该是隐性位,但总线上显示为显性。原来是终端电阻匹配不对,导致信号反射把分隔符冲坏了。你想想看,CAN FD 速率高,终端电阻和线缆长度一定要按数据手册严格控制。
3.4 过载帧——“太快了,等等我”
过载帧和错误帧的结构完全一样:6 个显性位 + 8 个隐性位。区别在于触发条件:
- 过载条件: 节点内部接收缓冲区已满,或帧间间隔(ITM)过短导致节点来不及准备。
- 发送时机: 节点在帧间间隔的第一位或第二位发送过载帧。
说实话,实际项目中过载帧很少见。大部分芯片的接收 FIFO 深度足够,只要 DLC 不乱设,很少把缓冲区撑爆。不过有一种情况我遇到过:某款 MCU 的 CAN FD 控制器只支持 2 层 FIFO,高频发送 64 字节数据帧时,接收端处理不过来就发过载帧。解决方法要么降速,要么加大 FIFO 深度。
3.5 四种帧的对比总结
看表最清楚:
| 特性 | 数据帧 | 远程帧 | 错误帧 | 过载帧 |
|---|---|---|---|---|
| 发送者 | 任意节点 | 请求节点 | 检测到错误的节点 | 接收过载的节点 |
| 触发方式 | 主动发送 | 主动发送 | 事件触发 | 事件触发 |
| 数据场 | 0~64 字节 | 无数据场 | 无 | 无 |
| RTR 位 | 显性 (0) | 隐性 (1) | 不适用 | 不适用 |
| 帧格式 | 标准/扩展 | 标准/扩展 | 固定(无 ID) | 固定(无 ID) |
| 长度 | 随数据变化 | 44/64 位(无数据) | 14 位 | 14 位 |
| 优先级 | 高(同 ID 下最高) | 低 | 最高(打断任何帧) | 次高 |
3.6 实战要点:如何区分帧类型?
你调试 CAN FD 时,拿到一个波形或逻辑分析仪的捕获,怎么判断它是哪种帧?我教一个套路:
- 看帧起始: SOF 显性位后,如果是连续 11 位或 29 位 ID,大概率是数据帧或远程帧。
- 看 RTR 位: 仲裁段最后一位。显性 -> 数据帧;隐性 -> 远程帧。
- 看 FDF 位: 控制段第一位。显性 -> 经典 CAN;隐性 -> CAN FD。
- 看错误标志: 如果波形里突然冒出 6 个显性位,紧接着 8 个隐性位,那就是错误帧或过载帧。
- 看帧间间隔: 过载帧只出现在帧间间隔的前两位;而错误帧可以出现在任何位置。
嗯,这里要注意:错误帧和过载帧的波形一模一样,只能通过上下文判断——错误帧前一定有一个存在错误的帧,而过载帧前是一个正常的帧(接收方来不及处理)。调试时最好连上逻辑分析仪的协议解析功能,让工具帮你判断。
最后分享一个小技巧:在 ECU 开发阶段,我一般会在 CAN FD 总线上连一个 ID 为 0x7FF 的周期性数据帧做“心跳”。一旦心跳帧消失,大概率是总线被错误帧或过载帧锁住了。这时用示波器抓一次完整波形,基本能定位问题。