既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
CAN ID : 0x20000004 = 10 0000 0000 0000 0000 0000 0000 0100, 即仲裁域的值。
-
Linux内核源码分析
因为出现此错误的是我厂的CAN控制器CPU TI 公司的AM3352, 内核版本为**Linux 3.2.0**
所以我们通过内核来看内核CAN错误can_id的定义:
[cpp] view plain copy print ?
- /* 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 */
/* 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 ?
- /* 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 */
/* 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 ?
- static int ti_hecc_error(struct net_device *ndev, int int_status,
- 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 ?
- 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);
- }
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);
}
-
总结
出现这个错误警告的原因很可能是:
-
此CAN总线上有干扰,导致CAN控制器发生接收错误,CAN总线上的信号经过收发器转化为差分电平信号,此时信号容易受到外界干扰,这样容易使CAN控制器发生接收错误,接收错误寄存器接收错误计数累计到一定值后会报此错误,如果错误计数达到一定程度甚至会导致总线关闭也就是BUS OFF. 如果最终确认是由于干扰引起的错误计数累计,则应该排查干扰源,然后增加抗干扰措施。
-
此CAN节点经过消息滤波后仍然需要接收大量的消息,导致CPU中的CAN控制器接收出错,并且错误计数达到了错误警告的上限。但是庆幸的是总线仍然没有过载,总线还可以正常收发数据,没有引起BUS OFF。但是对于一个安全可靠控制系统,这样的警告是绝对不允许的。我们需要通过一些手段去避免这样的问题出现,例如降低总线数据并发量,降低总线负载。
-
CAN总线设备离线与错误恢复
这种问题同样很诡异,但是似乎又是比较常见的问题,这样的问题出现的情况往往比较多,例如CAN节Power off也就是电断了,总线上也就肯定监听不到此CAN节点的心跳,或是CAN总线节点没有及时发送心跳,阻塞在任务处理里,又或是此CAN节点物理接线和总线断开,等等原因很多。
我这里要说的一种情况是我厂碰到的另一种问题。
-
问题描述
在整个系统重启后发现CAN总线上的某一个Cortex M0设备节点丢失,而其他的设备,也是同样M0架构的MCU和相同控制软件的设备则没有出现丢失的情况。
未完待续。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新