大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是串行NAND Flash的两大特性导致其在i.MXRT FlexSPI下无法XiP。
在嵌入式世界里,当我们提起XiP设备(支持代码原地执行的存储器),首先想到的应该是NOR Flash。比如中低端MCU内部通常会集成小容量并行NOR Flash(一般2MB以内),用于存放应用程序;而高性能MCU,往往内部不会集成Flash,需要在板级设计时外挂一片稍大容量的NOR Flash(大部分是串行NOR,一般8MB以上)。
恩智浦i.MXRT系列属于高性能MCU,需要外挂Flash。i.MXRT本身可以支持串/并行NOR、串/并行NAND四类设备作为启动设备,但在官方参考设计板EVK上,推荐的都是串行NOR Flash型号。官方没有推荐并行NOR/NAND,这是可以理解的,毕竟相比串行接口Flash,引脚占用略多,这对I/O资源紧张的MCU项目来说不太讨喜。那官方为何不推荐串行NAND作为启动设备呢?这主要是串行NAND在i.MXRT下无法XiP,这对项目软件设计来说有一些限制。NAND无法XiP的原因有两点,既跟NAND自身特性有关,也跟FlexSPI外设特性有关,且听痞子衡细说:
一、FlexSPI对于NAND的支持
我们知道在i.MXRT中是FlexSPI外设负责实现串行NOR/NAND Flash设备的读写访问支持,痞子衡写过一篇文章 《从头开始认识i.MXRT启动头FDCB里的lookupTable》,文章详述了FlexSPI是如何通过lookupTable来支持串行NOR Flash设备XiP启动的(这里主要是读访问支持)。
在lookupTable设计里,其实AHB读访问并不是NOR Flash设备的专利,或者这么说,FlexSPI外设本身并不在乎连接得是什么类型的设备,它就是完全根据用户在lookupTable里填入的命令时序按部就班工作而已。
对于四线QSPI NOR,仅需要在lookupTable里填入一条命令时序(Read有很多种,但都能在一条Sequence里实现)就可以支持AHB读。而HyperFlash、HyperRAM和串行NAND等设备,lookupTable里一条命令时序搞不定完整读操作,需要多条命令时序组合完成。
FlexSPI外设支持在lookupTable中联合多条命令时序去实现AHB读,通过FlexSPI->FLSHxxCR2寄存器里的如下两处功能位来实现。ARDSEQID位指明读访问时序在lookupTable中的起始位置(index),ARDSEQNUM位指明读访问时序共占用几条命令时序(这也意味着几条命令时序要按序放在一起)。
比如Micron MT29FxG01串行NAND系列,就需要如下三条命令时序(Page Read + Get Feature + Random Data Read)组合完成读操作。但是理想很丰满,现实却骨感,即使组合这三条命令时序也无法在FlexSPI下实现NAND的XiP。
实际应用时,对于NAND的读访问,都是在程序代码中先通过IPCMD方式手动发送Page Read和Get Feature命令,然后借助lookupTable中的Random Data Read命令实现仅一个Page空间大小的AHB读,做不到全部NAND空间的自动AHB读(当然如果你觉得一个Page空间的AHB读太鸡肋,完全可以直接用IPCMD方式去读Page数据)。
- Note: 关于NAND仅一个Page空间的AHB读支持再作下详细解释。比如NAND的Page大小为2KB,那么系统里仅需给NAND分配0x60000000 - 0x600007FF的AHB映射空间,每次对这个空间进行AHB读之前,都需要先通过IPCMD发送Page Read和Get Feature,确保NAND处于Page数据输出的Ready状态,底下FlexSPI就可以完成这个Page内的任意AHB读访问支持。而一旦切到新Page访问,需要重复上述过程,因此NAND所有Page的访问都可以在这个2KB的映射空间里完成的。
二、串行NAND阻碍XiP的两大特性
到底串行NAND的什么特性阻碍了XiP,现在痞子衡来揭秘,在揭秘前大家先看一下痞子衡的旧文 《Raw NAND简介》,先对NAND型Flash有个初步了解。下面痞子衡以Micron MT29FxG01型号串行NAND为例介绍其阻碍XiP的两大特性:
2.1 坏块导致的非线性存储
凡是NAND型Flash都绕不开坏块(Bad Block)问题,这也是NAND Flash区别于NOR Flash的一个重要特点。NAND技术上允许坏块的存在,这降低了NAND生产工艺要求,因此NAND单位容量价格比NOR低。
NAND内部按粒度从大到小划分依次为Plane、Block、Page、Byte(如下图所示),因为坏块导致了一些Block无法有效存储数据,这些Block会被标记拉黑,所以从主设备访问角度来看,NAND中的数据并不是按地址连续存储的,坏块占据的地址均为无效地址,这就是所谓的非线性存储,而非线性存储设备显然无法作为XiP设备。
- 非线性存储器,对于写入操作,无法保证应用程序一定放在指定链接的地址(即在Flash中的对应偏移地址),写入过程中遇到坏块,会跳过坏块,而那些坏块占据的无效地址极有可能就是应用程序实际链接地址。
2.2 ECC校验导致的Page Read等待
我们现在假设一种理想情况,NAND中不存在任何坏块,可以强行把NAND当作线性存储设备,这种情况下是不是就可以被用作XiP设备了呢?很遗憾,FlexSPI外设还是不能正面支持(有替代方法来支持)。
我们来看串行NAND的完整读时序,0x13(Page Read)是FlexSPI发送的第一个命令,用于通知NAND主设备想要访问Page了,随后发送列地址,指明要读的Page位置,此时NAND便会将内部状态寄存器里Busy位标志起来并进入忙状态。
在忙状态时间里,NAND会从内存块里将指定的Page数据全部拷贝到临时缓存区(Cache memory),对这一整个Page数据进行ECC校验,校验完成后将状态寄存器里相应ECC标志起来以及将Busy位清除掉,然后结束忙状态,进入数据输出准备状态。
由于不知道NAND什么时候会结束忙状态,因此FlexSPI需要不断发送0x0F(Get Feature命令)去读取状态寄存器的值,直到状态寄存器里Busy位被清零才能去读取Page数据,这种逻辑判断行为在lookupTable里无法自动实现(NOR读时序里无需逻辑判断)。
如果特意省略读状态寄存器的步骤,避免逻辑判断行为,在lookupTable直接填入Dummy周期来代替行不行呢?理论上倒是可以的。我们来算一下,比如NAND典型的50MHz时钟频率,一个Dummy Cycle周期耗时20ns,NAND Page Read等待典型值是45us,即2250个Dummy Cycle,lookupTable有16条Sequence,每个Seqence支持8个instruction,每个instruction如果都设为DUMMY_SDR,参数设最大255,则9个instruction就能满足这个等待时间。
但即使这么做能勉强实现NAND Flash的XiP,代码实际执行效率也是非常低下的,毕竟涉及到跨Page的指令长跳转(暂不讨论Cache因素)就需要等待45us,这在嵌入式世界里是不短的时间,系统实时性无法保证,又有什么意义呢?
至此,串行NAND Flash的两大特性导致其在i.MXRT FlexSPI下无法XiP痞子衡便介绍完毕了,掌声在哪里~~~
欢迎订阅
文章会同时发布到我的 博客园主页、CSDN主页、知乎主页、微信公众号 平台上。
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。