您尚未登录。

楼主 # 2024-05-24 09:37:58

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,379
积分: 1344.5

d133上电时,can总线上正好有其它设备正在发送数据,d133有很大概率报can接收错误。

怀疑是总线上其它设备发送数据发送了一半,d133才开始接收,结果报错。关键是,一次报错后,接下来所有的接收数据都报错。

[E] hal_can_bus_error_msg()303 error in RX direction, [E] hal_can_bus_error_msg()314 Other Error, [E] hal_can_bus_error_msg()335 Tolerate dominant bits

有什么解决办法好呢?一旦进入can错误处理这里就进行重启操作?

离线

#1 2024-05-25 07:40:59

tomas
会员
注册时间: 2024-03-26
已发帖子: 39
积分: 124

Re: d133上电时,can总线上正好有其它设备正在发送数据,d133有很大概率报can接收错误。

也是准备用can,但没测试过。最好不要有啥问题。

离线

楼主 #2 2024-05-25 09:09:19

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,379
积分: 1344.5

Re: d133上电时,can总线上正好有其它设备正在发送数据,d133有很大概率报can接收错误。

irqreturn_t hal_can_isr_handler(int irq_num, void *arg)
{
    u32 int_status;
    can_handle *phandle = (can_handle *)arg;

    int_status = readl(phandle->can_base + CAN_INTR_REG);

    if (int_status & (CAN_INTR_ERRB | CAN_INTR_ARBLOST | CAN_INTR_ERRP |
                CAN_INTR_WAKEUP | CAN_INTR_OVF | CAN_INTR_ERRW))
        hal_can_error_handle(phandle, int_status);

    if (int_status & CAN_INTR_TX) {
        phandle->status.sndpkgcnt++;
        if (phandle->callback)
            phandle->callback(phandle, (void *)CAN_EVENT_TX_DONE);
    }

    if ((int_status & CAN_INTR_RX) && !(int_status & CAN_INTR_OVF)) {
        hal_can_rx_frame(phandle->can_base, &phandle->msg);
        if (phandle->callback)
            phandle->callback(phandle, (void *)CAN_EVENT_RX_IND);
    }

    writel(int_status, phandle->can_base + CAN_INTR_REG);
    return IRQ_HANDLED;
}

aic_hal_can.c文件里,can中断函数中,是先看状态寄存器,一旦出现错误,就先去进行错误处理。

如果d133先上电,而总线上其它设备还没上电,则也会报can发送错误,这是可以理解的,can总线上没有其它can设备是发送不成功的。但其它can设备一上电,这个发送错误就会立刻消除了。
而接收错误这里,大部分情况下会一直错下去。

离线

#4 2024-05-25 12:16:06

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 662
积分: 795
个人网站

Re: d133上电时,can总线上正好有其它设备正在发送数据,d133有很大概率报can接收错误。

因为CAN规范的规定,大部分芯片的CAN外设都是差不多的。CAN收发出现错误会累计错误计数,只有当错误计数达到一定阀值才会触发bus off异常,此时CAN控制器会进入reset状态。
在reset状态下不能进行正常的收发处理,需要设置其状态到normal状态才能进行正常收发。

离线

楼主 #5 2024-05-25 13:51:39

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,379
积分: 1344.5

Re: d133上电时,can总线上正好有其它设备正在发送数据,d133有很大概率报can接收错误。

这是can错误处理函数,直接CAN_INTR_ERRB错误,进hal_can_bus_error_msg()函数。
看到里边有对发送错误计数寄存器的读取staus.txerr,超过阈值后,将can设置为复位模式。
虽然有对接收错误计数寄存器stauts.rxerr的读取,但是没看到有其它地方调用到。
另有对溢出错误的累加计数。
而看错误提示,应该是:
ERRB_INT:Bus Error Interrupt,总线错误中断(节点检测到总线上发生了错误)。
错误信息里提到的是,接收方向错误,Tolerate dominant bits错误。

