大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是i.MXRT上使用16MB以上NOR Flash软复位无法正常启动问题的分析解决经验

  痞子衡这几天在支持一个i.MXRT1050客户项目,客户遇到了软复位无法从32MB NOR Flash重新启动的问题。这个客户是做医疗设备的,已经基于i.MXRT做出一款成功的产品了,所以客户其实有丰富的i.MXRT使用经验。目前调试的项目是客户的第二款产品,这个软复位无法启动问题已经困扰他们很久,但问题毕竟不是特别紧急,不影响他们开发进度,所以耽搁至今。这次客户趁着出差苏州参加劳特巴赫TRACE32调试器培训机会,让痞子衡现场帮他们定位问题,经过一番调试和分析,痞子衡终于成功地解决了问题,特此将问题解决的全过程记录下来,供大家参考。

一、问题描述

  在描述问题前,首先给大家介绍下客户的项目设计,底下是客户硬件简图。客户选用的i.MXRT1052作为主控,挂载了两个QSPI Flash,FlexSPI接口连接的32MB Flash用于启动和存放静态图片资源(只需要读即可),LPSPI接口连接的1MB Flash用于存放运行时状态数据(需要读写),此外板子连接了一个显示屏,所以还挂载一片SDRAM用于显示缓存,其实SDRAM除了显示缓存功能之外,还用于执行App(QSPI Flash里的App会自加载到SDRAM执行)。

  有必要重点介绍下QSPI Flash启动设计细节,客户选用的Flash型号是ISSI的IS25WP256D,这是一款容量256Mb的四线串行Flash。客户启动流程设计的挺复杂,芯片上电之后,BootROM负责从Flash中XIP启动L2 loader程序,L2 loader运行后从Flash中选出最新的一份Boot程序(A/B是双备份),将其加载到SDRAM中执行。Boot程序运行后做一些系统初始化工作,然后直接跳转到App中执行(XIP),App才是最终的客户应用程序,这个应用程序会完成往SDRAM的自拷贝以及跳转执行。

  客户的App实际大小接近5MB,对于嵌入式程序来说,这个体量相当大了,这也是为什么客户需要借助专业的劳特巴赫TRACE32调试器来分析定位程序逻辑设计问题。从下图还可以看到从0x60800000开始,Flash中还存放了一些静态图片资源,客户项目有显示屏,Flash里放一些固定图片数据方便UI切换。

  介绍完客户的项目设计,现在描述客户的软复位无法重新启动问题。其实这个问题现象很简单,就是每次重新上电启动,程序都是可以正常运行的,但是一旦使用按键软复位(ONOFF Reset),系统就会有一定概率起不来(概率很大,很容易复现),调试器连上去会发现PC停留在BootROM里,这意味着此时BootROM没能正常启动L2 loader。

二、问题分析

  让我们来分析一下问题,这个问题要从两方面来考虑:一、板子上芯片的POR和软复位的区别;二、软复位无法启动是概率性的,因此痞子衡想到了如下四处疑点:

  1. 两种复位下主芯片内部非易失寄存器状态的区别是否对BootROM运行产生了影响?
  2. 两种复位下主芯片内FlexSPI这个模块状态是否有区别?
  3. 两种复位下外挂Flash芯片状态是否有区别?
  4. 客户App代码里是否有某种操作导致了概率性问题的发生?

  因为每次都是软复位重新启动出问题,所以客户板级供电设计不在疑点范围内。虽然问题都表现在BootROM没法加载L2 loader执行,但BootROM本身缺陷也不是我们主要考虑的方向,毕竟BootROM是固化在芯片内部的,可靠性有一定保证。我们首先要把疑点放在概率性以及两种复位的差异上,那么我们从哪里开始着手测试?

  痞子衡想的是先从第4个疑点开始下手,原因是前3个疑点本质上都由第4个疑点引起的,客户代码的执行可能会改主芯片内部非易失性寄存器,也同时会操作FlexSPI模块去访问外部Flash,它是问题的引爆点。

三、开始测试

3.1 对比非易失性寄存器

  i.MXRT内部有一些非易失性寄存器(比如IOMUXC_GPR寄存器组,SRC寄存器等),这些寄存器仅在POR时才会被复位,而普通软复位是不会改变其状态的。客户App代码近5MB,如果是去肉眼排查是否操作了非易失性寄存器,难免有疏漏。最简单的方法就是在正常启动和非正常启动时分别用调试器将这些寄存器的值全部保存下来,然后使用文本工具去对比。经测试,两种情况下,这些非易失性寄存器并无区别,因此这个疑点被排除。

3.2 逐步精简App代码

  现在我们开始逐步精简App代码,由于客户代码涉及机密,所以精简的工作由客户来做,当然客户也最清楚如何去精简他们自己的代码。一番测试下来,我们发现App代码里只要不去读存在Flash里的静态图片数据,就不会存在软复位无法重新启动问题,看起来我们已经找到线索了。

