• 痞子衡嵌入式:串行NOR Flash的Continuous read模式下软复位后i.MXRT无法启动问题解决方案之RESET#



      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT上使能NOR Flash的Continuous read模式在软复位后无法正常启动问题的解决经验

      前一篇文章 《在i.MXRT启动头FDCB里使能串行NOR Flash的Continuous read模式》 里,痞子衡简单介绍了Flash的Continuous read模式作用与意义,并且在MIMXRT1170-EVK上尝试使能了芯成IS25WP128的Continuous read模式做了一次实践(主要是文中第三节FDCB启动头的改动)。

      但其实在i.MXRT上使能Flash的Continuous read模式是有点小陷阱的,如果你在App代码里直接插一句 NVIC_SystemReset() 函数的调用,即对主控芯片做一次软复位,你会发现芯片没有从Flash正常启动,这是因为Flash此时仍处于Continuous read模式,这种情况下BootROM有时不能正常配置读取Flash内容去启动App。今天痞子衡就来跟大家探讨解决这个问题。

    • 本系列会有多篇文章,每篇文章均从一个核心切入点出发,给出一系列具体实现方案。
    • 本系列均以MIMXRT1170-EVK板为示例目标对象,板载Flash型号为芯成IS25WP128(其他i.MXRT芯片和Flash型号下实现流程也差不多,需查看对应数据手册)。

    一、解决思路

      我们知道无法启动问题是由于主芯片发生软复位但Flash仍处于Continuous read模式造成的,要解决这个问题无非如下三个角度,痞子衡会在后面具体实现方案里按这些角度全部搞一次(如果适用的话)。

    • 一、ROM方面不做任何相关处理,但App在调用NVIC_SystemReset()做复位前将Flash先切回到Normal模式;
    • 二、App方面不做任何相关处理,对BootROM相关配置做一些调整,让BootROM也能正常处理处于Continuous read模式的Flash;
    • 三、ROM和App联合对Flash模式切换做一些特殊处理。

    二、核心切入点(借助Flash的硬复位引脚功能)

      本文找的核心切入点是利用Flash的硬件复位引脚。Flash的硬件复位引脚有两种:一种是独立的,常见于SOIC-16封装上(这种情况下对板级设计有要求,需要在板级设计时将Flash复位引脚连到主芯片i.MXRT的GPIO上);另一种是复用在IO3上的,常用于SOIC-8封装上。

      如果是独立的复位引脚(RESET#),则主芯片GPIO直接做拉低操作即可(注意低电平持续时间的要求,详见Flash数据手册);如果是复用的复位引脚(RESET#/IO3),则需要先激活IO3的复位功能,然后做拉低操作。

      在IS25WP128数据手册里可以找到RESET#信号低电平至少需要持续1us(下表tRESET,如果RESET#低电平持续时间小于1us,也许不会影响Flash器件的复位,但不推荐),Flash进入复位后需要最大100us的恢复时间(下表tHWRST),在恢复期间内对Flash进行读写擦操作并不会生效,因此复位函数里(下文3.2节里的reset_flash_via_pin)最好保证足够的等待时间(这样后续代码里的Flash操作可靠性就得到了保证)。

    三、具体实现

      本章节描述的方法,如果是在App里(这里均指XIP App)完成,那么App里增加的相关处理代码(注意是执行到的全部代码)需要是 ramfunc 属性(即运行在内部RAM里),这样操作Flash时可以不受限制。此外代码运行前需要把全局中断关掉,防止执行过程中有中断触发,导致Flash里的相关IRQHandler函数被执行。

    #if (defined(__ICCARM__))
    __ramfunc 
    #endif
    void reset_flash_to_normal(void)
    {
        __disable_irq();
    
        // 处理代码,使Flash返回到Normal模式
    
        NVIC_SystemReset();
    }
    

    3.1 仅ROM方面做相关处理

      我们先仅从ROM单方面角度来解决问题,可以先看下痞子衡之前的旧文 《深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程》 里的2.1节。i.MXRT全系列ROM里关于串行NOR Flash启动流程大同小异。

      如果要利用ROM里集成的Flash硬件复位功能,则Flash本身必须包含独立的硬件RESET#引脚。本系列示例主芯片i.MXRT1170的fusemap表里关于RESET_PIN的相关定义如下,那么板级设计时Flash RESET#引脚应该连接到GPIO4[3]或者GPIO2[8](根据fuse 0xC80[5]位而定),并且我们还要将fuse 0xC80[7]位烧写为1。

    3.2 仅App方面做相关处理

      上一小节里的方法先决条件是Flash要包含独立RESET#引脚,但实际客户项目中SOIC-8封装的Flash选择更多。所以我们更多应该在复用的RESET#/IO3引脚上做文章,这就要从App方面的角度来解决问题了。

      我们先从IS25WP128数据手册看看RESET#/IO3引脚详细功能解释,主要如下两点:

    1. IO3引脚仅当QE模式不使能(Flash内部Status Register[6] = 0)的时候,其功能才是HOLD#/RESET#
    2. IO3引脚复用功能HOLD#/RESET#由Flash内部Read Register[7]位决定,默认值为0,是HOLD#功能
    

      所以 reset_flash_to_normal() 函数里我们需要先设Status Register将Flash切到QE不使能的状态(i.MXRT启动运行App时,Flash应处于QE使能的状态),然后再设Read Register将IO3复位功能指定为RESET#,然后拉低IO3对应的GPIO直到满足复位最小时间要求,最后再将之前改写的Status Register/Read Register全部恢复。过程中主要涉及如下命令:

      代码可以基于 SDK_2.9.1_MIMXRT1170-EVKoardsevkmimxrt1170driver_examplesflexspi orpolling_transfercm7下面的 flexspi_nor_polling_transfer.c 和 flexspi_nor_flash_ops.c,并新增如下代码:

    #define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 9
    #define NOR_CMD_LUT_SEQ_IDX_SETREADPARAM   14
    
    const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
        // ...
    
        /* 原来 Write Status Register */
        [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x01, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
    
        // 新增 Set read parameter
        [4 * NOR_CMD_LUT_SEQ_IDX_SETREADPARAM] = 
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x63, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
    };
    
    status_t flexspi_nor_set_flash_register(FLEXSPI_Type *base, uint32_t seqIdx, uint32_t regValue)
    {
        flexspi_transfer_t flashXfer;
        status_t status;
        uint32_t writeValue = regValue;
    
        /* Write enable */
        status = flexspi_nor_write_enable(base, 0);
        if (status != kStatus_Success)
        {
            return status;
        }
    
        flashXfer.deviceAddress = 0;
        flashXfer.port          = kFLEXSPI_PortA1;
        flashXfer.cmdType       = kFLEXSPI_Write;
        flashXfer.SeqNumber     = 1;
        flashXfer.seqIndex      = seqIdx;
        flashXfer.data          = &writeValue;
        flashXfer.dataSize      = 1;
    
        status = FLEXSPI_TransferBlocking(base, &flashXfer);
        if (status != kStatus_Success)
        {
            return status;
        }
    
        status = flexspi_nor_wait_bus_busy(base);
    
        /* Do software reset. */
        FLEXSPI_SoftwareReset(base);
    
        return status;
    }
    
    // MIMXRT1170-EVK上GPIO10[20]引脚连到了Flash的IO3上
    void reset_flash_via_pin(void)
    {
        gpio_pin_config_t gpio_config = {
            .direction = kGPIO_DigitalOutput,
            .outputLogic = 0U,
            .interruptMode = kGPIO_NoIntmode
        };
        GPIO_PinInit(GPIO10, 20U, &gpio_config);
        IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_11_GPIO10_IO20, 0U);
      
        // Pin拉高
        GPIO_PinWrite(GPIO10, 20U, 1U);
        SDK_DelayAtLeastUs(10, SystemCoreClock);
    
        // Pin拉低10us(需持续至少tRESET = 1us时间)
        GPIO_PinWrite(GPIO10, 20U, 0U);
        SDK_DelayAtLeastUs(10, SystemCoreClock);
    
        // Pin拉高(需持续最大tHWRST = 100us时间)
        GPIO_PinWrite(GPIO10, 20U, 1U);
        SDK_DelayAtLeastUs(100, SystemCoreClock);
    }
    
    void reset_flash_to_normal(void)
    {
        __disable_irq();
    
        flexspi_nor_flash_init(EXAMPLE_FLEXSPI);
    
        // Disable quad mode.
        flexspi_nor_set_flash_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG, 0x00);
        // Set IO3 pin to Reset func
        flexspi_nor_set_flash_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_SETREADPARAM, 0x80);
        
        // Drive IO3 to low for at least 1us
        reset_flash_via_pin();
     
        // Set back IO3 pin func
        flexspi_nor_set_flash_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_SETREADPARAM, 0x00);
        // Enter quad mode.
        flexspi_nor_set_flash_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG, 0x40);
        
        NVIC_SystemReset();
    }
    

      为了保证上述代码均执行在RAM里,工程链接文件里(以IAR示例)需做如下改动:

    initialize by copy { readwrite, 
                         section .textrw, 
                         object fsl_common.o,
                         object I64DivZer.o,
                         object I64DivMod.o,
                         object fsl_gpio.o,
                         object fsl_flexspi.o,
                         object flexspi_nor_flash_ops.o,
                         object flexspi_nor_polling_transfer.o,
                         section CodeQuickAccess };
    

    3.3 ROM和App联合处理

      关于ROM和App联合处理角度,在复位引脚这个切入点上并没有什么优势,此处略去。

      至此,i.MXRT上使能NOR Flash的Continuous read模式在软复位后无法正常启动问题的解决经验痞子衡便介绍完毕了,掌声在哪里~~~

    欢迎订阅

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

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

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

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

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

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

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

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

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

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


  • 相关阅读:
    schema约束和引入
    第一天
    github pages搭建网站(三)
    git安装和使用(二)
    使用github(一)
    命名实体识别总结
    约瑟夫环
    标准化和归一化
    cumsum累计函数系列:pd.cumsum()、pd.cumprod()、pd.cummax()、pd.cummin()
    pandas处理时间序列(4): 移动窗口函数
  • 原文地址:https://www.cnblogs.com/henjay724/p/14811509.html
Copyright © 2020-2023  润新知