static void hal_can_error_handle(can_handle *phandle, u32 err_status)
{
    u32 can_status;
    u8 errcode;

    errcode = readb(phandle->can_base + CAN_ERRCODE_REG) &
              CAN_ERRCODE_SEGCODE_MASK;

    can_status = readl(phandle->can_base + CAN_STAT_REG);
    phandle->status.rxerr = readl(phandle->can_base + CAN_RXERR_REG);
    phandle->status.txerr = readl(phandle->can_base + CAN_TXERR_REG);

    if (err_status & CAN_INTR_ERRB) {
        hal_can_bus_error_msg(phandle);
    }

    if (err_status & CAN_INTR_ARBLOST) {
        hal_can_arblost_msg(phandle);
    }

    if (err_status & CAN_INTR_ERRP) {
        if (phandle->status.current_state == PASSIVE_STATUS)
            phandle->status.current_state = WARNING_STATUS;
        else
            phandle->status.current_state = PASSIVE_STATUS;
    }

    if (err_status & CAN_INTR_OVF) {
        phandle->status.othererrcnt++;
        phandle->status.recverrcnt++;
        hal_can_set_mode(phandle, CAN_MODE_RST);
        hal_can_mode_release(phandle, CAN_MODE_RST);
        if (phandle->callback)
            phandle->callback(phandle, (void *)CAN_EVENT_RXOF_IND);
        /* clear bit */
        writel(CAN_MCR_CLR_OVF, phandle->can_base + CAN_MCR_REG);
    }

    if (err_status & CAN_INTR_ERRW) {
        if (can_status & CAN_STAT_BUS)
            phandle->status.current_state = BUS_OFF;
        else if (can_status & CAN_STAT_ERR)
            phandle->status.current_state = WARNING_STATUS;
        else
            phandle->status.current_state = ACTIVE_STATUS;
    }

    if (phandle->status.current_state == BUS_OFF)
        hal_can_mode_release(phandle, CAN_MODE_RST);

    if (phandle->status.txerr > CAN_ERRP_THRESHOLD &&
        errcode == CAN_ERRCODE_ACK_SLOT)
    {
        writel(CAN_MCR_ABORTREQ, phandle->can_base + CAN_MCR_REG);
        hal_can_set_mode(phandle, CAN_MODE_RST);
        hal_can_mode_release(phandle, CAN_MODE_RST);
    }
}

hal_can_bus_error_msg()函数里,打印出了错误的方向、错误的类型、在哪个阶段出的错。

static void hal_can_bus_error_msg(can_handle *phandle)
{
    u8 i;
    u8 errinfo = readb(phandle->can_base + CAN_ERRCODE_REG);
    u8 errtype = (errinfo & CAN_ERRCODE_ERRTYPE_MASK) >> 6;
    u8 errdir = (errinfo & CAN_ERRCODE_DIR) >> 5;
    u8 errcode = errinfo & CAN_ERRCODE_SEGCODE_MASK;

    for (i = 0; i < ARRAY_SIZE(bus_err_dir); i++) {
        if (errdir == bus_err_dir[i].code) {
            hal_log_err("%s, ", bus_err_dir[i].msg);
            if (i)
                phandle->status.recverrcnt++;
            else
                phandle->status.snderrcnt++;
            break;
        }
    }

    for (i = 0; i < ARRAY_SIZE(bus_err_type); i++) {
        if (errtype == bus_err_type[i].code) {
            hal_log_err("%s, ", bus_err_type[i].msg);
            switch (i) {
            case 0:
                phandle->status.biterrcnt++;
                break;
            case 1:
                phandle->status.formaterrcnt++;
                break;
            case 2:
                phandle->status.stufferrcnt++;
                break;
            default:
                phandle->status.othererrcnt++;
                break;
            }
            break;
        }
    }

    for (i = 0; i < ARRAY_SIZE(bus_err_code); i++) {
        if (errcode == bus_err_code[i].code) {
            hal_log_err("%s\n", bus_err_code[i].msg);
            break;
        }
    }
}

翻了手册,看到这么一段话:

错误报警阈值ERRWT将作为报警功能提示当前发生的总线错误,且在控制器进入被动错误状态之前被触发。在复位模式下,ERRWT数值可在错误报警阈值寄存器(CAN_ERRWT)中进行配置。当TEC和/或REC数值大于等于ERRWT时,ERR_STAT 被置1。当TEC 和REC 数值都小于ERRWT时, ERR_STAT被复位0。只要ERR_STAT或BUS_STAT位值发生变化,便会触发错误报警中断ERRW_INT。

当TEC和/或REC数值大于127 时,节点进入被动错误状态。当TEC和REC数值都小于等于127时,节点重新变为主动错误状态。节点在主动错误和被动错误状态之间切换时,都将触发被动错误中断ERRP_INT。

当TEC 数值大于255 时,节点进入总线关闭离线状态。此时,控制器将REC数值置为0、TEC数值置为127、BUS_STAT位置1、产生错误报警中断ERRW_INT、控制器进入复位模式。

为了返回主动错误状态,必须进行离线恢复。首先需要退出复位模式,进入正常操作模式;然后要求节点在总线上检测到128 次11 个连续隐性位。每一次检测到11 个连续隐性位时,TEC 数值都将减1,当离线恢复完成后(TEC 数值从127 减小到0),BUS_STAT位复位为0,从而触发错误报警中断ERRW_INT。

看can相关寄存器,有个CAN_MODE寄存器,0为复位模式,3为接收过滤。

最近编辑记录 Gentlepig (2024-05-25 14:11:31)

离线

楼主 #6 2024-05-28 15:42:25

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,379
积分: 1344.5

Re: d133上电时,can总线上正好有其它设备正在发送数据,d133有很大概率报can接收错误。