四、原因分析

  问题出在App代码里读存在Flash里的静态图片数据,这意味着App里可能用了特殊的读Flash方法改变了Flash状态,并且这个Flash状态是非易失性的。谜团接近解开了,痞子衡让客户公布了他们的L2 loader里的FDCB配置头以及App里的读Flash图片的代码实现:

4.1 L2 loader的FDCB

  先来看客户的FDCB启动头,客户仅让BootROM配置Flash工作于50MHz,并且是1bit SDR Fast Read(命令是0x0B),这是标准3字节地址读,因此配置成功后通过AHB总线最大可访问16MB以内的Flash空间。因为客户的L2 loader很小,且存储在Flash的起始地址,所以这样的配置对于启动而言没有问题。

4.2 App读Flash实现

  再来看客户实现的读Flash函数BigCapRead(),根据前面的介绍,静态图片数据是从0x60800000处开始存储的,因此0x60800000 - 0x60FFFFFF范围内的8MB数据是可以直接AHB读,但是0x61000000地址之后的数据在上述BootROM的配置下无法直接访问,这也是为什么客户写了BigCapRead()函数,这个函数会根据传入的地址范围来判断数据是在低16MB空间还是高16MB空间,然后对地址空间做了一个切换。

#define FLASH_BIG_CAP_SIZE (0x1000000)

static status_t flexspi_nor_select_segment(uint32_t base, uint8_t seg)
{
qspi_transfer_t flashXfer;
status_t status = Success;
uint32_t writeValue = 0x00;
uint32_t readValue = 0x00; flexspi_nor_write_enable(base, 0, true); flexspi_nor_read_volatilebankaddr_reg(base, &readValue);
if ((readValue & 0x01) == (seg & 0x1))
{
return Success;
} writeValue = seg & 0x1;
flexspi_nor_write_volatilebankaddr_reg(base, writeValue); flexspi_nor_read_volatilebankaddr_reg(base, &readValue);
if (readValue != writeValue)
{
return Failure;
} flexspi_nor_wait_bus_busy(base);
return Success;
} static UINT32 BigCapRead(struct flash_dev* dev, UINT32 start_addr, UCHAR *buffer, UINT32 size)
{
UINT32 tempLen = 0;
UINT32 result = 0;
if (start_addr >= FLASH_BIG_CAP_SIZE)
{
flexspi_nor_select_segment(dev->base, 1);
start_addr = start_addr - FLASH_BIG_CAP_SIZE;
result = Read(dev, start_addr, buffer, size);
}
else
{
if (start_addr + size < FLASH_BIG_CAP_SIZE)
{
flexspi_nor_select_segment(dev->base, 0);
result = Read(dev, start_addr, buffer, size);
}
else
{
tempLen = FLASH_BIG_CAP_SIZE - start_addr;
flexspi_nor_select_segment(dev->base, 0);
result = Read(dev, start_addr, buffer, tempLen);
flexspi_nor_select_segment(dev->base, 1);
result = Read(dev, 0, buffer + tempLen, size - tempLen);
}
}
return result;
}

4.3 关于Flash的3/4字节地址

  对于16MB以上空间的Flash,总会面临3/4字节地址访问的问题,JESD216规定了3/4字节地址访问标准命令,对于3字节地址Fast Read,其命令是FRD(0x0B);而对于四字节地址Fast Read,其命令是4FRD(0x0C)。对于一个32MB的Flash,如果仅需要访问低16MB空间,可以使用FRD;如果需要访问高16MB空间,则需要使用4FRD。

  4FRD相比FRD多传输了一字节地址,对于地址连续的大块数据访问,这个1字节地址影响不太,但是如果是执行代码或者非连续数据访问,4FRD相比FRD还是有效率上的降低的,对于这个问题,不同的厂家提供了不同的解决方案。

  客户选用的这款Flash来自ISSI,ISSI的解决方案是在Flash内部增加一个Bank Address Register,其bit0用于实时切换低Bank和高Bank(并且这个位是非易失性的,仅POR才会复位,引脚reset无法复位!),当bit0值为0时,FRD命令访问的是低16MB空间,而bit0置1后,FRD命令此时实际访问的是高16MB空间(从AHB地址上看不出这个变化)。

4.4 解决方案

  看到这,这个软复位无法重启问题真相大白了,是由于这颗Flash里的内部非易失寄存器BAR[0]的操作导致的,如果软复位时间点恰好在App读了高16MB空间(Bank1)里的数据之后,此时Bank发生了切换,软复位后BootROM去启动时无法读到存在低16MB空间(Bank0)的有效的L2 loader。如果软复位时间点发生在App正在读低16MB空间的数据,那下次还是可以正常启动,这就是概率性启动失败的原因。

  原因调查清楚了,问题解决方法就很简单了,将L2 loader里的FDCB头用4FRD代替FRD,这样BootROM配置完成之后,可以直接AHB读全部的32MB空间,不需要切换Bank,因此App里的BigCapRead()函数里的Bank切换操作可以删掉。

  这个经验也告诉了我们,当使用16MB以上Flash作为启动设备时,一定要小心处理好3/4字节地址访问问题,不然就可能出现启动问题。

  至此,i.MXRT上使用16MB以上NOR Flash软复位无法正常启动问题的分析解决经验痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

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

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

