3. CAN/LIN 总线故障注入:总线 off、位错误、CRC 错误、信号超时
总线,是线控转向系统的神经网络。信号丢了、乱了、迟了,转向指令就传不过去。这一章我们专门聊 CAN/LIN 总线的故障注入。说白了,就是模拟总线“生病”的各种状态,看看系统扛不扛得住。
核心观点:总线故障注入不是乱搞破坏,而是验证通信协议栈的鲁棒性。你注入的每一个错误,都应该对应到 ISO 26262 中定义的通信故障模型。
3.1 总线 off 故障注入
总线 off,是 CAN 控制器最严重的自我保护状态。当发送错误计数器(TEC)超过 255,节点会自动离线。我见过不少工程师只测了“拔线”这种粗暴方式,其实真正的总线 off 注入要精细得多。
注入方法
- 方法一:连续发送错误帧——通过工具(如 CANoe、PCAN-Explorer)持续发送违反 CAN 协议格式的报文,迫使目标节点 TEC 飙升。
- 方法二:物理层干扰——在 CAN_H/CAN_L 之间接入可编程电阻,模拟短路或断路,触发总线 off。
- 方法三:寄存器级注入——直接修改节点 CAN 控制器的 TEC 寄存器,强制进入 bus off 状态(需要调试接口)。
我的习惯:优先用方法一。因为它最接近真实场景,而且能精确控制错误注入的频次和时机。我曾经在项目里用 CANoe 的 IG(Interaction Layer)模块,每秒注入 200 个错误帧,3 秒内就让目标节点离线了。
测试观察点
| 观察项 | 预期行为 | 常见问题 |
|---|---|---|
| 节点恢复时间 | 总线 off 后,节点应在 128 个空闲位后自动恢复 | 恢复时间过长或无法恢复 |
| 应用层响应 | 转向系统应进入降级模式(如切换到冗余总线) | 系统直接死机或输出错误扭矩 |
| 故障诊断记录 | DTC 应正确记录总线 off 事件 | 诊断未触发或记录错误 |
注意:总线 off 恢复后,节点会重新参与总线仲裁。如果此时发送缓冲区还有积压报文,可能引发“恢复风暴”——多个节点同时发送,导致总线再次拥堵。我曾经在测试中遇到过,恢复后 500ms 内又触发了第二次总线 off。
3.2 位错误注入
位错误,是 CAN 总线最底层的错误。发送节点在发送位时,会回读总线电平。如果回读值与发送值不一致,就产生位错误。你想想看,如果总线被强拉成显性,而你要发送隐性位,那肯定报错。
注入技巧
- 单比特翻转:在报文发送过程中,用工具强制翻转某个位(如将 ACK 槽的显性位改为隐性位)。
- 多比特干扰:在 CRC 场或数据场连续注入多个错误位,模拟强电磁干扰。
- 位时序偏移:通过调整采样点位置,让节点在错误的时间点采样,产生位错误。
// 示例:使用 CANoe CAPL 脚本注入单比特错误
on start {
// 配置 CAN 通道,在报文 ID 0x123 的第 15 位注入错误
canSetErrorFrameInjection(1, 0x123, 15, 1);
write("位错误注入已启动 - 目标报文 0x123,位位置 15");
}
避坑指南:我曾经在测试中只关注数据场的位错误,忽略了 CRC 场的位错误。结果发现,CRC 场的位错误会导致节点重发,但应用层完全不知道。后来我加了一条规则:CRC 场的位错误注入,必须同时监控错误帧计数器和重发次数。
3.3 CRC 错误注入
CRC 错误,是 CAN 协议中用于检测数据完整性的机制。接收节点计算 CRC 并与发送值比较,不一致就丢弃报文。嗯,这里要注意:CRC 错误不会触发错误帧,只是报文被静默丢弃。
注入方式
- 修改 CRC 场:在报文发送前,用工具将 CRC 场的值改为任意错误值。
- 破坏数据场:修改数据场的某个字节,但不重新计算 CRC,导致接收端 CRC 校验失败。
- 注入 CRC 边界值:测试 CRC 全 0、全 1 或随机值,验证接收节点的容错能力。
| CRC 注入类型 | 预期结果 | 测试优先级 |
|---|---|---|
| 单比特 CRC 错误 | 报文被丢弃,节点请求重发 | 高 |
| 多比特 CRC 错误 | 报文被丢弃,可能触发错误帧 | 中 |
| CRC 全 0 | 接收节点应能识别并丢弃 | 低 |
| CRC 全 1 | 接收节点应能识别并丢弃 | 低 |
关键点:CRC 错误注入后,要观察应用层是否收到了错误报文。如果应用层收到了 CRC 错误的报文,说明接收节点的 CRC 校验逻辑有 bug。我在一个项目中就遇到过,接收节点在特定条件下跳过了 CRC 校验,直接使用了错误数据。
3.4 信号超时注入
信号超时,是应用层最关心的故障。ECU 在规定时间内没收到预期报文,就判定信号超时。线控转向中,转向角信号超时超过 10ms,系统就必须进入安全状态。
注入策略
- 完全丢帧:停止发送某条报文,模拟发送节点死机。
- 延迟发送:将报文发送时间推迟到超时阈值之后(如正常周期 10ms,延迟到 15ms 发送)。
- 周期抖动:随机改变报文发送周期,模拟总线负载波动导致的延迟。
我的建议:信号超时测试一定要做“临界值测试”。比如超时阈值是 100ms,你就分别注入 99ms、100ms、101ms 的延迟。我见过一个系统,99ms 延迟正常,101ms 延迟就报超时,但 100ms 延迟时系统状态不确定——这就是典型的边界问题。
测试矩阵示例
| 信号名称 | 正常周期 | 超时阈值 | 注入延迟 | 预期行为 |
|---|---|---|---|---|
| 转向角信号 | 10ms | 20ms | 25ms | 进入降级模式,使用预测值 |
| 扭矩请求 | 5ms | 10ms | 12ms | 切换到冗余传感器 |
| 状态报文 | 100ms | 200ms | 210ms | 记录 DTC,保持当前状态 |
警告:信号超时注入时,要同时监控多个接收节点。我曾经在测试中只关注了主控制器,结果发现冗余控制器也收到了超时信号,两个控制器同时切换,导致系统震荡。后来我加了一条规则:超时注入必须覆盖所有接收节点。
3.5 知识体系总览
下面这张图,把四种总线故障注入的核心逻辑串起来了。你可以把它当作测试时的“作战地图”。
四种故障类型,覆盖了从物理层到应用层的所有通信故障模型。总线 off 和位错误属于物理层,CRC 错误属于数据链路层,信号超时属于应用层。测试时,我建议按这个顺序来:先做信号超时(最简单),再做 CRC 错误,然后做位错误,最后做总线 off(破坏性最大)。
总结:总线故障注入的核心,是验证系统在通信异常时的行为是否符合安全目标。不要只测“能不能恢复”,还要测“恢复过程中会不会产生危险”。记住,线控转向没有机械备份,总线就是生命线。