zoukankan      html  css  js  c++  java
  • 痞子衡嵌入式:快速定位i.MXRT600板级设计ISP[2:0]启动模式引脚上电时序问题的方法


      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是一种快速定位i.MXRT600板级设计ISP[2-0]启动模式引脚上电时序问题的方法

      我们知道恩智浦i.MXRT600是主打音频市场的MCU产品,其也是i.MXRT三位数平台的第一款型号。这颗MCU已被众多知名国际大厂客户选用,在项目中作为协处理器负责音频相关子功能。不少客户都已经到了量产阶段,最近痞子衡在支持其中一个量产客户,客户遇到了同一批次某几个板卡无法正常启动的问题。痞子衡和同事一起排查,最终发现是ISP[2:0]启动引脚电平上电时序问题。这其实是个典型问题,痞子衡今天教你一招快速定位此类问题的方法:

    一、引出上电时序问题

      我们先来看看客户的问题,下面是客户板卡简图,i.MXRT600是负责音频功能的协处理器,它的启动引脚ISP[2:0]与主应用处理器(AP)连接了起来(客户项目设计里,AP并不负责控制i.MXRT600的启动模式),为了防止对i.MXRT600上电ISP引脚采样有影响,客户还特地在中间加了一层反向隔离电路。

    • 注:其实i.MXRT600支持Serial Boot模式,这种模式下i.MXRT600作为协处理器,其应用程序数据可直接由AP通过指定的UART/I2C/SPI/USB下载进i.MXRT600的内部RAM运行,能省去一颗外部Flash。

      客户量产过程中,同一批次几百块板卡,有一两块板卡上i.MXRT600无法启动。客户做了少量ABA实验:将无法启动板卡上的i.MXRT600芯片吹下来,换到能正常启动板卡上,依然无法启动。反过来,能正常启动板卡上的i.MXRT600芯片换到无法正常启动的板卡上,这块板卡就能正常启动了。

      从上面ABA实验来看,似乎不是板级设计问题,像是出问题的板卡上i.MXRT600芯片自身问题。痞子衡拿到一块出问题的板子,上电后测量了ISP[2:0]引脚电平,其值是3'b011 - FlexSPI Boot from Port A,上电稳定后ISP设置是没问题的,但刚上电时i.MXRT600 BootROM到底采样到的是什么ISP电平值没人知道。

      下面是客户板卡上ISP部分反向隔离设计,为了验证是ISP采样时机问题,我们特意对电路进行改造将RT600_BOOT0和RT600_BOOT2分别强行拉高和拉低,然后给板卡重新上电,终于板卡能正常启动了。

      所以我们可以得出初步结论,对于i.MXRT600从上电到BootROM进行ISP采样,这段时间不是一个严格固定值,因芯片制造差异,这个时间应该是在一定范围内,板级供电设计时上电时间应留有足够余量。客户这个项目里上电时间余量留得不足,导致无法满足个别i.MXRT600芯片ISP采样时间要求。

    二、BootROM中对于启动模式的处理

      在介绍快速定位ISP采样时机问题方法前,痞子衡先带大家了解下i.MXRT600 BootROM中关于启动模式的处理流程。

      咱们先回顾下痞子衡的旧文 《Boot配置(ISP_Pin/OTP)》,每次i.MXRT600芯片硬复位,OTP中的部分关于系统配置的值会被自动加载到OCOTP模块相应Shadow Register里(关于OCOTP外设基础知识可参考 《OTP及其烧写方法》),BootROM中主要用如下 get_runtime_boot_device_info() 函数来获取最终启动模式,并将其存在全局变量 s_bootDeviceInfo 中。

    • 注:代码中 OCOTP->OTP_SHADOW[0x60] 寄存器低四位即芯片参考手册里提及的 PRIMARY_BOOT_SRC[3:0]
    static boot_device_info_t s_bootDeviceInfo;
    
    void get_runtime_boot_device_info(void)
    {
        // 从OTP Shadow Register获取启动模式
        uint32_t bootSrc = OCOTP->OTP_SHADOW[0x60] & 0x0f;
        boot_device_info_t bootDeviceInfo = { 0 };
    
        if (bootSrc == 0) // Isp Pin
        {
            // 从ISP[2:0]引脚获取启动模式 
            bootSrc = get_bootpin_mode();
            // 对 bootDeviceInfo 成员进一步赋值
        }
        else
        {
            // 对 bootDeviceInfo 成员进一步赋值
        }
        s_bootDeviceInfo = bootDeviceInfo;
    }
    

      每一次i.MXRT600系统软复位去重新执行BootROM时,ISP[2:0]引脚状态都会被重新采样,这完全是软件采样。ROM中ISP采样功能函数如下面 get_bootpin_mode() 所示,代码中做了IO电平去抖处理:

    #define BOOT_PIN_DEBOUNCE_READ_COUNT 500
    
    uint32_t get_bootpin_mode(void)
    {
        uint32_t bootSrc = 0;
    
        // 使能GPIO外设
        CLOCK_EnableClock(kCLOCK_HsGpio1);
        RESET_PeripheralReset(kHSGPIO1_RST_SHIFT_RSTn);
    
        // 设置ISP引脚为GPIO模式,并使能上拉.
        IOPCTL->PIO[1][15] = IOPCTL_PIO_FSEL(0) | IOPCTL_PIO_PUPDENA(1) | IOPCTL_PIO_PUPDSEL(1) | IOPCTL_PIO_IBENA(1);
        IOPCTL->PIO[1][16] = IOPCTL_PIO_FSEL(0) | IOPCTL_PIO_PUPDENA(1) | IOPCTL_PIO_PUPDSEL(1) | IOPCTL_PIO_IBENA(1);
        IOPCTL->PIO[1][17] = IOPCTL_PIO_FSEL(0) | IOPCTL_PIO_PUPDENA(1) | IOPCTL_PIO_PUPDSEL(1) | IOPCTL_PIO_IBENA(1);
    
        // 配置ISP引脚GPIO属性为数字输入模式.
        GPIO->DIR[1] &= ~((1U << 15) | (1U << 16) | (1U << 17));
    
        // Note1: 管脚默认上拉是disable的,ROM需要使能管脚上拉.
        // Note2: 从使能管脚上拉到读取管脚值之间应间隔10us以上.
        sw_delay_us(10);
    
        // 采样ISP引脚值
        for (uint32_t pin = 17; pin >= 15; pin--)
        {
            uint32_t readCount = 0;
            for (uint32_t i = 0; i < BOOT_PIN_DEBOUNCE_READ_COUNT; i++)
            {
                readCount += GPIO->B[1][pin] & 0x1;
            }
            if (readCount >= BOOT_PIN_DEBOUNCE_READ_COUNT / 2)
            {
                bootSrc |= 0x1;
            }
            if (pin != 15)
            {
                bootSrc <<= 1;
            }
        }
    
        return bootSrc;
    }
    

      上面就是BootROM中关于启动模式的处理代码。那么有没有方法挂上调试器通过查后门方式直接读取到 s_bootDeviceInfo 变量值呢?很抱歉,不可以!即使痞子衡也做不到,虽然痞子衡能通过查BootROM map文件得知这个变量放在 0x10012d38 地址处。但是i.MXRT600 BootROM中集成了 《Debug Mailbox机制》,我们无法通过调试器读取正常运行后的ROM状态,这条路行不通。

    三、快速定位ISP[2:0]电平采样问题

      第一小节介绍的客户项目启动问题,其实还算比较好定位,因为有ABA实验在先,基本可以明确问题就出在ISP采样时机上。但更多时候,在客户项目研发阶段,没有ABA实验的条件,可能仅有一块板卡,并且Flash配置以及App里启动头是否正确都尚待验证。这种情况下,我们就需要一种快速甄别是否是ISP采样时机因素导致的启动问题。

      当芯片无法启动时,我们第一想法肯定是要得知第二小节介绍里 s_bootDeviceInfo 到底是什么值,这样我们就能反推ISP引脚到底在ROM里是什么采样值,但这条路行不通。换个角度想,我们能不能不让BootROM去采样ISP引脚,换一种替代方式来决定启动模式,如果这种情况下能按替代设置去启动,就也可以反证ISP引脚采样时机有问题。

      这种启动模式替代设置方法就是痞子衡今天要教大家的方法,利用调试器临时改写OCOTP->OTP_SHADOW[0x60]值(对的,我们可以不烧写OTP),改写完成后对芯片做一次软复位即可。OCOTP->OTP_SHADOW寄存器组仅芯片硬件复位或者执行OCOTP更新命令其值才会被重新加载,软复位不会影响其值。

    四、在MIMXRT685-EVK上做一次实验

      让我们在MIMXRT685-EVK上做一次实验,这块板卡上Flash连到了FlexSPI0 Port B上,我们随意下载一个SDK XIP工程,并将ISP引脚拨码设为3'b010 - FlexSPI Boot from Port B,复位后芯片能正常启动,工程运行正常。

      现在我们将ISP引脚拨码设为3'b110 - Serial ISP,软复位后芯片进入了ISP下载模式,不会从Flash启动。查芯片头文件得知 OCOTP->OTP_SHADOW[0x60] 寄存器地址是 0x50130180,我们现在尝试改写这个寄存器。

    /** OCOTP - Register Layout Typedef */
    typedef struct {
      __IO uint32_t OTP_SHADOW[496];                   /**< OTP shadow register N, array offset: 0x0, array step: 0x4 */
           uint8_t RESERVED_0[64];
      __IO uint32_t OTP_CTRL;                          /**< Control/address register, offset: 0x800 */
      // 省略...
    } OCOTP_Type;
    
    /** Peripheral OCOTP base address */
    #define OCOTP_BASE                               (0x50130000u)
    /** Peripheral OCOTP base address */
    #define OCOTP_BASE_NS                            (0x40130000u)
    /** Peripheral OCOTP base pointer */
    #define OCOTP                                    ((OCOTP_Type *)OCOTP_BASE)
    /** Peripheral OCOTP base pointer */
    #define OCOTP_NS                                 ((OCOTP_Type *)OCOTP_BASE_NS)
    

      挂上J-Link调试器,打开J-Link Commander,连接芯片,注意选择"MIMXRT685_M33",然后使用w4命令在0x50130180地址处写入0x00000005(在PRIMARY_BOOT_SRC[3:0]定义里,4'b0101是QSPI_B_BOOT)。

      继续执行reset和go命令(或者按一下板载软复位按钮RESET BUTTON SW3),这时候你可以看到芯片从Flash正常启动了,SDK XIP工程又运行起来了,显然这时候ISP引脚电平设置被忽略了,因此我们找到了有效的启动模式替代设置方法。

      最后有一点要注意,在使用J-Link软复位时,如果看到如下log,得检查下配套JLinkScript里的ResetTarget()函数具体功能,要确保内核真的被复位了。

      至此,快速定位i.MXRT600板级设计ISP[2-0]启动模式引脚上电时序问题的方法痞子衡便介绍完毕了,掌声在哪里~~~

    欢迎订阅

    文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

    微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

      最后欢迎关注痞子衡个人微信公众号【痞子衡嵌入式】,一个专注嵌入式技术的公众号,跟着痞子衡一起玩转嵌入式。

    痞子衡嵌入式-微信二维码 痞子衡嵌入式-微信收款二维码 痞子衡嵌入式-支付宝收款二维码

      衡杰(痞子衡),目前就职于恩智浦MCU系统部门,担任嵌入式系统应用工程师。

      专栏内所有文章的转载请注明出处:http://www.cnblogs.com/henjay724/

      与痞子衡进一步交流或咨询业务合作请发邮件至 hengjie1989@foxmail.com

      可以关注痞子衡的Github主页 https://github.com/JayHeng,有很多好玩的嵌入式项目。

      关于专栏文章有任何疑问请直接在博客下面留言,痞子衡会及时回复免费(划重点)答疑。

      痞子衡邮箱已被私信挤爆,技术问题不推荐私信,坚持私信请先扫码付款(5元起步)再发。


  • 相关阅读:
    不干就不需要知道,不需要知道就不想知道,不想知道就永远不知道,猪混几十年还是猪
    Visual Studio 2015编译安装配置QT5.5.1(含QTWEBKIT)
    IT生涯, 我的常用软件清单
    WIN10以后如果Manifest中不写支持WIN10的话,获取版本号的API获取的是6
    大促准备流程
    T4模板合并js
    maven/eclipse搭建ssm(spring+spring mvc+mybatis)
    如何理解分布式和区块链技术
    MaidSafe.net,一个完全去中心的化的云存储系统
    Akka.NET是Java/Scala 流行框架Akka的一个 .NET 开源移植
  • 原文地址:https://www.cnblogs.com/henjay724/p/14824056.html
Copyright © 2011-2022 走看看