zoukankan      html  css  js  c++  java
  • 痞子衡嵌入式:串行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元起步)再发。


  • 相关阅读:
    Java Native Method
    SQL语句优化
    Ibatis的环境搭建以及遇到的问题解决
    Java 构建器
    SpringMVC自定义视图 Excel视图和PDF视图
    java 枚举的常见使用方法
    mysql 根据某些字段之和排序
    MFC The Screen Flickers When The Image Zoomed
    How To Debug Qmake Pro File
    Gcc And MakeFile Level1
  • 原文地址:https://www.cnblogs.com/henjay724/p/14811509.html
Copyright © 2011-2022 走看看