NXP MCU 技术论坛
直播中

幽默

10年用户 887经验值
擅长:362163
私信 关注
[问答]

MCIMX6G2CVM05AB imx6ul启动偶尔can无法通信怎么解决?

通过断电重启的方式会发现偶发性的can无法进行通信,通过加入调试信息后,发现无法启动的时候是因为驱动文件flexcan.c中的flexcan_chip_disable方法中写入mcr寄存器的第31bit后,读取mcr第20bit,如果读到对应的值,认为禁用成功,否则禁用失败,注册can失败。导致应用层无法使用can进行通信。而且can0注册失败后,can1也会因为同样的原因失败。
一般断电重启几十到几百次之间后会出现这种can无法通信的情况。
分析过程:
1.用2台设备搭建了一个can通信的测试环境,A设备和B设备通过can做数据通信,B设备会通过1个gpio控制的电源给A设备供电,A设备开机后会发送can数据给B设备,B设备收到can信号会拉gpio,让A设备重启。反复测试多次就会出现A无法给B发送数据,查看打印信息就会发现A的can驱动代码中读取mcr第20bit失败。
2.在1的环境下在读取mcr第20bit多次失败后,在代码中再次尝试写入一次mcr的第31bit后,继续读取多次还是失败。
3.单独一台A设备,把驱动程序编译成ko后,在进入根文件系统后,用一个shell命令来反复调用insmod和rmmod 先加载ko,然后卸载ko,如果insmod正常,后续循环5000多次都可以正常insmod。
在1的环境下,因为怀疑是can接的收发芯片问题,把A上的can1接的收发芯片吹下来了,用了A设备上的一个单片机的can与B设备通信,A设备上的单片机和imx6ul是通过spi连接,启动驱动是用的insmod,还是模拟1的环境测试,发现重启多次后还是会出现无法加载成功的情况.而且只要出现一次无法insmod成功,在不重启设备的情况下,不管后续insmod,rmmod多少次都无法正常insmod,也是会报错在读取mcr第20bit失败。

回帖(1)

王凯

2025-3-2 13:17:10

针对MCIMX6G2CVM05AB imx6ul启动时CAN偶发通信失败的问题,以下是逐步解决方案:


1. 增加超时和延迟


flexcan_chip_disable中延长等待时间,确保硬件有足够时间响应。


修改驱动代码(flexcan.c):


static void flexcan_chip_disable(struct flexcan_priv *priv)
{
    struct flexcan_regs __iomem *regs = priv->regs;
    u32 mcr;
    int timeout = 1000; // 将超时次数从默认值(如100)增加到1000

    mcr = flexcan_read(®s->mcr);
    mcr |= FLEXCAN_MCR_MDIS;
    flexcan_write(mcr, ®s->mcr);

    while (timeout-- > 0) {
        mcr = flexcan_read(®s->mcr);
        if (mcr & FLEXCAN_MCR_LPM_ACK)
            break;
        udelay(20); // 增加每次循环的延迟,如从10us调整到20us
    }

    if (timeout <= 0)
        dev_err(priv->dev, "FlexCAN: Disable timeout, MCR=0x%08xn", mcr);
    // 其他清理代码...
}

2. 添加内存屏障


确保寄存器写入操作完成后再读取状态。


在写入MCR后添加内存屏障:


mcr |= FLEXCAN_MCR_MDIS;
flexcan_write(mcr, ®s->mcr);
wmb(); // 插入写内存屏障,确保写入完成

3. 检查时钟配置


确认禁用期间时钟未被关闭。在设备树中检查CAN时钟配置,确保没有启用过早关闭时钟的电源管理策略。


设备树检查:


&can1 {
    clocks = <&clks IMX6UL_CLK_CAN1_IPG>,
             <&clks IMX6UL_CLK_CAN1_SERIAL>;
    clock-names = "ipg", "per";
    // 确保没有使用不合理的时钟门控配置
};

4. 强制复位模块


在初始化前执行硬件复位,确保模块状态正确。


在驱动初始化函数中添加复位:


static int flexcan_probe(struct platform_device *pdev)
{
    // ...其他初始化代码
    reset_control_assert(priv->rst); // 断言复位
    udelay(10);
    reset_control_deassert(priv->rst); // 释放复位
    // 继续初始化...
}

5. 查阅勘误表及更新驱动


检查i.MX6UL的芯片勘误表,确认是否存在FlexCAN问题。例如,NXP可能建议在禁用模块前执行特定操作。


参考勘误表建议:



  • 确保在进入MDIS模式前停止所有CAN传输。

  • 禁用中断并清空接收缓冲区。


6. 调试信息增强


在失败时记录更多寄存器状态,帮助定位问题。


添加调试输出:


if (timeout <= 0) {
    dev_err(priv->dev, "FlexCAN disable failed, MCR=0x%08x CTRL=0x%08xn",
            flexcan_read(®s->mcr), flexcan_read(®s->ctrl));
}

7. 电源和复位信号检查


使用示波器测量CAN控制器的电源和复位信号:



  • 电源纹波:确保在启动期间VDD_CAN稳定,无跌落。

  • 复位信号:检查复位引脚在启动时是否有毛刺或延迟。


8. 热复位 vs 冷复位测试


通过软件复位与断电重启对比,确定是否与电源周期相关:


echo 1 > /sys/class/remoteproc/remoteproc0/recovery # 触发软件复位(示例)

9. 驱动清理流程


确保在模块禁用时彻底释放资源,避免残留状态影响后续初始化:



  • 关闭所有CAN中断。

  • 清空接收/发送FIFO。

  • 释放DMA通道(如果使用)。


10. 更新驱动版本


检查NXP官方Linux内核的最新flexcan驱动版本,合并修复补丁。例如,某些版本可能已修复LPM_ACK检测问题。




总结:通过增加超时、优化时序、确保时钟稳定、强制复位和增强调试,可解决大部分偶发性禁用失败问题。若问题仍存,需结合硬件信号分析和芯片勘误表进一步排查。建议优先实施步骤1、2、4,并在失败时捕获寄存器状态以缩小问题范围。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分