ARM Linux CAN 异常排查步骤
ARM Linux CAN 异常排查方法
1. 背景
项目上经常有反馈,说我们的CAN总线相关设备不受控,或者控制板重启也没用。登陆系统后查看,会发现经常出现CAN通信异常或超时的情况,由于我们的控制程序在CAN总线上连续6秒接收不到信息就会异常退出。所以表象上,经常只能看到CAN总线超时退出的程序打印日志。
这样显然是不利于问题偏差的,如何更容易定位问题,弄清哪里坏了,是现在需要解决的问题。本文最后会提供一个基于ARM Linux CAN的问题排查方法。
2. 进一步探索
后续发现我们使用的libsocketcan
这个开源库中,有一个接口叫can_get_state
,这个接口里可以读到当前CAN芯片的状态值。
这个接口里开源库的描述是这样的:
/** * @ingroup extern * can_get_state - get the current state of the device * * @param name name of the can device. This is the netdev name, as ifconfig -a shows * in your system. usually it contains prefix "can" and the numer of the can * line. e.g. "can0" * @param state pointer to store the state * * This one stores the current state of the can interface into the given * pointer. Valid states are: * - CAN_STATE_ERROR_ACTIVE * - CAN_STATE_ERROR_WARNING * - CAN_STATE_ERROR_PASSIVE * - CAN_STATE_BUS_OFF * - CAN_STATE_STOPPED * - CAN_STATE_SLEEPING * * The first four states is determined by the value of RX/TX error counter. * Please see relevant can specification for more information about this. A * device in STATE_STOPPED is an inactive device. STATE_SLEEPING is not * implemented on all devices. * * @return 0 if success * @return -1 if failed */int can_get_state(const char *name, int *state)
这里解开了CAN机制的一角,CAN总线的错误机制比较复杂,需要了解的较多。这里有篇写的不错的博客可以分享:
这里只说简单的便于理解的结论:
3. 需要了解的CAN机制相关背景结论:
CAN是差分电路,有两根线。其中显性电平为逻辑0,隐性电平为逻辑1。显性电平、隐性电平同时往总线上丢,会呈现显性电平。
当总线上的上出现连续的11位隐性电平,那么总线就处于空闲状态。
可以存在多个发送者,但是同一时刻只能有一个发。
逐位仲裁:当多个节点同时向总线发送消息时,对各个消息的标识符(即ID号)进行逐位仲裁,如果某个节点发送的消息仲裁获胜,那么这个节点将获取总线的发送权,仲裁失败的节点则立即停止发送并转变为监听(接收)状态。
所有的节点都可以检测出错误(错误检测功能);
检测出错误的节点会立即通知总线上其它所有的节点(错误通知功能);
正在发送消息的节点,如果检测到错误,会立即停止当前的发送,并在同时不断地重复发送此消息,直到该消息发送成功为止(错误恢复功能)CAN协议中规定,所有数据,当相同极性的电平持续五位时,则添加一个极性相反的位。
-
主动错误标志:6个连续的显性位;
被动错误标志:6个连续的隐性位;
错误界定符:8个连续的隐性位。
错误标志本身就是一种错误。
这里扩展一点,主动错误模式实际上错误标志位会覆盖总线上其他数据。但是被动错误由于是14个或者更多的隐性位,所以不影响其他节点的收发。
CAN总线每个节点有两个错误计数器,接收错误计数器和发送错误计数器,一般大体上来说,错误计数器会在节点出于对应状态的时候,探测到错误的时候 8,正常的时候-1。累积到128和255的时候,会发生节点状态转换。具体加减规则请查阅此文章:CAN总线学习笔记(3)- CAN协议错误帧
错误主动,错误被动两个状态都能正常通信。 这里有些博客会有误导说错误被动只能收不能发,实际是不正确的。出于BUS OFF状态的,无法和总线通信。只能等128个连续11隐性位。
4. 系统正常情况下,各个节点的状态值,以及有问题之后的演变:
一般情况,正常的时候,每个节点大多数时间出于
CAN_STATE_ERROR_ACTIVE
这个状态,也就是错误主动状态。别看这个状态名字叫错误,但是实际上就是对应的普通状态。标示这个节点检测到错误,会发出主动错误标示。随着问题的增多,节点逐渐会升级到
CAN_STATE_ERROR_WARNING
状态。但是这个状态并没有固定的硬件标示,实际上是一个软件层面的预警。也就是说,对于CAN_STATE_ERROR_ACTIVE
和CAN_STATE_ERROR_WARNING
而言,这个节点的任何逻辑行为(包括软硬件)都不会有什么区别。随着问题的继续增多,节点会升级到
CAN_STATE_ERROR_PASSIVE
状态。在这个状态下,节点的硬件行为会改变,收到错误的时候,发送的是被动错误标示。如果此时问题还会继续,则节点会进入
CAN_STATE_BUS_OFF
状态。这个时候只有检测到128个连续的11个隐性位才能回到CAN_STATE_ERROR_ACTIVE
。
5. 系统状态变换分析
最初情况下,有少量错误的时候,某个节点错了一次,总线上大家都会接收到主动错误标示,计数器会 8,但由于错误较少,后续如果一直正常,那么大家都是和平的。基本还是都会在0。
当某个节点本身出现了问题,总在错的时候,刚开始大家检测到错误都会报告错误,然后由于节点在发送状态的时候检测到错误是 8,节点处与接收状态检测到错误 1。所以,那个错误的节点会迅速进入错误被动状态,他发现错误也只能报告错误被动标示,错误被动标示实际上是不影响总线数据的。
当这个节点一直出问题,那么后续会继续跌到
CAN_STATE_BUS_OFF
状态。此时这个节点理论上要听到128次总线空闲才能重新回来。(这里也修正一种说法,出于BUS OFF状态的节点就一辈子回不来了,这也是错误的)
6. 了解到这些知识后,ARM LINUX层可以看那些地方加速排查问题呢?
6.1 cat /proc/net/can/stats
这个文件记录了can节点的收发情况,还有帧正确率,一个异常的现场看到如下的信息:
69227 transmitted frames (TXF) 14288017 received frames (RXF) 0 matched frames (RXMF) 0 % total match ratio (RXMR) 7 frames/s total tx rate (TXR) 1562 frames/s total rx rate (RXR) 0 % current match ratio (CRXMR) 8 frames/s current tx rate (CTXR) 917 frames/s current rx rate (CRXR) 0 % max match ratio (MRXMR) 10 frames/s max tx rate (MTXR) 4894 frames/s max rx rate (MRXR) 1 current receive list entries (CRCV) 1 maximum receive list entries (MRCV) 1 statistic resets (STR)
正常业务上,这个节点的发送应该是每秒8帧,接收应该是每秒40帧。而实际上这个记录上看来接收的帧数明显超大,峰值甚至到了4.8K,而且匹配率是0%,明显应该是由于有一个节点在疯狂输出导致的。
6.2 ifconfig can0
在CAN0的ifconfig中,有drop
,error
,overrun
,collisions
等信息,一样可以辅助判断问题。
can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 UP RUNNING NOARP MTU:16 Metric:1 RX packets:1251704 errors:0 dropped:0 overruns:0 frame:0 TX packets:312926 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:10 RX bytes:10013632 (9.5 MiB) TX bytes:2503408 (2.3 MiB) Interrupt:25
7. 排查方法
查看
can_get_state
中,对应的当前芯片的错误状态。查看
cat /proc/net/can/stats
中的匹配率和每秒收发频率。查看
ifconfig can0
中drop
,error
,overrun
,collisions
结合can错误状态,收发频率,其他数值,结合上文can机制进行分析。