CAN总线错误分析与解决_can总线的错误帧,应用层要处理吗 ,2024年最新靠这份物联网嵌入式开发知识点PDF成功跳槽

163 阅读7分钟

img img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

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

  1. Linux内核源码分析

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

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

[cpp] view plain copy print ?

  1. /* error class (mask) in can_id */
  2. #define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */
  3. #define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */
  4. #define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */
  5. #define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */
  6. #define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */
  7. #define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */
  8. #define CAN_ERR_BUSOFF 0x00000040U /* bus off */
  9. #define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */
  10. #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 控制器错误类型描述:

[cpp] view plain copy print ?

  1. /* error status of CAN-controller / data[1] */
  2. #define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */
  3. #define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */
  4. #define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */
  5. #define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */
  6. #define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */
  7. #define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */
  8. #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 错误的内核源函数为:

[cpp] view plain copy print ?

  1. static int ti_hecc_error(struct net_device *ndev, int int_status,
  2. 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的时候内核就会报此错误

[cpp] view plain copy print ?

  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。但是对于一个安全可靠控制系统,这样的警告是绝对不允许的。我们需要通过一些手段去避免这样的问题出现,例如降低总线数据并发量,降低总线负载。

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

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

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

  1. 问题描述

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

未完待续。

img img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取