3、CAN FD数据链路层:帧结构解析(标准帧与扩展帧)、DLC编码规则、位填充机制与CRC校验差异

好,咱们今天来啃一块硬骨头——CAN FD的数据链路层。说实话,很多工程师做CAN开发好几年,对CAN 2.0的帧结构烂熟于心,但一碰到CAN FD就有点懵。我当年第一次看CAN FD的帧结构时,心里也犯嘀咕:这跟经典CAN到底差在哪?

别急,咱们一层层剥开它。你想想看,数据链路层说白了就是负责把物理层传来的比特流,组装成有意义的“帧”。CAN FD的帧,就是在经典CAN的骨架上做了几处关键升级。

3.1 标准帧与扩展帧:ID长度决定一切

先说说帧类型。CAN FD继承了CAN 2.0的两种帧格式:标准帧和扩展帧。区别在哪?就在仲裁段的那11位还是29位标识符上。

  • 标准帧:11位ID,帧头短,适合节点不多、优先级明确的系统。我做过一个车身控制项目,用的就是标准帧,简单粗暴,够用。
  • 扩展帧:29位ID,帧头长,适合复杂网络。比如你搞一个整车控制器,下面挂了几十个ECU,标准帧那11位ID根本不够分,这时候就得用扩展帧。

嗯,这里要注意:CAN FD的帧格式里,IDE位(Identifier Extension)决定了你是标准帧还是扩展帧。IDE=0是标准帧,IDE=1是扩展帧。这个位在经典CAN里也有,但CAN FD里它的位置和作用完全一样。

我个人习惯是:能用标准帧就别用扩展帧。为什么?因为帧头短,总线利用率高。但如果你需要更多节点或更复杂的优先级管理,那就老老实实用扩展帧。

3.2 DLC编码规则:从4位到9种长度

接下来是DLC,也就是数据长度码。经典CAN的DLC是4位,能表示0到8,对应0到8字节数据。但CAN FD支持最多64字节数据,4位显然不够用。

那怎么办?CAN FD的DLC还是4位,但编码规则变了。我刚开始学的时候也被这个绕晕过,后来画了个表才搞明白。

DLC值(二进制) 经典CAN数据长度(字节) CAN FD数据长度(字节)
0000 0 0
0001 1 1
0010 2 2
0011 3 3
0100 4 4
0101 5 5
0110 6 6
0111 7 7
1000 8 8
1001 8 12
1010 8 16
1011 8 20
1100 8 24
1101 8 32
1110 8 48
1111 8 64

看到了吗?DLC从1001到1111,经典CAN都只能发8字节,但CAN FD可以发12、16、20……一直到64字节。说白了,CAN FD用4位DLC编码了9种数据长度,而不是经典CAN的9种(0-8)。

核心要点:DLC=1001时,CAN FD实际发送12字节数据,而不是8字节。很多新手在这里踩坑,写代码时直接拿DLC当数据长度用,结果数据对不上。

3.3 位填充机制:同步的代价

位填充,这是个老话题了。经典CAN和CAN FD都用了NRZ(非归零)编码,这种编码方式有个毛病:如果连续出现太多相同的位,接收器会失去同步。

解决办法?每5个相同位后,强制插入一个相反位。这就是位填充。

举个例子:你要发送 11111 00000,经过位填充后变成 111110 000001。注意,插入的位是反的,这样接收器就能重新同步。

但CAN FD在这里做了个重要改动:数据段不进行位填充。你没听错,从FDF位(CAN FD格式标志)之后,一直到CRC段之前,CAN FD的数据段不再做位填充。

为什么会这样?我当年也纳闷。后来想明白了:CAN FD的数据段速率可以很高(比如5Mbps),如果还做位填充,那发送器得实时计算插入位,对硬件要求太高。而且位填充会增加数据长度,影响效率。

避坑指南:我曾经在一个项目中,把经典CAN的位填充逻辑直接搬到了CAN FD控制器里,结果数据段老是出错。后来查了协议才发现,CAN FD的数据段根本不填充。嗯,从那以后我再也不敢想当然了。

3.4 CRC校验差异:从15位到21位

最后说说CRC。经典CAN用的是15位CRC,多项式是 x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1。这个多项式能检测出所有单比特错误、双比特错误,以及大部分突发错误。

但CAN FD的数据段最长64字节,15位CRC的检错能力不够用了。所以CAN FD引入了两种CRC:

  • CRC_17:用于数据长度不超过16字节的帧,17位CRC,多项式是 x^17 + x^16 + x^14 + x^13 + x^11 + x^10 + x^9 + x^8 + x^7 + x^4 + x^3 + 1
  • CRC_21:用于数据长度超过16字节的帧,21位CRC,多项式是 x^21 + x^20 + x^19 + x^18 + x^16 + x^15 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^4 + x^3 + 1

你想想看,CRC越长,检错能力越强,但开销也越大。CAN FD的设计者很聪明,根据数据长度动态选择CRC长度,既保证了安全性,又没浪费带宽。

另外,CAN FD的CRC计算范围也变了。经典CAN只计算数据段和CRC段本身,但CAN FD的CRC还包含了填充位计数器(Stuff Bit Count)和固定填充位(Fixed Stuff Bits)。这个细节很容易被忽略,但如果你自己写CRC校验代码,一定要算进去。

重要提醒:CAN FD的CRC多项式与经典CAN完全不同。如果你用经典CAN的CRC算法去校验CAN FD帧,结果肯定不对。我见过有人把经典CAN的CRC模块直接复用,结果通信死活不通,折腾了两天才发现是CRC的问题。

好了,帧结构这块咱们就聊到这。总结一下:CAN FD的帧结构在经典CAN的基础上,改了DLC编码规则、去掉了数据段的位填充、升级了CRC算法。这些改动看似不大,但每一个都直接影响你的硬件设计和软件实现。下一节咱们聊聊CAN FD的物理层,那又是另一番天地了。