第3章 CAN FD数据链路层(一):CAN FD帧结构

各位同学,今天我们来啃CAN FD协议里最核心的一块——帧结构。

说实话,我刚接触CAN FD时,看着那一堆缩写(SOF、IDE、FDF、BRS、ESI...)头都大了。但后来我发现,只要把帧结构拆开来看,每个字段都有它存在的道理。你想想看,一个通信协议能活这么多年,它的设计一定是有讲究的。

3.1 帧结构概览:标准帧与扩展帧

CAN FD的帧,说白了就是一串有格式的二进制数据。它分为两种:标准帧扩展帧。区别在哪?就在ID的长度上。

  • 标准帧:11位ID,帧头比较短,适合简单系统
  • 扩展帧:29位ID,帧头更长,适合复杂网络

我个人习惯,在项目初期先用标准帧,等节点多了再切扩展帧。为什么?因为标准帧的仲裁场短,总线利用率更高。但如果你一开始就设计一个大型网络,那直接上扩展帧吧,省得后面改协议。

来看一个完整的CAN FD帧结构(标准帧为例):

SOF | 仲裁场(11位ID + RTR) | 控制场(IDE + FDF + BRS + ESI + DLC) | 数据场(0-64字节) | CRC场(17位或21位) | ACK场 | EOF

嗯,这个结构你得背下来。我在调试时,经常对着逻辑分析仪一帧一帧地数位,少了哪个字段都跑不通。

3.2 帧起始(SOF)

SOF(Start of Frame)就1个显性位(0)。它干两件事:

  • 同步所有节点的时钟
  • 宣告总线开始传输

我曾经遇到一个坑:某个节点在SOF之后莫名其妙丢帧。查了半天,发现是晶振偏差太大,导致SOF后的同步跳变没被正确识别。所以啊,晶振精度一定要选好,至少±0.1%以内。

3.3 仲裁场:ID与RTR

仲裁场是CAN协议的灵魂。它决定了:谁能在总线上说话

ID(标识符)

  • 标准帧:11位,范围0x000~0x7FF
  • 扩展帧:29位,范围0x00000000~0x1FFFFFFF
  • ID越小,优先级越高

RTR(远程传输请求位)

  • 显性(0):数据帧
  • 隐性(1):远程帧

注意!CAN FD中RTR位必须为0(数据帧)。为什么?因为CAN FD不支持远程帧。我刚开始做CAN FD项目时,想用远程帧来请求数据,结果发现控制器直接报错。后来查手册才知道,CAN FD压根没这功能。

避坑指南:我曾经在仲裁场设计上吃过亏。把两个节点的ID设得太接近(比如0x100和0x101),结果在总线负载高时,优先级低的节点经常发不出去。后来我学乖了,关键节点用低ID,非关键节点用高ID,中间留足间隔。

3.4 控制场:IDE、FDF、BRS、ESI、DLC

控制场是CAN FD和传统CAN最大的区别所在。我们一个一个看。

名称 说明
IDE 标识符扩展位 0=标准帧,1=扩展帧
FDF FD格式位 0=传统CAN,1=CAN FD
BRS 比特率切换位 0=不切换,1=切换到高速数据段
ESI 错误状态指示位 0=主动错误,1=被动错误
DLC 数据长度码 4位,表示数据场字节数

IDE位:这个很简单,就是告诉接收方,后面跟的是11位ID还是29位ID。

FDF位:这是CAN FD的身份证。如果FDF=0,那就是传统CAN帧;FDF=1,才是CAN FD帧。我建议你在发送时,FDF位一定要显性(0)?不对,是隐性(1)!嗯,这里容易搞混,记住:FDF=1表示CAN FD

BRS位:这个位决定了数据段是否用高速率传输。BRS=1时,从BRS位之后切换到高速率(比如5Mbps),直到CRC分隔符之前切回。我在项目中用过这个功能,确实能大幅提升吞吐量。但要注意,所有节点都必须支持BRS,否则会报错。

ESI位:这个位反映发送节点的错误状态。如果节点处于被动错误状态,ESI=1。我一般用这个位来做诊断,看哪个节点快挂了。

DLC位:4位,但CAN FD的DLC编码和传统CAN不一样。传统CAN的DLC只能表示0-8字节,而CAN FD可以表示0-64字节。编码规则如下:

DLC值 传统CAN数据长度 CAN FD数据长度
0-8 0-8字节 0-8字节
9 8字节 12字节
10 8字节 16字节
11 8字节 20字节
12 8字节 24字节
13 8字节 32字节
14 8字节 48字节
15 8字节 64字节

你看,DLC=9时,传统CAN还是8字节,但CAN FD已经变成12字节了。这个设计是为了兼容传统CAN的DLC编码,但扩展了数据长度。我刚开始用CAN FD时,就因为这个编码规则,写了个bug——DLC=9只发了8字节数据,结果接收方等12字节,直接超时。嗯,这种低级错误,希望大家别犯。

3.5 数据场

数据场就是你要传输的实际数据。CAN FD支持0-64字节,而传统CAN只有0-8字节。这是CAN FD最大的优势。

我个人建议,数据场长度尽量用满。比如你要传一个64字节的固件升级包,用CAN FD一帧搞定,传统CAN得拆成8帧。效率差距一目了然。

但要注意,数据场越长,CRC校验就越重要。因为数据多了,出错概率也大了。

3.6 CRC场:17位与21位CRC

CRC场是保证数据完整性的关键。CAN FD有两种CRC:

  • 17位CRC:用于数据场长度≤16字节
  • 21位CRC:用于数据场长度>16字节

为什么分两种?因为数据越长,需要的校验位越多。17位CRC的生成多项式是:

x^17 + x^15 + x^13 + x^11 + x^9 + x^8 + x^5 + x^3 + x^2 + 1

21位CRC的生成多项式是:

x^21 + x^19 + x^17 + x^15 + x^13 + x^11 + x^9 + x^8 + x^5 + x^3 + x^2 + 1

我在项目中遇到过一个问题:CRC计算错误导致节点频繁离线。后来发现是MCU的CRC硬件模块配置错了,没有用对多项式。所以,如果你用硬件CRC,一定要确认配置和CAN FD协议一致。

小技巧:如果你自己实现CRC计算,建议用查表法。17位CRC的表有128个条目,21位CRC的表有256个条目。查表法比逐位计算快得多,尤其是在数据场64字节时。

3.7 ACK场

ACK场只有2位:

  • ACK槽(1位):发送节点发隐性位,接收节点如果正确接收,就拉成显性位
  • ACK分隔符(1位):必须为隐性位

这个机制很有意思。发送节点只负责发,不负责确认。确认工作由接收节点完成。如果总线上没有任何节点应答(ACK槽保持隐性),发送节点就知道出问题了。

我曾经调试一个多节点系统,发现某个节点总是发帧失败。用示波器一看,ACK槽一直是隐性。原来那个节点的接收中断没处理好,导致它没来得及应答。嗯,这种问题,排查起来确实费劲。

3.8 帧结束(EOF)

EOF(End of Frame)是7个隐性位。它告诉所有节点:这帧结束了,准备接收下一帧。

EOF之后,还有3位ITM(Intermission,间歇场)。ITM也是隐性位,用于总线空闲检测。

注意,EOF期间如果有节点发送显性位,那就是错误帧。我见过一个案例,某个节点的EOF被干扰成显性,结果整个网络都报错。后来加了终端电阻和屏蔽线,问题才解决。

重要提醒:EOF的7个隐性位必须完整。如果因为总线干扰导致EOF被破坏,接收节点会认为帧不完整,从而丢弃数据。所以,CAN FD的物理层(比如终端电阻、线缆质量)一定要做好。

3.9 实战经验总结

好了,这一章的内容就这些。最后我总结几个要点:

  1. 帧结构是基础:SOF、仲裁场、控制场、数据场、CRC场、ACK场、EOF,一个都不能少
  2. 控制场是CAN FD的灵魂:FDF、BRS、ESI这三个位,决定了你的帧是CAN FD还是传统CAN
  3. CRC别搞错:17位还是21位,取决于数据长度。错了就收不到
  4. ACK场是反馈:没有ACK,发送节点就是瞎子

下一章,我们会深入CAN FD的位填充机制和错误处理。到时候,你会看到更多有意思的细节。

记住,CAN FD协议不难,但细节多。多动手,多分析波形,你很快就能成为专家。