3. 错误帧机制深度解析:CAN FD总线的5种错误类型
大家好,我是老周。干CAN总线这一行十几年,处理过上百起由EMI引发的错误帧问题。今天咱们聊点硬核的——CAN FD总线上那5种错误类型到底怎么检测的。说实话,很多工程师会把错误类型背下来,但遇到真实干扰时还是一头雾水。我个人习惯把每种错误的检测逻辑和内核对上号,这样分析定位才能快准狠。
你想想看,CAN FD协议规定了严格的错误检测规则,任何一个节点发现违规,都会立即发送错误帧。这5种错误分别是:位错误、填充错误、CRC错误、形式错误、ACK错误。它们覆盖了从物理层到数据链路层的各个角落。下面我一个一个拆解。
3.1 位错误(Bit Error)
位错误的检测逻辑很简单:发送节点把自己发送出去的位电平,与总线上实际采到的电平进行逐位对比。如果不一致,就判定为位错误。
你可能会问:自己发的和自己收的有什么好比的?这里有两个关键点:第一,总线是“线与”逻辑,多个节点同时发送显性位时,总线就是显性,这没问题。但如果你只发送隐性位,却收到显性位,说明有其他节点在同时发送显性位——这就是仲裁。但仲裁阶段是允许这个行为的,所以位错误检测只在仲裁场之后才使能。
嗯,这里要注意:仲裁场之后,如果发送节点发的是隐性位,却读到显性位,且这不是仲裁,那就报位错误。同理,如果发显性位读到隐性位,也报位错误。
💡 避坑指南
我曾经遇到一个项目,CAN FD通信在高温下频繁报位错误。排查了很久,最后发现是电源纹波导致发送节点自身的发送引脚波形畸变,但总线上的实际电平没问题——位错误检测的是「发送节点monitor到的电平」vs「它自己的发送缓冲」,并不是直接和总线上其他节点对比。所以节点内部收发器故障也可能导致位错误。
3.2 填充错误(Stuff Error)
CAN FD沿用了经典CAN的位填充机制:在仲裁场、控制场、数据场(经典CAN是全部场,CAN FD有区别,后面说)中,每连续发送5个相同极性位,就自动插入一个反极性位。这个插入位的目的是保证足够多的电平跳变,便于时钟同步。
填充错误的检测逻辑:任何节点(发送方和接收方)在应用填充规则的字段中,检测到连续6个相同位,就立即报填充错误。因为正常情况下不可能出现连续6个相同位,填充机制保证了最多5个相同位后一定有一个翻转。
我习惯把这种错误叫做「同步破产错误」。CAN FD在数据场长度超过8字节时,数据场采用新的填充规则(使用特殊填充计数,但检测逻辑仍然是连续6个相同位)。实际上,EMI干扰最容易制造填充错误——一个毛刺把一个位给翻转了,就可能破坏填充模式,导致接收方看到连续6个相同位。
注意区别:经典CAN在数据场也使用普通填充规则。CAN FD在数据场(BRS之后的速率切换字段)使用了不同的填充机制(动态填充),但任何节点检测到连续6个相同位,都视为填充错误。
3.3 CRC错误(CRC Error)
CRC错误是数据完整性的最后一道防线。发送节点会计算整个帧(从SOF到数据场的全部位)的CRC校验和,放入CRC场。接收节点同样计算自己接收到的数据的CRC,并与收到的CRC比较。不一致就报CRC错误。
CAN FD使用了更强大的CRC算法:CRC多项式根据数据场长度动态选择(17位或21位),可以检测到多达6位随机错误。我遇到过好几次EMI导致CRC错误的情况,尤其是当干扰脉冲正好落在CRC场的校验和位上时,接收方计算出的CRC和收到的CRC不一致。
你想想看,CRC错误通常意味着数据已经被破坏了,但节点无法判断是哪个位被改了,只能通过错误帧通知发送方重发。所以CRC错误一旦频繁出现,通信吞吐量会骤降。
3.4 形式错误(Form Error)
形式错误检测的是固定格式位。CAN FD帧中有一些位或位段的逻辑电平是协议固定好的,比如CRC分隔符必须是隐性位,ACK分隔符必须是隐性位,EOF必须是7个隐性位。如果任何节点在这些固定位检测到显性电平,就报形式错误。
说白了,形式错误就是「协议规定这里必须是隐性,结果你测到了显性」。形式错误通常源于两种场景:一是干扰电平把隐性位冲成了显性;二是某些节点因为故障发送了不该发的内容。
我个人习惯把形式错误和位错误放在一起分析——形式错误的检测节点是所有接收节点(包括发送节点自己),而位错误的检测节点只是发送节点。两者可以通过错误帧的标志位在CAN日志中区分。
⚠️ 常见误区
初学者容易把形式错误和位错误搞混。记住:位错误是发送方「自检」发现不一致;形式错误是任何节点发现固定格式位被破坏。举个例子:如果发送方在ACK分隔符本该发隐性位,却因为内部故障发成了显性位,那么它自己会检测到位错误,而其他节点会检测到形式错误。同一个故障可能导致两种错误被同时报出。
3.5 ACK错误(Acknowledge Error)
ACK错误是CAN FD总线中非常特殊的一种错误,检测逻辑如下:发送节点在ACK槽(1位时间)发送一个隐性位,然后等待总线被其他接收节点拉成显性——表示确认。如果在ACK槽结束时,发送节点采样到的仍然是隐性位,就报ACK错误。
换句话说,ACK错误意味着没有一个其他节点成功接收了这个帧。这是一个集体否定的信号,发送节点知道:当前帧所有人都没确认,必须重发。
我在实际项目中经常用ACK错误来判断「某个节点是否脱离了总线」。如果某个节点持续发送但总是收到ACK错误,可能是该节点发送的内容其他节点都因为CRC错误或填充错误而丢弃了,或者总线上只有一个节点在工作(单节点自通信也会报ACK错误)。
嗯,这里有一个重要的细节:ACK错误不会触发其他节点发送错误帧(因为ACK错误是在发送节点检测到的,而其他节点在ACK槽之前可能已经帧结束了)。只有当发送节点检测到ACK错误后,它会发送一个错误帧(主动错误标志),通知所有节点进入错误状态。
快速对比:五种错误类型
| 错误类型 | 检测节点 | 检测时机 | 检测条件 |
|---|---|---|---|
| 位错误 | 发送节点 | 仲裁场后逐位对比 | 发送位 ≠ 采样位 |
| 填充错误 | 所有节点 | 填充规则生效的字段 | 连续6个相同位 |
| CRC错误 | 接收节点 | CRC场结束后 | 计算CRC ≠ 接收CRC |
| 形式错误 | 所有节点 | 固定格式位 | 规定隐性位读到显性 |
| ACK错误 | 发送节点 | ACK槽结束时 | 采样到隐性位(无确认) |
这张表我建议你截个图放到调试手册里。每次抓CAN FD波形时,先看错误帧的类型,定位到对应的检测节点,再结合EMI干扰的频段特征,就能快速缩小问题范围。
我个人习惯在实验室里做专项测试:比如在CAN FD总线附近用近场探头打一个固定频率的电磁场,然后看哪种错误先出现。如果位错误先出现,说明干扰直接作用在发送节点物理层;如果CRC错误先出现,大概率是数据场被翻转了。这些实战经验,后面几节咱们会结合具体波形一个一个过。