4. CAN FD数据链路层(下):远程帧、错误帧、过载帧、帧间隔、位填充机制、CRC校验(17位/21位)
好,咱们接着聊CAN FD的数据链路层。上一节我们把数据帧和遥控帧的底细摸了个透,这一节我打算把剩下的几种帧类型、帧间隔,还有两个非常重要的底层机制——位填充和CRC校验,一次性讲清楚。
说实话,这些内容在项目里平时不太会直接碰,但一旦出了问题,比如总线莫名其妙挂掉、报文收不到、或者偶发性的错误帧风暴,你回头一查,十有八九就是这些“底层细节”没处理好。我当年刚入行时,就被一个过载帧的问题折腾了整整两天,最后发现是接收端处理不过来,硬件自动发了过载帧,把整个总线节奏打乱了。嗯,从那以后,我对这些“非数据帧”就格外上心。
4.1 远程帧:你问,它答
远程帧,说白了就是一个“请求”。节点A发一个远程帧,意思就是:“谁有这个ID的数据,请发给我。” 被请求的节点收到后,会回复一个相同ID的数据帧。
远程帧的结构和数据帧几乎一模一样,唯一的区别就是:远程帧没有数据场。它的RTR位(在CAN 2.0里)或R1/R0位(在CAN FD里)被置为隐性,表示这是一个远程请求。
关键点: 远程帧的DLC(数据长度码)必须与被请求的数据帧的DLC一致。比如你请求一个8字节的数据帧,远程帧的DLC就得填8。这个细节很容易被忽略,我见过有人DLC填0,结果对方根本不响应。
在CAN FD里,远程帧的使用其实变少了。为什么?因为CAN FD的数据场可以很大,远程帧的请求效率反而不如直接用数据帧里的控制位来协商。我个人习惯是,在新项目里尽量少用远程帧,除非是为了兼容老的CAN 2.0设备。
4.2 错误帧:总线的“警报器”
错误帧是CAN总线自我保护的机制。任何一个节点检测到错误,就会立刻发送错误帧,通知所有节点:“刚才那帧有问题,大家别用了!”
错误帧由两部分组成:
- 错误标志: 6个连续的显性位(主动错误)或6个连续的隐性位(被动错误)。
- 错误界定符: 8个连续的隐性位。
这里有个有意思的点:主动错误和被动错误的区别。主动错误的节点,一旦发现错误,会强行把总线拉成显性,覆盖掉其他节点的发送。被动错误的节点则只能发隐性位,不能主动破坏总线。这个机制保证了“犯错的人”不会把整个总线搞瘫痪。
避坑指南: 我曾经遇到过一个案例,某个节点频繁发送错误帧,导致总线利用率骤降。排查后发现是它的CAN控制器时钟精度不够,位时序偏差太大,导致采样点总是不对。换了个晶振就好了。所以,时钟精度是CAN FD稳定性的基石,别在这上面省钱。
4.3 过载帧:我忙不过来了
过载帧和错误帧长得很像,但含义完全不同。过载帧的意思是:“我(接收节点)处理不过来了,请慢一点发。”
过载帧的触发条件有两个:
- 接收节点内部条件不满足,比如接收缓冲区满了。
- 在帧间隔期间,检测到一个显性位(这属于异常情况)。
过载帧的结构也是6个显性位(过载标志)+ 8个隐性位(界定符)。你想想看,如果总线上多个节点同时发过载帧,那6个显性位就会叠加,但没关系,CAN总线是“线与”机制,显性位会覆盖隐性位,最终大家看到的还是连续的显性位。
在实际项目中,过载帧出现的频率应该非常低。如果频繁出现,说明你的系统设计有问题——要么是接收节点的处理能力不足,要么是发送节点的发送间隔太短。我建议你在设计阶段就估算好最坏情况下的总线负载,留出余量。
4.4 帧间隔:给总线喘口气
帧间隔,就是两帧之间的“空闲时间”。它把总线上的连续帧分隔开,让节点有时间准备下一帧的接收或发送。
帧间隔由三部分组成:
- 间歇场: 3个隐性位。
- 总线空闲: 任意长度的隐性位,直到有节点开始发送。
- (可选)暂停发送场: 仅被动错误节点需要,8个隐性位。
这里要注意:帧间隔是强制性的。任何节点在发送完一帧后,都必须等待至少3个隐性位(间歇场),才能开始发送下一帧。这个机制保证了总线的公平性,防止某个节点霸占总线。
个人经验: 在调试CAN FD通信时,我习惯用示波器抓一下帧间隔的波形。如果间歇场出现显性位,那说明有节点在“抢跑”,很可能是它的协议控制器配置有问题。这种问题在低速时不容易发现,但到了高速(比如5Mbps以上),就会频繁触发错误帧。
4.5 位填充机制:保证时钟同步
位填充,是CAN总线一个非常巧妙的设计。它的规则很简单:在发送连续5个相同电平的位之后,自动插入一个相反电平的位。
为什么要这么做?因为CAN总线没有独立的时钟线,所有节点都靠总线上的电平跳变来同步时钟。如果长时间没有跳变(比如连续发送15个隐性位),节点的时钟就会漂移,导致采样点偏移,最终采样错误。
位填充的规则适用于:
- 帧起始(SOF)
- 仲裁场
- 控制场
- 数据场
- CRC场(包括CRC界定符之前的位)
但要注意:CRC界定符、ACK场、帧结束(EOF)等固定格式的位段,不进行位填充。 因为这些位段的长度和电平是固定的,不需要额外同步。
重要变化: 在CAN FD中,数据场的位填充机制是可选的!你可以通过FDF位和BRS位来控制。如果开启了“位填充取消”(Stuff Bit Count),数据场就不会插入填充位,从而提高了有效数据传输效率。但代价是,接收端需要更精确的时钟同步。我个人建议,在数据场长度超过64字节时,一定要开启这个功能,否则填充位会浪费大量带宽。
4.6 CRC校验:17位 vs 21位
CRC校验是保证数据完整性的最后一道防线。CAN FD引入了两种CRC多项式,分别对应不同的数据场长度:
| CRC类型 | 多项式 | 适用场景 |
|---|---|---|
| CRC_17 | x¹⁷ + x¹⁵ + x¹³ + x¹¹ + x⁹ + x⁸ + x⁷ + x⁵ + x⁴ + x³ + x² + 1 | 数据场长度 ≤ 16字节 |
| CRC_21 | x²¹ + x¹⁹ + x¹⁷ + x¹⁵ + x¹³ + x¹¹ + x⁹ + x⁸ + x⁷ + x⁵ + x⁴ + x³ + x² + 1 | 数据场长度 > 16字节 |
为什么要有两种?说白了,就是为了平衡安全性和效率。数据短的时候,17位CRC足够用了,还能省点带宽。数据长的时候,21位CRC能提供更强的检错能力,防止漏检。
CRC的计算范围包括:帧起始、仲裁场、控制场、数据场,以及填充位(如果启用了)。接收端收到后,会用同样的多项式重新计算,然后和发送端附带的CRC值比较。如果不一致,就说明传输过程中有错误,接收端会发送错误帧。
注意: CRC_17和CRC_21的生成多项式是固定的,但不同厂家的CAN控制器在实现时,可能会对“填充位是否参与CRC计算”有细微差别。我曾经在项目中遇到过两个不同品牌的MCU通信时,CRC校验总是不通过,最后发现是其中一个芯片的CAN FD控制器在计算CRC时,把填充位也算进去了,而另一个没有。所以,跨平台通信时,一定要确认双方的CRC计算规则完全一致。
4.7 小结与建议
这一节的内容,说实话,有点“硬”。但这些东西,就像汽车的刹车和转向系统——平时你可能感觉不到它们的存在,但一旦出了问题,它们就是保命的关键。
我给你的建议是:
- 远程帧: 能不用就不用,用数据帧替代更可靠。
- 错误帧和过载帧: 如果频繁出现,先查时钟精度,再查总线负载。
- 帧间隔: 调试时用示波器看一眼,能发现很多隐藏问题。
- 位填充: 长数据帧时开启取消填充,但确保时钟同步足够好。
- CRC校验: 跨平台通信时,务必确认计算规则一致。
下一节,我们会进入CAN FD的物理层,聊聊那些“看得见摸得着”的东西——电平、位时序、采样点。到时候我会分享一些我在实际布线时的经验,保证实用。