查看: 4420|回复: 1

[分享] i.MX RT1060/1010上串行NOR Flash冗余程序启动设计

[复制链接]
  • TA的每日心情
    开心
    7 天前
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3868

    主题

    7472

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39227
    最后登录
    2025-7-18
    发表于 2022-3-10 09:51:58 | 显示全部楼层 |阅读模式
    i.MX RT1060/1010上串行NOR Flash冗余程序启动设计


    工业产品设计里经常会有冗余程序/备份程序设计的需求,因为在工业环境里要求设备能够持续稳定运行,不能轻易宕机,但现实环境中常常有各种意外发生,其中一个常见的意外就是设备主控MCU程序被破坏。


    为了降低程序损坏这种意外带来的影响,一个很典型的做法就是增加MCU程序的份数,第一份被破坏,就启动第二份...,用程序数量的增加来降低启动失败率,这属于概率学手段范畴。
    我们知道恩智浦i.MX RT系列MCU内部没有非易失性存储器,它需要搭配外部存储器来工作,可选存储器类型非常多:NOR Flash, NAND Flash, eMMC, SD卡都行。
    其中对于NAND型存储器,冗余程序设计是必备的,因为NAND本身允许坏块现象存在,所以不得不做冗余设计。而对于NOR型存储器,冗余设计则不是必需的,偏偏串行NOR Flash是i.MX RT最常用的搭档,那该怎么办?别急,今天痞子衡介绍的就是i.MX RT1010/1060上串行NOR Flash冗余程序设计,恩智浦已经都给你考虑到了。
    注:本文所涉及的串行NOR Flash冗余程序设计,不支持早期的i.MX RT1050/1020/1015型号。


    一、初识冗余程序启动
    在i.MX RT上可以挂载串行NOR Flash去启动程序的外设有两个,分别是FlexSPI和 LPSPI,如下图所示。
    14.png
    注:并不是所有 i.MXRT 型号都支持 LPSPI 外设挂载存储器去启动。


    其中连接在FlexSPI 上的 Flash A 属于主启动设备,连接在LPSPI上的Flash B属于备份启动设备(关于备份设备启动详见痞子衡旧文《从Serial(1-bit SPI) EEPROM/NOR恢复启动》)。


    用两片NOR Flash去完成冗余程序设计当然是没问题,但也相应增加了硬件成本,而本文今天要讨论得不是这种冗余程序设计,我们要聊的是在一片挂载在FlexSPI上的串行 NOR Flash里做冗余程序设计,就是图中的image 0和image 1。


    冗余程序启动流程其实特别简单,上电永远先启动物理地址靠前的image 0,如果 image 0被破坏了,则启动image 1。原则上image 0和image 1应该是完全一样的(链接地址也一样,并且中途不需要搬移这两份image数据,这个是靠芯片里的一个黑科技做到的,下文会细讲),毕竟是冗余设计,不过你要执意放两份不完全一样的image,倒也没问题。

    二、实测冗余程序启动
    我们知道i.MX RT芯片上电总是先运行厂商固化好的BootROM,所以冗余程序启动设计是做在BootROM代码里的。之前有一篇旧文 《了解i.MXRT1060系列ROM中串行NOR Flash启动初始化流程优化点》中2.1 节其实已经简单地提到了冗余程序设计,其主要借助了芯片系统FlexSPI地址重映射(Remap)功能,这个功能是在恩智浦后期推出的 i.MX RT1060/1010 等型号上才有的,这也是上文所说的黑科技。关于这个黑科技,痞子衡也有旧文《利用i.MXRT1060,1010上新增的FlexSPI地址重映射(Remap)功能可安全OTA》。


    有了FlexSPI Remap黑科技存在,我们就可以将同一份image binary放在Flash中两个不同位置,并且不用做擦除编程操作来交换其位置,就可以实现各自的启动执行。如果没有这个黑科技,我们只能老老实实做数据搬移,这会增加擦除次数从而影响Flash使用寿命。


    原理搞清楚了,现在我们在板子上实测一下这个功能,看看如何正确地放两份image进Flash,哪些情况会导致image 0启动失败从而去启动image 1。


    我们就以恩智浦官方MIMXRT1060-EVK开发板为例,这个板子FlexSPI1上挂了两片 Flash,默认连接的8MB QuadSPI Flash,还有一片64MB HyperFlash(需要做板子改动才能使能):

    2.1 使能冗余程序启动
    使能冗余程序启动特性很简单,就是将fuse 0x6E0[23:16] - FLEXSPI_NOR_SEC_IMAGE_OFFSET烧录为非0值即可,根据下面定义,第二份image 偏移地址最大可以设到Flash中0x3FC0000(63.75MB)处:


    Remap功能的ADDR_START寄存器固定设为Flash 起始映射地址。


    fuse 0x6e0[15:13] - xSPI_FLASH_IMAGE_SIZE,App的最大长度,标识了第一份App的结束地址,该值加上ADDR_START后被填入Remap功能的ADDR_END寄存器。


    fuse 0x6e0[23:16] - FLEXSPI_NOR_SEC_IMAGE_OFFSET,标识了第二份App的起始地址(在Flash中偏移位置),即填入Remap功能的ADDR_OFFSET寄存器的值。
    15.png
    本次测试,我们就将FLEXSPI_NOR_SEC_IMAGE_OFFSET烧录为0x10,xSPI_FLASH_IMAGE_SIZE保持默认0,即第二份image 偏移地址在Flash 0x400000(4MB)处,最大image长度也是4MB,可借助MCUBootUtility工具完成Fuse烧录:
    16.png
    2.2 下载两份无签名image进Flash
    现在开始准备image,我们就直接用\SDK_2.10.1_EVK-MIMXRT1060\boards\evkmimxrt1060\demo_apps\led_blinky例程,简单直观。为了便于肉眼分辨效果,我们生成两个稍微不一样的image,闪灯间隔时间一个是200ms(image 0 - iled_blinky_delay200ms.bin),另一个是2s(image 1 - iled_blinky_delay2s.bin):
    17.png
    然后还是借助MCUBootUtility工具,先使用All-In-One操作将image 0下载进Flash,因为是bin文件,所以我们要填入正确的链接起始地址(对于i.MX RT1060就是 0x60000000;对于i.MX RT1010应该是0x60000400,具体查看工程链接文件便知)。


    此外我们使用的是完整的可启动镜像文件(包含了全部所需启动头),也可以直接在软件通用编程器界面做下载。
    18.png
    image0下载进Flash后,继续下载image 1,这时候只能在软件通用编程器界面操作。这里主要是设置好下载起始地址,前面我们使能冗余程序启动时在Fuse里设置的偏移地址是0x400000,那么此时下载起始地址就应该是0x400000(对于i.MX RT1060是0x400000;对于i.MX RT1010应该是0x400400)。至此两份image下载就完成了。
    19.png
    2.3 快速验证两份image正确性
    现在Flash里有了两份image,我们来做一个快速验证,看看image是不是放得符合冗余程序启动的要求。对于image 0,没什么好说的,芯片启动模式设为2'b10 后断电复位应该可以看到image 0在执行,最重要的是验证image 1是不是合法。


    这里开始涉及到芯片冗余程序启动流程核心了,当image 0启动失败后,芯片BootROM不是立刻去执行image 1的,它用了一个取巧的方式,在一个软复位不置位的寄存器里(SRC_GPR10)标记了当前状态,然后调用NVIC_SystemReset()重新进入BootROM执行,第二次BootROM执行时才会去启动image 1。
    20.png
    所以这也给了我们快速验证image 1执行的可能性,我们在板子上挂上J-Link仿真器,然后打开J-Link Commander,直接将SRC_GPR10寄存器改写为0x40000000,再依次执行reset和go命令,这时你应该可以看到image 1正在执行了。
    21.png
    2.4 测试无签名 image 0 损坏条件
    痞子衡之前在 《i.MXRT Bootable image格式》一文里介绍过一个可启动image包含哪些组成部分,其中最简单的无签名image应该至少包含FDCB, IVT, BD, App四部分,芯片BootROM也是按序读取这四部分数据完成程序启动的。
    22.png
    现在我们尝试分别破坏这几个组成部分来看看何种程度的image 0损坏能被BootROM识别出从而去启动image 1,下面是测试结果。从测试结果来看,除了Image 0 - App的损坏无法检测外,image 0其余启动头的损坏都可以被BootROM识别到。
    23.png
    2.5 能检测image 0 app损坏的方法


    如果不能检测image app部分的损坏,那这个冗余程序启动功能就比较鸡肋了,毕竟app部分的数据才是整个image核心所在。如果要加上app损坏检测,需要使能i.MX RT 签名启动,还是可以借助MCUBootUtility工具完成全部流程,下载两份含签名的image进Flash的过程跟2.2节基本差不多,只是Secure Boot Type里需要选择 "HAB Signed Image Boot",含签名的image 0下载没什么好说的,All-In-One操作全搞定,含签名的image 1数据可以通过在通用编程器界面里将含签名的image 0数据全部读回得到,这个具体操作就不详细展开了。


    含签名image 0相比无签名image 0多了HABdata(csf,cert,signature) 数据段,BootROM在跳转image之前会根据HAB data数据对image进行验签,验签通过才做跳转。
    24.png
    此时再做一次破坏实验,结果如下,显然加了签名的image 0其完整性就有保证了,这时的冗余程序启动设计才能发挥出最大效果。
    25.png

    qiandao qiandao
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 23:21
  • 签到天数: 1845 天

    连续签到: 5 天

    [LV.Master]伴坛终老

    203

    主题

    3万

    帖子

    64

    超级版主

    Rank: 8Rank: 8

    积分
    112619
    最后登录
    2025-7-17
    发表于 2022-3-10 11:04:32 | 显示全部楼层
    这玩法真高级啊
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-18 20:52 , Processed in 0.084374 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表