前言:
很多同学对错误帧,只有很浅显的认知。认知并不是很全面。本文将从三个部分详细解释清楚,can总线错误帧。
*1)CAN总线错误检查基础知识
*2) CAN错误叠加部分的复杂性
*3)根据CAPL代码来解析错误帧
*4)VN6501实践操作
*1)CAN总线错误检查基础知识
1.1 主动错误帧和被动错误帧。
1:主动错误帧:6bit显性位+8bit隐形位
2:被动错误帧:6bit隐性位+8bit隐形位
1.2 CAN总线节点的三种种状态
CAN总线节点的两种状态 ,主动错误状态和被动错误状态,总线关闭状态(Bus off)
CAN通讯的底层代码中,同时存在两个个错误帧计数器
1:TEC counts :发送端错误计数器
2:REC counts:接收端错误计数器
主动错误状态和被动错误状态,总线关闭状态(Bus off)三种状态的切换和管理,是根据两种计数器的数值决定的。
如果有同学不懂,此三种状态下,节点如何工作,也没关系。后文会讲。暂时记住(主动错误状态和被动错误状态,总线关闭状态(Bus off)三种状态的切换和管理,是根据两种计数器的数值决定的。)
注意:以下截图中需要注意
1:主动错误状态,是TEC和REC都要同时满足<=127, (TEC<=127)&&(REC<=127)。
2:被动错误状态,是TEC和REC只要有一个满足>=128, (TEC>=128)&&(REC>=128)。
3:总线关闭状态,是TEC>256,即可。REC不关注,即REC错误超过256,也不会报BusOff错误。
4:错误计数不是只能增加,在正确接收数据后计数也会相应的增加的。
假设我们代码中设置三种状态的标识符,主动错误标识符,PassiveErrorFlag,被动错误标识符NegativeErrorFlag,总线关闭标识符BusOffFlag
判断语句如下
if((TEC<=127)&&(REC<=127))
PassiveErrorFlag=1;
else if((TEC>=128)&&(REC>=128))
{
PassiveErrorFlag=0; //注意清除上一个标识符
NegativeErrorFlag=1;
}
else if(TEC>=256)
{
NegativeErrorFlag=0; //注意清除上一个标识符
BusOffFlag =1;
}
从以上代码中,还可以看出一个问题,就是三种状态是无法跳变的,节点完成初始化后TEC=0和REC=0;
只能从主动错误--》被动错误
被动错误--》总线关闭
总线关闭--》主动错误
另外,根据经验我知道,假如总线上一个节点在总线上,其TEC累计达到120。此时断开电源,再上电,或者按下reset复位按键。其上一次累计的TEC清零。我对此的理解就是,程序并没有把此参数写进E2里面去。
1.3CAN总线错误类型
- 位错误
位错误:主要依赖方法,回读。位错误可以同时由TX节点和RX节点发出。
对于TX节点很好理解
发送帧时,对每一个bit进行回读,如果错误就发出错误帧。
接收RX节点
特指ACK位,当RX节点接收完帧后,发现无错误,就会将ACK位拉低成显性电平,如果此时RX节点,回读的数据为隐性。则会由RX节点发出位错误的错误帧
这里解释一下,发送TX节点和RX节点的概念,1:TX节点是指发送数据的节点(除了ACK位),RX节点是指接收数据段的节点(除了ACK位,在确认数据没有错误时由RX节点发送)。
总结:
1:其实只要记住一点即可,数据以bit为单位来看,那个节点发送此bit的数据,那个节点自查,有没有出现位错误?
2:仲裁段的位错误,有人会说仲裁段不检测位错误,这个结论是一个非常严重的错误,仲裁段肯定会检测位错误,只是一种情况下(仲裁段发送隐形电平时,读到显性电平。就不会报位错误)。
这里涉及到仲裁的概念,(这里不细说),但是仲裁时,各个节点之间的是不知道到底有几个节点在同时和我竞争总线的使用权。通讯节点之间的状态机是根据回读结果,来判断是否竞争失败的(注意不判断成功,失败者知道成功,成功者只知道我方正没有失败,到底是因为竞争成功或者总线上压根就没有其它节点与我竞争)
回到我们的主题:什么情况下仲裁段会报出bit错误?就是仲裁段发出显性电平,但是却读到的是
一句话:bit错误由该bit的发送节点自测
检查范围,SOF-EOF(不包括填充位)
不包括填充位:假如发送节点,发送连续5个显性位,下一位将会发送一个隐性位填充,如果回读发现是显性,不会报位错误,而认为是填充错误。(这里说蒙了,回读机制对填充的位也一直起作用)
发送节点的ACK,发送与回读不一致,忽略也不认为是,位错误。
接收单元,按照位错误的检测方式,来检测ACK位
无论是主动错误帧,还是被动错误帧,都会进行位检查。如果出现错误也会再根据自身状态,发出错误帧。
输出被动错误标志(6 个位隐性位)但检测出显性电平时,如何理解这句话,被动错误状态时,发出的是连续6个隐形电平。,当发送前5个bit时,此时其他节点并不知道总线已经是发出错误帧,以为是正常的数据发送,此区间段内如果其他节点发现错误,并发出显性错误标识符。规范是允许这样的。
将遵从错误标志的结束条件,等待检测出连续相同6 个位的值(显性或隐性),并不视为位错误。
- ACK错误
ACK错误,仅仅是由发送单元检测的错误,换句话说ACK错误帧,w也仅仅只能由发送节点来检测错误。只要他检测到ACK不位隐性,则判断为ACK错误,且在ACK的下一位(即ACK界定符)发送出错误帧。
- 填充错误
检测机制:在SOF-CRC段(不包括界定符)之间检测到存在6个连续相同极性的位,则根据自身状态发送主动错误帧或被动错误帧。
要弄清楚这个问题,我们必须弄懂,位填充的规则。
我们知道填充的作用范围:SOF-CRC。为什么不会包括ACK以后的段,则是因为如果包括,可能会影响ACK位。如果ACK位的前5bit全为1,则是发送节点将会填充1bit显性位0,如果实际上并没有接收节点去应答,发送节点也会自认为ACK有应答,会导致错误。
延伸一下,CANoe等设备中,HardwareSetup中有一个Self -ACK勾选项,如果勾选,即使总线上不存在接收节点,发送节点也不会报ACK错误。个人猜想,就是强制发送时,将这1bit直接发送为0。
即如果在CRC的最低4bit检测到隐性位+1bit的CRC界定符(一定位隐性)。则不会在ACK位进行填充1bit的显性位。
填充错误,如果发现错误,就会在检测到第6个相同极性的位的下一位,根据自身状态发布错误帧。
填充错误仅仅支持非错误帧的sof-crc段进行检查,其他如主动错误帧,ACK-EOF段,以及帧间间隔(>3bit的隐性位),以及总线静默状态下,直接不起作用。
- CRC错误
CRC校验的原理,发送单元在发送数据时或者发送数据前(至于到底是发送之前就已经计算好,还是发送中计算,恳亲大佬指点),会根据SOF-数据段之间的所有数据按照一个固定的公式和计算方法,已经计算好了一个CRC的值,发送出去。我估计这个值是提前算好的,如果不是
接收节点,也会按照同样的计算方法和固定公式,把接收到的SOF-SOF-数据段之间的所有数据,
然后将CRC校验值,与接收到的校验值比较,两者一致时,表示校验通过。
CRC值如果不一致,则会报crc错误。CRC校验使用算法是固定的,一般不需要对发送节点和接收节点作特别的算法配置。
总结:
1特别注意:CRC检测出错误时,不会立即发送,而是等ACK界定符之后。再根据自身状态发出错误帧。
总结2:需要注意接收端的CRC校验是不包括,填充位的。
注意点3:接收节点发现CRC错误,后不是立即发送错误帧,如果此时ACK发生错误,那么就会发送ACK错误帧,相当于CRC错误会被覆盖。
注意点4:接收节点不会对错误帧数据进行CRC校验。如果发现错误帧,程序将会终止CRC校验。发送节点也会停止位填充规则,接收节点也不会将检测位填充错误
- 格式错误:检查范围
数据帧( CRC 界定符、 ACK 界定符、EOF )• 遥控帧( CRC 界定符、 ACK 界定符、EOF )• 错误界定符• 过载界定符即使接收单元检测出 EOF(7 个位的隐性位)的最后一位(第 8 个位)为显性电平,也不视为格式错误。 即使接收单元检测出数据长度码(DLC)中 9∼15 的值时,也不视为格式错误。
总结1:格式错误只能是接收节点发送,也就是说格式检测的都是各种界定符号(都是隐形位),和EOF(7BIT的隐形位),接收节点,在此阶段如果接收到显性电平那么,将会报出格式错误
2:格式错误,本质上可以理解为只检测,数据段之后的两种界定符(ACK界定符合CRC界定符,和7个隐形位的EOF(End of Frame))。此外接收节点还对错误帧和过载帧的
3:同时,帧结束时,即EOF之后,检测到显性位,也不会报错误,也就说明了,格式错误是不对帧间间隔做出错误判断的。位监听错误也不会帧间间隔做出判断。
补充说明一种错误:(帧间间隔检测错误)
对帧间隔(IFS是规范中对帧间隔的简称),是最少3个bit隐形位构成。规范中是这样说的,数据帧和远程帧与前面的任何帧(数据帧,远程帧,错误帧和过载帧)之间必须必须有帧间隔。
也可以这样理解,数据帧和远程帧之前,必须存在一个帧间隔。而错误帧或远程帧前面,必须不能存在帧间隔。这就说明了帧间隔也是一种必须固定的格式,那为啥不去检测?所有五种格式错误都不支持检测?
IFS错误检测条件(1:EOF段被成功发送,发送节点没发现位错误,接收节点没发现格式错误)。则所有节点就需要进入监听模式
(此处需要理解另外一个知识,节点通讯的三种状态机)
1:发送模式
2:接收模式
3:监听总线模式
初始化时,节点进入监听模式,监听模式下,节点既不发送数据也不接收数据。(这里的不接收数据指的并不是不监控总线上的数据,实际上监听模式下,数据链路层依然读取总线上的数据)。当监听到总线上出现连续11个隐形位的状态位时,如果此时节点有数据需要发送,即进入数据发送模式。发送模式中在ID仲裁段内,如果仲裁失败,则自动进入数据接收模式。如果没有数据需要发送,则在检测到SOF后自动进入,数据接收模式。
直到下一个监听到11bit的隐形位。
回到正题,我们这里讨论如果在帧间间隔中,如果在EOF后,或者错误标识符后的三位中,检测到显性位,则直接报出过载帧。
此处又要提出一个问题,过载帧的两种发送情况。1在帧间间隔(只检测帧间隔的前3bit)发现显性位。则发出过载帧(此种状态下,总线)。2:因为接受节点的原因,无法处理新接受的数据,(这里的无法处理)是指数据链路层已经处理完毕,且没有发现错误。数据被打包成PDU数据包。传送至应用层时,数据无法被处理。
过载帧,只有一种类型,就是6显性位+8隐形位。没有像错误帧一样分为两种格式。过载
那么当节点处被动错误状态时,通过示波器观察出,节点发出了6个连续显性位,这是正常的。并不是异常。
节点检测到过载错误,发出过载帧,并不会使得节点状态计数器发生变化,这一点是需要特别注的。
1.4 总线节点的三种状态
1:主动错误状态
2:被动错误状态
3:busoff状态
总线上的三个节点,必然是处于这三个节点中的任意一个。CAN通讯中的各个节点的状态管理是单独进行的,也就是说是独立管理的。更准确一点的说法是分布式管理
1.4.1 主动错误节点
根据规范,总线上的节点如果正确完成初始化,则一定是属于主动错误的状态(TEC或REC均小于127)。此时通讯开始。错误检查机制启动。
总线上节点陆续检测到错误。假设一个节点老是检查到位错误,那么他的TEC将会一直增加。当累计到一定地步时,该节点将会进入被动错误状态。如果错误计数还一直增加,就会进入到Busoff(总线关闭状态)
主动错误状态下,会发送主动错误帧(6显性+8隐性错误帧)。主动错误状态下,节点检测到发送错误,发出主动错误帧后(包括错误标志+错误界定符号需完整的发送)。后会再次发送上一发送错误的帧。中间需要等待一个(3bit的帧间隔)。
1.4.2 被动错误节点
被动错误状态是,有两种状态会进入该种状态
1:被动错误状态--》进入主动 错误状态(判断条件TEC或REC>127)。
2:busoff--》主动错误状态(TEC<256)。
被动错误节点,处于此状态的节点,是可以接受和发送数据帧的,且一样可以检测五种错误和过载错误(这一点需要记住)。
被动错误和主动错误状态,在处理两件事上的逻辑是不同的。
1:发送错误帧的逻辑上不同,主动错误状态,错误帧是6显性+8隐性界定符,被动状态是6隐性+8隐性位。
2:数据重发模式下的逻辑不一样,这里的数据重发机制,具体是指帧发送状态下,如果发现数据发送错误,将会重新发送上一错误帧。
主动错误状态下,会直接在至少3bit隐性帧间隔后,直接发送,而被动错误状态下,则中间还需要间隔8bit隐性位的,
3:如果总线上只有一个节点,该节点发送数据帧后得不到应答,TEC最大只能计数到128,即这种情况下节点只会进入被动错误状态而不会进入总线关闭状态。
1.4.3:总线关闭状态:
- 总线关闭:
处于总线关闭状态的节点不允许发送和接收任何形式的帧报文。且只能通过用户请求进行恢复。
注:由于存在实现方式的不同,CAN总线关闭状态存在只允许用户请求恢复和检测到128个11位连续的隐性位时自恢复两种不同的恢复形式。 - 实际上处于BusOFF状态下的节点也会监控总线的电平状态
1.5:TEC和REC的计数详情
1:指示的是接收节点,检测到ack位错误,或者CRC位错误是,REC计数+1。但是接收单元检测出,错误帧中或过载帧中的位错误时,并不会使得错误计数增加。
2:接收单元发送完,错误标志后,如果检测到帧间间隔有错误(即检测显性位,规范规定必须是隐形位),TEC数据+8
3:发送单元,发送完错误标识后,TEC+8(如果发送单元检查出为错误,会在错误帧发出后,TEC计数增加)
4:发送单元在检测出主动错误标志位,或过载标志时,检查出位错误,则计数器加8(如果是检测出位错误,而后又在发出的错误标志检测出位错误,那么错误计数该如何增加?)
5:接收单元在检测出主动错误标志中,检测到位错误时,REC+8(注意虽然错误帧是接收节点发出的,但是增加的却是REC(REC无限增加也不会进入·BUSoff状态)
)
6:各单元连续检测出14个bit的显性位开始,到之后连续检测出8个bit的显性位,发送单元的TEC和接收单元的REC都增加8
7:发送单元正确发送数据TEC-1
8:接收单元正确接收数据,当REC<127时,错误计数-1,当REC>127时,错误计数直接=127
1.6奇妙的11bit隐性位间隔。
总线上出现连续11bit的隐形位,有两个地方
1:busoff状态的节点检测到128次连续的11个隐性bit位,就会 从BusOff状态转变到主动错误的状态。
1.6.1:就是以下状态下,处于主动错误的节点再次发送数据时,需要在帧间隔后,插入至少8bit的隐性电平(3+8=11bit的隐性bit)
1.6.2:另外一个会连续发出11bit隐性bit的电平就是,帧正确的被发送和接收,没有任何错误发生。ACK界定符(1bit隐性)+7bit隐性的EOF+3bit(帧间间隔)=11bit(隐性电平)
1.6.3:错误帧(主动+被动)界定符或过载帧界定符(8bit隐性)+帧间间隔=11bit(前提是下一帧必须是要发送正常帧)
1.7从CAPL代码看错误帧的结构
实际上CAPL编程中
代码如下所示
on errorFrame
{
write("this.time = %fs",this.time/100000.0);//获取时间戳,时间单位是秒
write("this.id = 0x%x",this.ID);
write("this.ErrorPosition_Bit = %d",this.ErrorPosition_Bit);
write("this.ErrorCode = 0x%x",this.ErrorCode);
}