痞子衡嵌入式:了解i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择


  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择

  关于 i.MXRT 系列 BootROM 中串行 NOR Flash 启动流程,痞子衡写过一篇非常详细的文章 《深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程》,这篇文章主要针对 i.MXRT1xxx 四位数系列,但基本上也适用 i.MXRTxxx 三位数系列,仅一些细节处有区别。

  在串行 NOR Flash 热启动过程中(非首次上电复位,而是单纯系统软复位 NVIC_SystemReset),有很多场景下均需要先复位一下 Flash ,将其恢复到默认的 Normal 模式,然后 Flash 才能被 BootROM 正常启动。这些场景包括 Flash 在上次系统运行时被配置到了某种特殊运行模式(QSPI 进入 Continuous Read 或者 QPI 模式,Octal Flash 进入 OPI 模式等),或者直接进到了低功耗模式(Deep Power Down)。

  本文就是介绍利用 BootROM 里集成的 Flash 硬复位功能来完成 Flash 复位操作。闲话少叙,进入正文:

  • 备注1:本文主要针对已量产的 i.MXRT500/600 。
  • 备注2:本文仅适用那些包含独立 RESET# 引脚的 Flash。

一、BootROM中实现

  在 《深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程》 一文的 2.1 节里,我们知道在 i.MXRT1xxx 四位数系列 BootROM 里同样集成了 Flash 硬复位功能,但是用于连接 Flash RESET# 引脚的 GPIO 是固定的(i.MXRT1050 上是GPIO1[9],i.MXRT1170 上是GPIO4[3] / GPIO2[8]),这对 PCB 设计有一定限制,如果被指定的 GPIO 在项目设计里有不可替代的功能,那只能放弃 BootROM 里这个 Flash 复位功能了。

  鉴于 i.MXRT1xxx 里 GPIO 指定不够灵活的缺陷,恩智浦 ROM 小组在 i.MXRTxxx 系列里做了改进,我们来看 i.MXRT600 的 fusemap 表,其中 BOOT_CFG[1] 里关于 QSPI_RESET_PIN 定义如下:

  我们看到了 3bit GPIO_PORT (0-7) 和 5bit GPIO_PIN_NUM (0-31) 设置,有了这个设置,用于连接 Flash RESET# 引脚 的 GPIO 选择就非常灵活了,基本可以涵盖所有 GPIO,因此项目 PCB 设计里只要随便找一个空闲的 GPIO 连到 Flash RESET# 引脚即可。

  该功能在 BootROM 里实现代码大概如下:

const clock_ip_name_t k_GpioClocks[8] = { kCLOCK_HsGpio0, kCLOCK_HsGpio1, kCLOCK_HsGpio2, kCLOCK_HsGpio3,
                                          kCLOCK_HsGpio4, kCLOCK_HsGpio5, kCLOCK_HsGpio6, kCLOCK_HsGpio7 };

const RSTCTL_RSTn_t k_GpioResets[8] = { kHSGPIO0_RST_SHIFT_RSTn, kHSGPIO1_RST_SHIFT_RSTn, kHSGPIO2_RST_SHIFT_RSTn, kHSGPIO3_RST_SHIFT_RSTn, 
                                        kHSGPIO4_RST_SHIFT_RSTn, kHSGPIO5_RST_SHIFT_RSTn, kHSGPIO6_RST_SHIFT_RSTn, kHSGPIO7_RST_SHIFT_RSTn};

if (OCOTP->OTP_SHADOW[0x61] & 0x400)
{
    // Initialize Reset Pin
    uint32_t portInstance = (OCOTP->OTP_SHADOW[0x61] & 0x3800) >> 15;
    uint32_t gpioInstance = (OCOTP->OTP_SHADOW[0x61] & 0x7c000) >> 18;

    // Enable Clock before accessing registers
    CLOCK_EnableClock(k_GpioClocks[portInstance]);
    RESET_PeripheralReset(k_GpioResets[portInstance]);

    // Configure the port to GPIO mode with pull-up resistor enabled.
    IOPCTL->PIO[portInstance][gpioInstance] = IOPCTL_PIO_FSEL(0) | IOPCTL_PIO_PUPDENA(1) | IOPCTL_PIO_PUPDSEL(1) | IOPCTL_PIO_FULLDRIVE(1);
    GPIO->DIRSET[portInstance] = (1u << gpioInstance);

    // High
    GPIO->SET[portInstance] = (1u << gpioInstance);
    flexspi_sw_delay_us(250);
    // Low
    GPIO->CLR[portInstance] = (1u << gpioInstance);
    flexspi_sw_delay_us(250);
    // High
    GPIO->SET[portInstance] = (1u << gpioInstance);
    flexspi_sw_delay_us(500);
}

二、在MIMXRT685-EVK上实践

  我们现在在官方 MIMXRT685-EVK 上实测一下这个功能,EVK 上选用的 Flash 型号是旺宏的 MX25UM51345G,这颗 Flash 有独立的 RESET# 引脚(A4),它被连到了主芯片的 PIO2_12 脚上。

  要想激活 BootROM 中 Flash 硬复位功能需要烧写 eFuse(也可以写相应 OCOTP Shadow Register 来替代,Shadow Register 只在上电或者触发 OCOTP refresh 命令时从 eFuse 中加载一次值,其后即使软复位 Shadow Register 值也不丢失),我们暂且用写 Shadow Register 方式来测试。

  正好前段时间痞子衡在做 SBL 项目写了篇文章 《在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器》,里面就有系统软复位需求,在支持 i.MXRT600 时就遇到了问题,因为第一次启动后 MIMXRT685-EVK 上的这颗 Octal Flash 被配置到了 OPI 模式,需要复位后才能再次被 BootROM 正常启动,所以我们直接就用上了 BootROM 里的 Flash 硬复位功能,代码很简单:

void isp_cleanup_enter(uint32_t flag)
{
    CLOCK_EnableClock(kCLOCK_Rtc);
    RTC->CTRL &= ~RTC_CTRL_SWRESET_MASK;
    RTC->GPREG[0] = flag;

    // Reset Flash to normal mode by BootROM
    // QSPI_RESET_PIN_ENABLE = 1'b1, GPIO_PORT = 3'b010, GPIO_PIN_NUM = 5'b01100
    OCOTP->OTP_SHADOW[0x61] = 0x314000;
    __DSB();

    NVIC_SystemReset();
}

  至此,i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

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

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

posted @ 2021-07-21 22:38  痞子衡  阅读(781)  评论(0编辑  收藏  举报