CAN FD 帧结构详解
讲负载率之前,得先把帧结构掰开揉碎了说清楚。你想想看,CAN FD 的帧结构和经典 CAN 2.0 差别不小,要是搞混了,后面计算带宽、仿真延迟的时候,数据全是错的。我刚开始做 CAN FD 项目时,就因为没注意控制场里那个 EDL 位,算出来的负载率整整差了一倍——嗯,那会儿可没少挨骂。
数据帧——最常用的那个
数据帧负责发送实际数据。CAN FD 的数据帧比 CAN 2.0 多了几个关键字段。咱们从左到右一个个看:
- 帧起始(SOF) —— 1 个显性位,标志总线开始干活。没啥花样,就是告诉大家「我要发消息了」。
- 仲裁场 —— 这里分标准帧和扩展帧。标准帧 11 位 ID,扩展帧 29 位 ID(前 11 + 后 18)。CAN FD 仲裁场里还多了一个
RRS位(代替 CAN 2.0 的 RTR),表示这是数据帧还是远程帧。我以前遇到过有人把 RRS 当成保留位置 1,结果对方节点死活不认——其实应该置 0。 - 控制场 —— 这是 CAN FD 变化最大的地方。6 位里包含:
EDL(1 位,1 表示 FD 格式,0 就是经典 CAN)、BRS(1 位,1 表示后面的数据段可以切到高速)、ESI(1 位,错误状态指示),然后 + 4 位DLC(数据长度码)。注意 FD 的 DLC 能编码到 64 字节,而经典 CAN 最多 8 字节。 - 数据场 —— 0~64 字节。最多可以放 512 位数据。我一般建议项目中先算好最大数据量,再定 DLC,不然多填充的垃圾位浪费带宽。
- CRC 场 —— 经典 CAN 用 15 位 CRC + 1 位分隔符。CAN FD 根据数据长度不同,CRC 有 17 位和 21 位两种(加上填充位)。这是我的个人经验:FD 的 CRC 计算比经典复杂,仿真时要特别注意 CRC 位数的切换,否则负载率算不准。
- ACK 场 —— 2 位:应答隙(1 位)+ 应答分隔符(1 位)。接收节点拉低 ACK 表示收到;没收到就保持隐性。嗯,这里有个坑:FD 模式下 ACK 的位时序和仲裁段是不同波特率,所以仿真模型里必须分开配置。
- 帧结束(EOF) —— 7 个隐性位。收尾,没别的。
数据帧结构一图搞定
下面这张图把 CAN FD 数据帧的每个场串起来了。你保存好,以后算负载率时直接对着看字段长度。
远程帧——只问不答
远程帧的结构和数据帧几乎一样,唯一的区别是仲裁场里的 RTR(CAN 2.0)或 RRS(CAN FD)位被设置为隐性(1)。它本身不带数据场(DLC 指示期望的数据长度,但实际发送不占用总线数据位)。说白了,远程帧就是「我没数据要发,但你得发给我」。这在多节点请求数据时很实用。我见过有人用远程帧做轮询,结果因为负载没算进去,总线利用率飙升——远程帧虽然数据场长度为 0,但帧头、CRC、ACK 一个都不少,所以仿真时要把它当完整帧来计算。
错误帧——总线的自我修复
错误帧由 6 个显性位(错误标志)和 8 个隐性位(错误分隔符)组成。当任何节点检测到总线错误时,就会主动拉低 6 个显性位来「破坏」当前帧。注意 CAN FD 下错误帧的格式和 CAN 2.0 完全一致,但因为 FD 数据段波特率更高,错误标志的位时间更短。我曾经遇到一个奇怪现象:某个节点在高波特率下报错,错误帧长度按低波特率算,结果仿真负载低于实际,导致预留带宽不足。
过载帧——总线也怕撑的慌
过载帧结构和错误帧类似:6 个显性位 + 8 个隐性位。当接收节点来不及处理数据,或者检测到帧间间隔异常时,它就发过载帧来「刹一下车」。过载帧可以在两个正常帧之间插入任意多个——只要你发,总线就一直被占用。所以,如果你在仿真里假设永远不发生过载,那计算结果只能是理想值。我自己的做法是在 CAN FD 控制器配置 里加上一个过载概率参数,统计典型工况下平均每 1000 帧出现过载的频率。
三种帧结构的速查表
| 帧类型 | 主要字段差异 | 数据场长度 | 典型用途 |
|---|---|---|---|
| 数据帧 | RRS=0(显性) | 0~64 字节 | 正常通信,发送载荷 |
| 远程帧 | RRS=1(隐性) | 0 字节(仅 DLC 指示) | 请求远程节点数据 |
| 错误帧 | 6 显性 + 8 隐性固定结构 | 无 | 总线错误通知与恢复 |
| 过载帧 | 6 显性 + 8 隐性固定结构 | 无 | 接收端节流控制 |
核心要点: 计算 CAN FD 总线负载率时,你不能只考虑数据帧。远程帧虽然没数据,但占用一样的总线时间;错误帧和过载帧虽然不常出现,但一旦出现就能把负载率推高 20% 以上。我的习惯是先统计实际系统中各类帧的比例(通过监听日志),再代入仿真模型。否则算出来的数字再漂亮,也经不起实车测试的检验。