4、填充错误(Stuff Error):CAN FD中填充规则的变化

填充错误,说白了就是位填充规则被打破了。在CAN总线里,这是个老生常谈的问题。但到了CAN FD时代,事情变得有点不一样了——BRS位之后,填充规则悄悄发生了变化。很多工程师第一次接触时都会踩坑,我自己也不例外。

4.1 经典CAN的填充规则回顾

先简单回顾一下。经典CAN(Classic CAN)里有个硬性规定:

  • 连续发送5个相同电平的位后,必须插入一个相反电平的填充位
  • 这个规则覆盖从SOF到CRC Delimiter之前的所有位
  • 接收端在解码时会自动移除这些填充位

为什么要这么做?说白了就是为了保证总线有足够的电平跳变,方便接收节点做时钟同步。你想想看,如果连续发几十个"1",没有跳变,接收端的PLL可能就失锁了。

4.2 CAN FD的填充规则变化

到了CAN FD,事情变得复杂了。BRS位(Baud Rate Switch)之后,填充规则分成了两种情况:

区域 填充规则 说明
BRS位之前 与经典CAN相同 5个相同位后插入相反位
BRS位之后(数据段) 无填充或固定填充 取决于是否启用FD格式

嗯,这里要注意。CAN FD其实有两种数据段格式:

  • FD格式(FD Frame):数据段不进行位填充。没错,完全不填充。这样做的目的是提高数据传输效率,毕竟填充位占用了宝贵的带宽。
  • 经典格式(Classic Frame):数据段仍然保持5位填充规则,和经典CAN一样。

我刚开始做CAN FD项目时,就因为这个差异吃过亏。当时我习惯性地认为所有段都有填充,结果在分析错误帧时怎么都找不到原因。

4.3 填充错误的常见触发场景

填充错误到底怎么触发的?我总结了几个典型场景:

场景一:BRS位后的连续相同电平

在FD格式下,数据段没有填充。这意味着什么?意味着你可以连续发送超过5个相同电平的位。比如:

// 假设数据段内容为 0x00 0x00 0x00
// 二进制:0000 0000 0000 0000 0000 0000
// 连续24个"0",没有填充位

这在经典CAN里是绝对不允许的。但在CAN FD的FD格式下,这是合法的。不过,如果接收节点配置错误,比如它还在用经典CAN的规则去解码,就会报填充错误。

⚠️ 注意: 如果总线上混有经典CAN节点和CAN FD节点,经典CAN节点看到连续6个相同位就会报填充错误。这就是为什么CAN FD规范要求:FD格式的帧必须被经典CAN节点识别为错误帧。

场景二:BRS位本身的误判

BRS位是决定填充规则切换的关键。如果BRS位被错误采样:

  • 发送端认为BRS=1(切换到FD格式),数据段不填充
  • 接收端认为BRS=0(保持经典格式),期待数据段有填充

结果就是接收端在数据段看到连续6个相同位,直接报填充错误。我在项目中遇到过这种情况,当时排查了很久才发现是BRS位的采样窗口设置有问题。

场景三:ESI位与填充规则的耦合

ESI位(Error State Indicator)位于BRS位之后。在FD格式下,ESI位之后的数据段也不填充。但如果节点处于被动错误状态(Error Passive),ESI位会被置为1。这时候如果接收端对ESI位的解析有偏差,也可能间接导致填充错误。

4.4 如何避免填充错误?

我个人习惯从这几个方面入手:

  1. 确认所有节点都支持CAN FD。如果总线上有经典CAN节点,老老实实用经典格式,别开FD格式。
  2. 检查BRS位的采样点。BRS位位于仲裁段末尾,采样点设置不当很容易误判。我建议把采样点设在75%左右,留足余量。
  3. 使用位填充监控工具。调试时用CANscope或类似工具,实时监控填充位的位置和数量。一旦发现异常,立刻定位。
  4. 做边界测试。比如发送全0或全1的数据段,看接收端会不会误报填充错误。
💡 小技巧: 我曾经在测试时发现,某些CAN FD控制器在接收FD格式帧时,如果数据段长度超过8字节,内部FIFO处理不过来,也会偶发填充错误。后来我换了一款支持更大FIFO的控制器,问题就解决了。所以硬件选型也很重要。

4.5 填充错误与网络健壮性

填充错误看似是个小问题,但它对网络健壮性的影响不容忽视。你想想看:

  • 一次填充错误会导致整个帧被破坏
  • 错误帧会触发重传,增加总线负载
  • 如果错误频繁发生,节点可能进入Bus Off状态

所以我的建议是:在设计阶段就把填充规则的变化考虑进去。特别是从经典CAN迁移到CAN FD时,一定要做充分的兼容性测试。别等到量产了才发现问题,那时候改起来就麻烦了。

嗯,关于填充错误就先聊这么多。下一节我会讲CRC错误,那是另一个容易踩坑的地方。