CAN总线错误分析与解决

2 篇文章 0 订阅

CAN总线错误分析与解决

  1. 背景

写这篇文章是因为我看到网上介绍CAN总线错误处理的文章,清一色的都是生搬照抄教科书或是数据文档的内容,特别是国内很难找到一些有价值的内容,这让一些真正有需要的人很苦恼,包括我自己。这篇不打算对CAN的错误处理机制做进一步的探讨,而是从实际工作中碰到的具体问题来分析一些常见的CAN总线错误和解决办法。

  1. CAN节点数据收发过程

了解CAN节点在总线上数据上的收发过程很重要,之前的一篇文章讲解了一些CAN总线的错误处理机制,但是那些都是理论上的东西,如果不深入了解CAN总线上的数据收发过程,理解那些理论的东西难免有些晦涩。

我们知道CAN总线上的每个节点往总线上发送数据的同时会同时读取总线上的数据,并与自己发送的数据作对比。

CAN信息发送成功后,在这个间隙内,接收节点可以准备要回复的信息,也就是把应答场填充为显性0,在发送时其为隐性1应答过程可能如下:当信息传输到ACK前的Del时,可以认为信息已经传输完毕,接收节点也接收到了足够的信息来检测接收的信息是否正确,所以这时接收节点就会检测信号是否正确,如果正确,就将ACK置位为显性0,注意这时,发送节点因为还在发送而接收节点又将ACK信息置位为1,所以它就会在回读时检测到ACK为0,判断接收成功。注意:这其中有个接收节点用显性覆盖隐性---覆盖ACK位的过程,覆盖+回读。

ACK前后各加一个Del,就是为了考虑到时间误差,让接收节点有足够的时间对ACK确认。这个过程说明,CAN发送是个双向互动的过程,发送节点一边发送,一边对节点进行回收确认数据正确,而接收节点也时刻接收,并在正确的时间将ACK设置为1。

  1. CAN总线错误

CAN总线错误分别有发送和接收错误计数,计数达到一定的累计以后就会产生CAN BUS OFF, 这说明CAN总线上出现了严重的错误。如下图CAN总线产生错误后的状态转换机制:

如果出现了BUS OFF,总线上的节点需要做一些动作,例如重启CAN控制器或是重新上电,但是这些都只是一些补救措施,最根本的还是需要找到引起BUS OFF的根源。

CAN总线分析的一些工具和文档:

  • CAN分析仪或者逻辑分析仪
  • 数字示波器
  • 相关的软件debug工具
  • CAN控制器芯片数据手册,这很重要
  • 硬件电路图
  • CAN协议文档
  • 相关版本的Linux内核源码

 

  1. CAN节点发送错误不成功

    1. 问题描述与分析

挂载在CAN总线上的一个节点向总线上发送数据不成功,用逻辑分析仪也看不到任何波形。PS: 这应该是我碰到的最坑爹的事情了。下面具体来看看怎么不成功。于是调试中断查看CAN_STATUS即CAN状态寄存器显示0xE5, 查看CPU数据手册:

 

CAN总线状态直接进入了BUS OFF状态,这意味着错误计数已经超限,查看CPU收发寄存器的收发错误计数显示发送错误计数TEC达到248, 接收错误计数为0;这很明显,数据压根没有发送到总线上。

再进一步查看寄存器值LEC即LAST ERROR CODE 最后一个错误代码, 显示是BIT0 ERROR:

查看上面的错误代码表可知,BIT0错误也就是在发送数据期间,虽然CAN节点设备想要发送一个显性位,也就是逻辑0,但是CAN总线同时监听到总线上的数据位为隐性位,即逻辑1。这意味着CAN core往总线上发送的数据第一位就已经出错了,压根没有将数据经过CAN收发器传送到CAN总线上。

一直在使用CAN总线的我厂和我从来没遇到这等奇事,但是由于是新的CPU的开发所以在怀疑硬件的问题的同时也在排查软件问题,但是经过一阵排查,没有发现软件上的问题。回头再分析硬件,又经过一阵排查溯源,发现CPU的CAN收发线与CAN收发气的收发线接反,直接崩溃(PS: 硬件的大哥你能不能不要坑小弟):

  1. 总结

CAN节点发送数据不成功,首先分析是不是CAN控制器本身的问题,查看CPU中的CAN core的状态寄存器,分析是否有BUS OFF, 如果存在BUS OFF, 则进一步查看具体的错误信息,是主动的错误还是被动的错,发送错误计数有没有超限,最后一次发生的错误状态是什么,查看是位填充错误还是格式错误等其他错误,然后具体问题具体分析。这种错误一般是有硬件发送线路出现问题引起,例如光隔次边不导通,发送接口接触不良等,再则是一些奇葩的错误,例如本例,收发线直接接反了,坑爹啊!

 

  1. CAN Socket 的CAN节点检测到错误帧

    1. 问题描述

我们看到以下的CAN Socket日志,在38秒内的三个错误帧,但是并没有引起总线的BUS OFF,这说明总线上检测到了错误,有可能受到了干扰,也有可能是数据发送太密集导致的总线过载,但是在这38秒内出现错误,但是期间又恢复正常。

CAN ID : 0x20000004 = 10 0000 0000 0000 0000 0000 0000 0100, 即仲裁域的值。

  1. Linux内核源码分析

因为出现此错误的是我厂的CAN控制器CPU TI 公司的AM3352, 内核版本为Linux 3.2.0

所以我们通过内核来看内核CAN错误can_id的定义:

  1. /* error class (mask) in can_id */  
  2.   
  3. #define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */  
  4.   
  5. #define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */  
  6.   
  7. #define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */  
  8.   
  9. #define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */  
  10.   
  11. #define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */  
  12.   
  13. #define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */  
  14.   
  15. #define CAN_ERR_BUSOFF 0x00000040U /* bus off */  
  16.   
  17. #define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */  
  18.   
  19. #define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */  
/* error class (mask) in can_id */

#define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */

#define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */

#define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */

#define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */

#define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */

#define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */

#define CAN_ERR_BUSOFF 0x00000040U /* bus off */

#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */

#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */

由错误帧CAN ID : 0x20000004 = 10 0000 0000 0000 0000 0000 0000 0100, 去除最高为的1(SOFZ帧起始位?),因为仲裁位是29位,所以应该是0 0000 0000 0000 0000 0000 0000 0100 =0x00000004,既不是CAN_ERR_BUSOFF也不是CAN_ERR_BUSERROR, 而是CAN_ERR_CTRL, 即CAN控制器的问题,而我们在看data[1]描述的CAN 控制器错误类型描述:

  1. /* error status of CAN-controller / data[1] */  
  2.   
  3. #define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */  
  4.   
  5. #define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */  
  6.   
  7. #define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */  
  8.   
  9. #define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */  
  10.   
  11. #define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */  
  12.   
  13. #define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */  
  14.   
  15. #define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */  
/* error status of CAN-controller / data[1] */

#define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */

#define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */

#define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */

#define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */

#define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */

#define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */

#define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */

我们再看我们截取的错误帧数据报文中显示data[1] = 0x04,如下图所示:

即具体错误为:

#define CAN_ERR_CRTL_RX_WARNING  0x04 /* reached warning level for RX errors */

也就是说CAN 控制器接收错误计数达到了警告的级别,需要提出警告,如果再这样下去CAN控制器就要过载了,甚至会引起总线的BUS OFF.

我们再回头看内核源码对此错误的处理:产生data[1] = CAN_ERR_CRTL_RX_WARNING 错误的内核源函数为:

  1. static int ti_hecc_error(struct net_device *ndev, int int_status,  
  2.   
  3. int err_status)  
