完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
大家好,我是痞子衡,是正经搞威廉希尔官方网站
的痞子。今天痞子衡给大家介绍的是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。今天痞子衡就来跟大家探讨解决这个问题。 一、解决思路 我们知道无法启动问题是由于主芯片发生软复位但Flash仍处于Continuous read模式造成的,要解决这个问题无非如下三个角度,痞子衡会在后面具体实现方案里按这些角度全部搞一次(如果适用的话)。 二、核心切入点(借助Flash的硬复位引脚功能) 本文找的核心切入点是利用Flash的硬件复位引脚。Flash的硬件复位引脚有两种:一种是独立的,常见于SOIC-16封装上(这种情况下对板级设计有要求,需要在板级设计时将Flash复位引脚连到主芯片i.MXRT的GPIO上);另一种是复用在IO3上的,常用于SOIC-8封装上。 如果是独立的复位引脚(RESET#),则主芯片GPIO直接做拉低操作即可(注意低电平持续时间的要求,详见Flash数据手册);如果是复用的复位引脚(RESET#/IO3),则需要先激活IO3的复位功能,然后做拉低操作。 在IS25WP128数据手册里可以找到RESET#信号低电平至少需要持续1us: 三、具体实现 本章节描述的方法,如果是在App里(这里均指XIP App)完成,那么App里增加的相关处理代码(注意是执行到的全部代码)需要是 ramfunc 属性(即运行在内部RAM里),这样操作Flash时可以不受限制。此外代码运行前需要把全局中断关掉,防止执行过程中有中断触发,导致Flash里的相关IRQHandler函数被执行。 #if (defined(__ICCARM__))__ramfunc #endifvoid 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-EVKboardsevkmimxrt1170driver_examplesflexspinorpolling_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(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 GPIO_PinWrite(GPIO10, 20U, 0U); SDK_DelayAtLeastUs(10, SystemCoreClock); // Pin拉高 GPIO_PinWrite(GPIO10, 20U, 1U); } 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(); // 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模式在软复位后无法正常启动问题的解决经验痞子衡便介绍完毕了,掌声在哪里~~~ |
|
|
|
只有小组成员才能发言,加入小组>>
3318 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9063 浏览 16 评论
4088 浏览 18 评论
1182浏览 3评论
608浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
600浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 21:31 , Processed in 1.339740 second(s), Total 79, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号