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的规则去解码,就会报填充错误。
场景二: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 如何避免填充错误?
我个人习惯从这几个方面入手:
- 确认所有节点都支持CAN FD。如果总线上有经典CAN节点,老老实实用经典格式,别开FD格式。
- 检查BRS位的采样点。BRS位位于仲裁段末尾,采样点设置不当很容易误判。我建议把采样点设在75%左右,留足余量。
- 使用位填充监控工具。调试时用CANscope或类似工具,实时监控填充位的位置和数量。一旦发现异常,立刻定位。
- 做边界测试。比如发送全0或全1的数据段,看接收端会不会误报填充错误。
4.5 填充错误与网络健壮性
填充错误看似是个小问题,但它对网络健壮性的影响不容忽视。你想想看:
- 一次填充错误会导致整个帧被破坏
- 错误帧会触发重传,增加总线负载
- 如果错误频繁发生,节点可能进入Bus Off状态
所以我的建议是:在设计阶段就把填充规则的变化考虑进去。特别是从经典CAN迁移到CAN FD时,一定要做充分的兼容性测试。别等到量产了才发现问题,那时候改起来就麻烦了。
嗯,关于填充错误就先聊这么多。下一节我会讲CRC错误,那是另一个容易踩坑的地方。