static int ti_hecc_error(struct net_device *ndev, int int_status,

int err_status)

HECC也就是TI公司高速终端CAN控制器的简称,用以上的函数描述TI CAN core的错误处理,如下,我们可以看到也就是CAN控制器接收错误计数REC大于96的时候内核就会报此错误

  1. if (int_status & HECC_CANGIF_WLIF) { /* warning level int */  
  2.         if ((int_status & HECC_CANGIF_BOIF) == 0) {  
  3.             priv->can.state = CAN_STATE_ERROR_WARNING;  
  4.             ++priv->can.can_stats.error_warning;  
  5.             cf->can_id |= CAN_ERR_CRTL;  
  6.             if (hecc_read(priv, HECC_CANTEC) > 96)  
  7.                 cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;  
  8.             if (hecc_read(priv, HECC_CANREC) > 96)  
  9.                 cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;  
  10.         }  
  11.         hecc_set_bit(priv, HECC_CANES, HECC_CANES_EW);  
  12.         dev_dbg(priv->ndev->dev.parent, "Error Warning interrupt\n");  
  13.         hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR);  
  14.     }  
if (int_status & HECC_CANGIF_WLIF) { /* warning level int */
        if ((int_status & HECC_CANGIF_BOIF) == 0) {
            priv->can.state = CAN_STATE_ERROR_WARNING;
            ++priv->can.can_stats.error_warning;
            cf->can_id |= CAN_ERR_CRTL;
            if (hecc_read(priv, HECC_CANTEC) > 96)
                cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
            if (hecc_read(priv, HECC_CANREC) > 96)
                cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
        }
        hecc_set_bit(priv, HECC_CANES, HECC_CANES_EW);
        dev_dbg(priv->ndev->dev.parent, "Error Warning interrupt\n");
        hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR);
    }

  1. 总结

出现这个错误警告的原因很可能是:

  1. CAN总线上有干扰,导致CAN控制器发生接收错误,CAN总线上的信号经过收发器转化为差分电平信号,此时信号容易受到外界干扰,这样容易使CAN控制器发生接收错误,接收错误寄存器接收错误计数累计到一定值后会报此错误,如果错误计数达到一定程度甚至会导致总线关闭也就是BUS OFF. 如果最终确认是由于干扰引起的错误计数累计,则应该排查干扰源,然后增加抗干扰措施。
  2. CAN节点经过消息滤波后仍然需要接收大量的消息,导致CPU中的CAN控制器接收出错,并且错误计数达到了错误警告的上限。但是庆幸的是总线仍然没有过载,总线还可以正常收发数据,没有引起BUS OFF。但是对于一个安全可靠控制系统,这样的警告是绝对不允许的。我们需要通过一些手段去避免这样的问题出现,例如降低总线数据并发量,降低总线负载。

     

  1. CAN总线设备离线与错误恢复

这种问题同样很诡异,但是似乎又是比较常见的问题,这样的问题出现的情况往往比较多,例如CAN节Power off也就是电断了,总线上也就肯定监听不到此CAN节点的心跳,或是CAN总线节点没有及时发送心跳,阻塞在任务处理里,又或是此CAN节点物理接线和总线断开,等等原因很多。

我这里要说的一种情况是我厂碰到的另一种问题。

  1. 问题描述

在整个系统重启后发现CAN总线上的某一个Cortex M0设备节点丢失,而其他的设备,也是同样M0架构的MCU和相同控制软件的设备则没有出现丢失的情况。