痞子衡嵌入式:16MB以上NOR Flash使用不当可能会造成软复位后i.MXRT无法正常启动的更多相关文章

  1. 痞子衡嵌入式:实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(无缓存)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形. 上一篇文章 <i.MXRT中FlexSPI外设对A ...

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

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

  3. 痞子衡嵌入式:MCUBootUtility v3.5发布,支持串行NOR的ECC及双程序启动

    -- 痞子衡维护的 NXP-MCUBootUtility 工具距离上一个大版本(v3.4.0)发布过去半年了,这一次痞子衡为大家带来了版本升级 v3.5.0,这个版本主要有几个非常重要的更新需要跟大家 ...

  4. 痞子衡嵌入式:深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程. 从外部串行NOR Flash启动问题是i.MXRT系列开发最 ...

  5. 痞子衡嵌入式:深扒i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合. 在串行 NOR Flash 热启动过程 ...

  6. 痞子衡嵌入式:其实i.MXRT下改造FlexSPI driver同样支持AHB方式去写入NOR Flash

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT下改造FlexSPI driver以AHB方式去写入NOR Flash. 痞子衡前段时间写过一篇 <串行NAND Fl ...

  7. 痞子衡嵌入式:借助Serial Plot软件测量i.MXRT系列FlexSPI驱动Flash页编程执行时间

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT系列FlexSPI驱动Flash页编程执行时间. 痞子衡之前写过一篇文章 <串行NOR Flash的页编程模式对于量产 ...

  8. 痞子衡嵌入式:揭秘i.MXRT1170上串行NOR Flash双程序可交替启动设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上串行NOR Flash双程序可交替启动设计. 在上一篇文章 <i.MXRT1060/1010上串行NOR F ...

  9. 痞子衡嵌入式:RT-MFB - 一种灵活的i.MXRT下多串行NOR Flash型号选择的量产方案

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是一种灵活的i.MXRT下多串行NOR Flash型号选择的量产方案. 对于以 i.MXRT 这类没有内部 NVM (Non-Volati ...

随机推荐

  1. 暑假集训Day 4 P4163 [SCOI2007]排列 (状压dp)

    状压dp (看到s的长度不超过10就很容易想到是状压dp了 但是这个题的状态转移方程比较特殊) 题目大意 给一个数字串 s 和正整数 d, 统计 s 有多少种不同的排列能被 d 整除(可以有前导 0) ...

  2. Web安全之验证码绕过

    一,验证码绕过(on client) 首先让burpsuite处于抓包状态,打开pikachu的验证码绕过(on client)随意输入账号和密码,验证码先不输入,点击login,会提示验证码错误 然 ...

  3. vue基础入门(4)

    4.综合实例 4.1.基于数据驱动的选项卡 4.1.1.需求 需求说明: 1. 被选中的选项按钮颜色成橙色 2. 完成被选中选项下的数据列表渲染 3. 完成选项切换 4.1.2.代码实现 <!D ...

  4. eclipse在debug模式下鼠标移动到变量上不显示值的问题

    在eclipse中调试时,鼠标移动到变量上不显示值,使用ctrl+shift+i,或者通过配置达到目的: Window->Preferences->Java->Editor-> ...

  5. Java 从入门到进阶之路(二十六)

    在之前的文章我们介绍了一下 Java 中的  集合框架中的Collection 的子接口 List,本章我们来看一下 Java 集合框架中的Collection 的子接口 Queue. 在之前我们讲 ...

  6. 前端分页(js)

    //前端分页 var limit = 10; //每页显示数据条数 var total = $('#host_table').find('tr').length; var allPage = tota ...

  7. HDU 5969 最大的位或 题解

    题目 B君和G君聊天的时候想到了如下的问题. 给定自然数l和r ,选取2个整数\(x,y\)满足\(l <= x <= y <= r\),使得\(x|y\)最大. 其中\(|\)表示 ...

  8. React学习路径快速进入AntDesignPro开发

    好久没有写博客,有空再来记一下.最近在整些小东西,需要用到前端,最开始本着对nodejs的动不动几百兆插件的恐惧, 于是使用自己以前写的 OSS.Pjax 小框架(类似国外的Pjax,利用pushSt ...

  9. JVM(完成度95%,不断更新)

    一.HotSpot HotSpot是最新的虚拟机,替代了JIT,提高Java的运行性能.Java原先是将源代码编译为字节码在虚拟机运行,HotSpot将常用的部分代码编译为本地代码. 对象创建过程 类 ...

  10. HTML5提高

    HTML5提高 前言 我个人觉得,当你学会了一些最基本的标签其实是够用的,但是在很多网页中可以发现很多新的标签.这个时候不知道它是干嘛的实际上心里是非常没底的,所以在这里我打算写一篇HTML5提高的文 ...