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总线的错误机制比较复杂,需要了解的较多。这里有篇写的不错的博客可以分享:

  1. CAN总线学习笔记(3)- CAN协议错误帧
  2. CAN总线学习笔记(1)- CAN基础知识

这里只说简单的便于理解的结论:

3. 需要了解的CAN机制相关背景结论:

  1. CAN是差分电路,有两根线。其中显性电平为逻辑0,隐性电平为逻辑1。显性电平、隐性电平同时往总线上丢,会呈现显性电平

  2. 当总线上的上出现连续的11位隐性电平,那么总线就处于空闲状态。

  3. 可以存在多个发送者,但是同一时刻只能有一个发。

  4. 逐位仲裁:当多个节点同时向总线发送消息时,对各个消息的标识符(即ID号)进行逐位仲裁,如果某个节点发送的消息仲裁获胜,那么这个节点将获取总线的发送权,仲裁失败的节点则立即停止发送并转变为监听(接收)状态

  5. 所有的节点都可以检测出错误(错误检测功能);
    检测出错误的节点会立即通知总线上其它所有的节点(错误通知功能);
    正在发送消息的节点,如果检测到错误,会立即停止当前的发送,并在同时不断地重复发送此消息,直到该消息发送成功为止(错误恢复功能)

  6. CAN协议中规定,所有数据,当相同极性的电平持续五位时,则添加一个极性相反的位

  7. 主动错误标志:6个连续的显性位;
    被动错误标志:6个连续的隐性位;
    错误界定符:8个连续的隐性位。

错误标志本身就是一种错误。

这里扩展一点,主动错误模式实际上错误标志位会覆盖总线上其他数据。但是被动错误由于是14个或者更多的隐性位,所以不影响其他节点的收发。

  1. CAN总线每个节点有两个错误计数器,接收错误计数器和发送错误计数器,一般大体上来说,错误计数器会在节点出于对应状态的时候,探测到错误的时候 8,正常的时候-1。累积到128和255的时候,会发生节点状态转换。具体加减规则请查阅此文章:CAN总线学习笔记(3)- CAN协议错误帧

  2. 错误主动,错误被动两个状态都能正常通信。 这里有些博客会有误导说错误被动只能收不能发,实际是不正确的。出于BUS OFF状态的,无法和总线通信。只能等128个连续11隐性位。

4. 系统正常情况下,各个节点的状态值,以及有问题之后的演变:

  1. 一般情况,正常的时候,每个节点大多数时间出于CAN_STATE_ERROR_ACTIVE这个状态,也就是错误主动状态。别看这个状态名字叫错误,但是实际上就是对应的普通状态。标示这个节点检测到错误,会发出主动错误标示。

  2. 随着问题的增多,节点逐渐会升级到CAN_STATE_ERROR_WARNING状态。但是这个状态并没有固定的硬件标示,实际上是一个软件层面的预警。也就是说,对于CAN_STATE_ERROR_ACTIVECAN_STATE_ERROR_WARNING而言,这个节点的任何逻辑行为(包括软硬件)都不会有什么区别。

  3. 随着问题的继续增多,节点会升级到CAN_STATE_ERROR_PASSIVE状态。在这个状态下,节点的硬件行为会改变,收到错误的时候,发送的是被动错误标示。

  4. 如果此时问题还会继续,则节点会进入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中,有droperroroverruncollisions等信息,一样可以辅助判断问题。

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. 排查方法

  1. 查看can_get_state中,对应的当前芯片的错误状态。

  2. 查看cat /proc/net/can/stats中的匹配率和每秒收发频率。

  3. 查看ifconfig can0droperroroverruncollisions

  4. 结合can错误状态,收发频率,其他数值,结合上文can机制进行分析。

来源:https://www.icode9.com/content-3-798601.html

(0)

相关推荐