未完待续。


  • 47
    点赞
  • 291
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: CAN总线在车载电子系统中起着举足轻重的作用,能够处理多种类型的数据,但在实际应用中,由于外界干扰或器件失灵等原因,常常会发生错误。为了保证系统的正常运行,必须采取一定的错误处理机制。而其中一个典型的错误是RBus OFF问题。 CAN总线的RBus OFF问题是指一个CAN节点失去了对总线的控制能力,从而影响了整个网络的数据通信。首先我们需要了解CAN总线的工作机制,在总线上的每个节点都有一个控制器,这些控制器之间通过总线传输数据。当接收到一条信息时,节点必须发送一条ACK消息来表示确认。但如果一个节点在一定时间内(约128个时钟周期,即1ms)没有发送任何消息,其他节点将会认为它已经失去了控制能力,并从总线上把该节点排除掉,这就是RBus OFF问题的发生。 当RBus OFF问题发生时,节点会停止发送和接收数据,并对系统进行重启,从而恢复正常的数据通信。解决这个问题的方式是对CAN控制器加入看门狗机制,在一定时间内检查和发送数据,以避免被其他节点排除掉。另外,在电路设计中要避免干扰,减少外部因素对系统的影响,从而提高系统的可靠性和稳定性。 总之,RBus OFF问题是CAN总线应用中常见的错误,但只要采用合理的错误处理机制和电路设计,就能够有效地避免和解决这一问题。 ### 回答2: CAN总线错误处理机制是CAN总线通信过程中的一个非常重要的部分。它主要负责处理CAN总线上出现的各种错误,以保证通信的可靠性和稳定性。其中,RBUS OFF错误CAN总线上比较常见的一种错误,其表现为节点进入了总线关闭状态,导致节点无法正常进行通信。下面我们就来详细分析下RBUS OFF错误的产生原因和解决方法。 首先,我们需要了解下RBUS OFF错误的产生原因。在CAN总线通信过程中,如果某个节点发送的错误数量超过了一定的阈值,那么该节点就会进入总线关闭状态。这种情况通常是由于节点硬件故障或者软件编程错误导致的。当一个节点进入总线关闭状态后,它将无法发送和接收任何数据,同时也无法恢复到正常的通信状态,这样就会严重影响整个CAN总线的通信效率和可靠性。 那么,针对RBUS OFF错误我们应该采取哪些措施来解决呢?首先,我们需要对故障节点进行检测和修复。如果故障节点是由于硬件故障引起的,那么需要对其进行更换或者维修。如果故障是因为软件编程错误导致的,那么需要对程序进行修正和优化。此外,还需要对整个CAN总线系统进行优化和升级,通过加强总线监控和故障检测,避免出现类似的故障,并提高整个系统的可靠性和稳定性。 综上所述,RBUS OFF错误CAN总线通信中一个比较严重的故障现象,它会影响到整个系统的通信效率和稳定性。在解决这个问题时,我们需要对故障节点进行检测和修复,同时采取措施对CAN总线系统进行优化和升级,确保CAN总线通信的可靠性和稳定性。 ### 回答3: CAN总线是一种广泛应用于汽车、工业控制等领域的串行通信协议。在CAN总线通讯中,可能会出现所谓的“RBus off”问题。 “RBus off”是指接收节点在规定的时间内没有收到同步信号,或者收到的错误信号超过规定数量,导致它无法正确接收数据。在这种情况下,接收节点会主动断开连接,并且不再发送或接收任何数据,这就是CAN总线错误处理机制。 造成“RBus off”问题的原因有很多,可能是通讯线路问题,也可能是接收节点硬件故障,或者是接收节点程序出现问题。为了迅速排查问题,可以采取以下措施: 1. 检查CAN通讯线路的连接情况和质量,是否有松动、损坏等问题。 2. 对接收节点进行硬件检测,比如检查电压是否稳定、电容是否漏电等。 3. 检查接收节点的程序,是否存在程序bug、误操作等问题。 4. 在CAN通讯双方都启动的情况下,向CAN总线发送数据,观察是否能够正确发送和接收到数据。 另外,在实际场景中,需要注意的是,如果CAN总线中有多个节点同时出现“RBus off”问题,就会导致整个网络崩溃。因此,在进行CAN总线的设计和部署时,必须严格遵守CAN总线的标准和规范,保证通讯的稳定和可靠。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值