痞子衡嵌入式:16MB以上NOR Flash使用不当可能会造成软复位后i.MXRT无法正常启动
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是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和软复位的区别;二、软复位无法启动是概率性的,因此痞子衡想到了如下四处疑点:
- 两种复位下主芯片内部非易失寄存器状态的区别是否对BootROM运行产生了影响?
- 两种复位下主芯片内FlexSPI这个模块状态是否有区别?
- 两种复位下外挂Flash芯片状态是否有区别?
- 客户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无法正常启动的更多相关文章
- 痞子衡嵌入式:实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(无缓存)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形. 上一篇文章 <i.MXRT中FlexSPI外设对A ...
- 痞子衡嵌入式:串行NOR Flash的Continuous read模式下软复位后i.MXRT无法启动问题解决方案之RESET#
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT上使能NOR Flash的Continuous read模式在软复位后无法正常启动问题的解决经验. 前一篇文章 <在i ...
- 痞子衡嵌入式:MCUBootUtility v3.5发布,支持串行NOR的ECC及双程序启动
-- 痞子衡维护的 NXP-MCUBootUtility 工具距离上一个大版本(v3.4.0)发布过去半年了,这一次痞子衡为大家带来了版本升级 v3.5.0,这个版本主要有几个非常重要的更新需要跟大家 ...
- 痞子衡嵌入式:深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程. 从外部串行NOR Flash启动问题是i.MXRT系列开发最 ...
- 痞子衡嵌入式:深扒i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合. 在串行 NOR Flash 热启动过程 ...
- 痞子衡嵌入式:其实i.MXRT下改造FlexSPI driver同样支持AHB方式去写入NOR Flash
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT下改造FlexSPI driver以AHB方式去写入NOR Flash. 痞子衡前段时间写过一篇 <串行NAND Fl ...
- 痞子衡嵌入式:借助Serial Plot软件测量i.MXRT系列FlexSPI驱动Flash页编程执行时间
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT系列FlexSPI驱动Flash页编程执行时间. 痞子衡之前写过一篇文章 <串行NOR Flash的页编程模式对于量产 ...
- 痞子衡嵌入式:揭秘i.MXRT1170上串行NOR Flash双程序可交替启动设计
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上串行NOR Flash双程序可交替启动设计. 在上一篇文章 <i.MXRT1060/1010上串行NOR F ...
- 痞子衡嵌入式:RT-MFB - 一种灵活的i.MXRT下多串行NOR Flash型号选择的量产方案
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是一种灵活的i.MXRT下多串行NOR Flash型号选择的量产方案. 对于以 i.MXRT 这类没有内部 NVM (Non-Volati ...
随机推荐
- tap4fun(成都尼必鲁)--2020春招实习
笔试 可能是我做过最简单的笔试了,只有选择填空,而且难度都不是很大,没啥印象了,考点和其他公司的笔试都差不多. 一面(技术面) 具体的不太记得了,因为这是我很后面面的了,所以问题基本都是那几个问题,都 ...
- linux主机连接sftp报错received unexpected end-of-file from SFTP server
SFTP 连接主机失败,提示信息如下: 登陆目标主机,编辑查看 /etc/ssh/sshd_config 文件,找到 Subsystem 关键字 替换为 Subsystem sftp internal ...
- vue基础入门(1)
1.vue初体验 1.1.vue简介 1.1.1.vue是什么? Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架,什么叫做渐进式呢?通俗的讲就是一层一层的,一步一 ...
- RabbitMQ(dotnet基本使用
前言 RabbitMQ环境环境搭建及基本配置,在此不讨论.网上一大堆. NET环境下,Rabbit库可以在官网或NUGET上查找得到. 生产者 static void Main(string[] ar ...
- 小白入门NAS—快速搭建私有云教程系列(一)
什么是NAS 在日常的工作生活中,我们有大量的资料.文件需要存储在电脑或者其他终端设备中,但是这种方式需要电脑配备高容量的硬盘,而且需要随时随地的带着,这样是不是很麻烦? 那么,今天,我来介绍一种家庭 ...
- springsecurity简单学习
一.初识SpringSecurity 在springboot项目中加入spring security. 1.在pom.xml中加入依赖 <dependency> <groupId&g ...
- UVA 11383 Golden Tiger Claw 题解
题目 --> 题解 其实就是一个KM的板子 KM算法在进行中, 需要满足两个点的顶标值之和大于等于两点之间的边权, 所以进行一次KM即可. KM之后, 顶标之和就是最小的.因为如果不是最小的,就 ...
- 单调栈之WYT的刷子
好久没更题解了(改题困难的我) 题目描述 WYT有一把巨大的刷子,刷子的宽度为M米,现在WYT要使用这把大刷子去粉刷有N列的栅栏(每列宽度都为1米:每列的高度单位也为米,由输入数据给出). 使用刷子的 ...
- 洛谷 P2114 [NOI2014]起床困难综合症 位运算
题目描述 21世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm一直坚持与起床困难综合症作斗争.通过研究相关文献,他找到了该病的发病原因 ...
- 测试必备工具之抓包神器 Charles 如何抓取 https 数据包?
之前发过一篇文章讲解了Charles抓包工具的基本使用(有需要的小伙伴可以去看上一篇文章), 讲的数据包主要是http协议,大家可以看到数据包并直接显示具体详细的内容: 但是如果抓到的是https的 ...