bit4 R/W 0x0 SLEEP_MOD:Sleep Mode,休眠模式,只在复位模式可写
0x0:正常操作。控制器唤醒。
0x1:休眠模式。CAN无总线活动和无中断发生。

bit3 R/W 0x0 FILTER_MOD:Acceptance Filter Mode,接收过滤器模式
0x0:双过滤模式。使用两个过滤器。
0x1:单过滤模式。使用一个4字节过滤器。

bit2 R/W 0x0 SELFTEST_MOD:Self Test Mode,自测模式
0x0:正常操作。发送成功需有应答。
0x1:自测模式。在SELF_REQ自接收请求指令下,无需其它节点
参与也能完成整个节点测试,发送成功无需应答。

bit1 R/W 0x0 LISTEN_MOD:Listen Only Mode,只听模式
0x0:正常操作。错误计数停止于当前值 。
0x1:只听模式。只接收总线上数据,不产生应答信号,
也不更新接收错误计数。

bit0 R/W 0x1 RST_MOD:Reset Mode,复位模式
0x0:正常操作。控制器返回正常操作模式。
0x1:复位模式。发送或接收中止,控制器处于可配置状态。

这是can状态寄存器的描述。
程序里出错时打印了状态寄存器的值,我看是0xA2和0xF3差不多交替出现。这么看,像是在自动切换复位模式和正常模式。

[E] hal_can_bus_error_msg()340 0xA2
[E] hal_can_bus_error_msg()303 error in RX direction, [E] hal_can_bus_error_msg()314 Stuff Error, [E] hal_can_bus_error_msg()335 ID28~21
[E] hal_can_bus_error_msg()340 0xF3
[E] hal_can_bus_error_msg()303 error in RX direction, [E] hal_can_bus_error_msg()314 Other Error, [E] hal_can_bus_error_msg()335 Tolerate dominant bits
[E] hal_can_bus_error_msg()340 0xA2
[E] hal_can_bus_error_msg()303 error in RX direction, [E] hal_can_bus_error_msg()314 Other Error, [E] hal_can_bus_error_msg()335 Tolerate dominant bits
[E] hal_can_bus_error_msg()340 0xF3
[E] hal_can_bus_error_msg()303 error in RX direction, [E] hal_can_bus_error_msg()314 Other Error, [E] hal_can_bus_error_msg()335 Tolerate dominant bits
[E] hal_can_bus_error_msg()340 0xA2
[E] hal_can_bus_error_msg()303 error in RX direction, [E] hal_can_bus_error_msg()314 Stuff Error, [E] hal_can_bus_error_msg()335 ID28~21
[E] hal_can_bus_error_msg()340 0xA2
[E] hal_can_bus_error_msg()303 error in RX direction, [E] hal_can_bus_error_msg()314 Other Error, [E] hal_can_bus_error_msg()335 Tolerate dominant bits
[E] hal_can_bus_error_msg()340 0xF3
[E] hal_can_bus_error_msg()303 error in RX direction, [E] hal_can_bus_error_msg()314 Stuff Error, [E] hal_can_bus_error_msg()335 ID28~21

最近编辑记录 Gentlepig (2024-05-28 15:43:19)

离线

楼主 #7 2024-06-24 14:52:17

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,379
积分: 1344.5

Re: d133上电时,can总线上正好有其它设备正在发送数据,d133有很大概率报can接收错误。

更新1.0.5版本的sdk后,上电时can容易进错误中断的现象消除了。
对比新旧两版test_can例程,发现新例程在打开并配置好can后,增加了句打开can中断的语句。

    //enable CAN TX interrupt
    rt_device_control(can_tx_dev, RT_DEVICE_CTRL_SET_INT, NULL);

上一版的例程里没这么一句,但是却能进can中断。奇怪。

另,新版的sdk,lvgl的rtp使能后正常了,但是旋转屏幕却变得不正常了。
在lv_port_disp.c里的lv_port_disp_init()函数里,增加这一句:

    // disp_drv.rotated = LV_DISP_ROT_180;

画面视觉效果没有旋转,但是点击按钮没反映,而按旋转后的位值虚空点击,却出现了点击效果。
感觉是,画面貌似旋转了,但是呈现没旋转。

--------------------------------------------------------

比较下了,两版sdk,打开can时,参数里都带有中断方式参数,新版的,在设置完波特率等后,又通过ctrl命令打开中断。
于是对比了两版sdk里rtt_kernel里的can驱动部分,的rt_can_open(),发现给的参数里有中断方式,那么就在函数结尾处直接调用contrl命令打开中断。而新版里注释了这部分。
那么问题应该就是就板过早的打开了can接收中断,波特率还未配置,滤波器组也未配置,结果总线上有信息,于是就报错进错误中断了。

----------------------

lvgl屏幕旋转的问题是,忘了使能USE_DRAW_BUF这个宏定义。

最近编辑记录 Gentlepig (2024-06-24 15:40:30)

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn