CAN FD 数据链路层:帧结构、仲裁与位填充
我记得刚接触 CAN FD 那会儿,总觉得数据链路层就是个协议栈,调调参数就行。直到有一次,EMI 干扰把总线打得七零八落,我才发现——不懂链路层细节,你连错误帧长什么样都看不懂。
这一节,我们就把 CAN FD 的帧结构、仲裁机制和位填充掰开揉碎。说白了,这三样东西决定了数据怎么装车、怎么抢道、怎么防干扰。
3.1 CAN FD 帧结构:标准帧 vs 扩展帧
CAN FD 的帧结构和传统 CAN 2.0 很像,但多了几个关键字段。我习惯把帧想象成快递包裹——有头、有身子、有尾巴。
先看帧头:
- SOF(Start of Frame):一个显性位,告诉所有节点“我要发数据了”。
- 仲裁场(Arbitration Field):包括 ID 和 RTR 位。标准帧 11 位 ID,扩展帧 29 位 ID。
- 控制场(Control Field):CAN FD 这里加了 FDF、BRS、ESI 位,用来标识是 FD 帧还是传统帧。
再看数据场:最多 64 字节,比传统 CAN 的 8 字节翻了 8 倍。
帧尾:CRC 校验、ACK 位、EOF。这里有个坑——CAN FD 的 CRC 比传统 CAN 多,特别是数据场超过 16 字节时,CRC 要用 21 位甚至更多。
| 字段 | 标准 CAN (2.0) | CAN FD |
|---|---|---|
| 仲裁场 ID | 11 位 | 11 或 29 位 |
| 控制场 | IDE, r0, DLC | FDF, BRS, ESI, DLC |
| 数据场长度 | 0~8 字节 | 0~64 字节 |
| CRC | 15 位 | 17 或 21 位 |
| 位速率切换 | 不支持 | 支持,数据场可高速 |
3.2 仲裁机制:谁先抢到总线?
仲裁,说白了就是多个节点同时发数据时,谁能赢。
CAN 总线的物理层用了“线与”逻辑:显性位(逻辑 0)会覆盖隐性位(逻辑 1)。所以,ID 数值越小,优先级越高。
举个例子:节点 A 的 ID 是 0x100,节点 B 是 0x200。两者同时开始发送:
- A 发 ID 位 0x100 的二进制:0001 0000 0000
- B 发 ID 位 0x200 的二进制:0010 0000 0000
- 第一位:A 发 0(显性),B 也发 0(显性)。两者都不让步。
- 第二位:A 发 0(显性),B 发 1(隐性)。显性盖过隐性,A 赢。
为什么会这样?因为 B 在第二位看到总线不是自己发的东西,就知道有人优先级更高,它立刻停止发送,转为接收。
这个机制在 EMI 下会出问题。我曾经遇到过:总线被干扰,一个节点本来该发隐性位,结果收到了显性电平,误以为在仲裁中输了——于是它停止发送,后面一帧全乱。这就是典型的错误帧来源之一。
关键结论:仲裁失败不是错误帧,但仲裁阶段受 EMI 干扰,会虚假触发错误帧。调试时优先看 SOF 之后的几个位,有没有不该出现的显性电平。
3.3 位填充:同步与错误检测的基石
位填充,名字听着吓人,其实很简单:发送方每发送 5 个连续相同电平的位,就插入一个相反电平的位。
比如你发连续 5 个隐性位(11111),填充规则会自动加一个显性位(0)。接收方看到这 6 个位,知道第 6 个是填充位,不把它当数据。
为什么搞这么复杂?两个原因:
- 同步:CAN 节点没有独立的时钟线,靠总线电平跳变同步时钟。连续相同电平超过 5 位,时钟可能漂移,节点之间不同步了。
- 错误检测:如果接收方看到连续 6 个相同电平,就知道这是违规的——填充规则要求最多 5 个连续相同位。这就是“填充错误”。
嗯,这里要注意:位填充规则适用于从 SOF 到 CRC 场(包括 CRC 本身)。ACK 场、EOF、帧间隔等不填充。
// 举例:发送数据 0xFF(二进制 1111 1111)
// 按位填充规则:
// 原始:1 1 1 1 1 1 1 1
// 填充后:1 1 1 1 1 0 1 1 1 1 1 0 ...
// 你看,每5个1插入一个0,打破了连续相同电平
在我以前的项目中,遇到过别车厂反馈——EMI 干扰导致插入的填充位被误判成数据位,CRC 校验收到的帧就不对,最终触发错误帧。解决办法是检查总线终端电阻和共模扼流圈,填充位错误率大幅下降。
3.4 本章知识结构图
下面这张图把 CAN FD 数据链路层的核心逻辑串起来了——从帧结构到仲裁,到位填充,再到错误帧触发。你可以把它当成调试时的思维地图。
图里你能看到三个模块怎么串起来的。帧结构决定了数据封装方式;仲裁机制决定总线控制权;位填充保证同步和错误检测。任何一个环节受 EMI 干扰,最终都可能表现为错误帧。
好了,这就是 CAN FD 数据链路层的核心。下面我们看实战中怎么抓这些信号、怎么分析错误帧。