起初对Boot流程感到疑惑的原因是所开发的项目中程序A(用于下载上位机程序,并跳转至程序B)位于0x60000000地址,而程序B位于0x0000000(当时在架构设计上是为了方便调试,因此将程序放在此处)。
本文总结整理痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU启动那些事,以及《IMXRT1020RM》文档,为个人学习笔记,如有错误欢迎在评论区指正,谢谢!
Boot的基本原理
Boot分为从内部FLASH启动,从内部SRAM启动,从外部存储器启动
1.从内部Flash启动
Boot,首先应该联想到的是FLASH,通常Cortex-M微控制器芯片内部一般都会集成FLASH(从FLASH分类上来看应该属于Parallel NOR FLASH),你的Application代码都是保存在FLASH里,每次上电CPU会自动从FLASH里获取Application代码并执行,这个行为就是Boot。
ARM Cortex-M内存使用的是统一编址,32bit总线的地址空间是4GB (0x00000000 - 0xFFFFFFFF)。同样I.MX RT1020同样遵守Arm®v6/7/8-M Architecture Reference Manual手册下的system address map表。
ARM 4GB空间的前512MB(0x00000000 - 0x1FFFFFFF)规划为非易失性存储器空间。仅含FLASH的芯片上电启动默认都是从0x0地址开始获取Application的初始PC和SP开始Boot。
从映射表中《i.MXRT1020RM》表3.1可以看出
0x00000000 - 0x0003FFFF为ITCM
0x60000000 - 0x7FFFFFFF 为FlexSPI连接的存储区域,项目中FlexSPI所连接的是NOR FLASH
0x80000000 - 0x81FFFFFF 为SDRAM
BOOT ROM
《IMXRT1020RM》9.2 Overview
The boot process begins at any Reset where the hardware reset logic forces the Arm core to begin execution starting from the on-chip boot ROM.
BootROM其实是芯片在出厂前固化在ROM里的一段Bootloader程序。这个Bootloader程序可以帮助你完成FLASH里的Application的更新,而不需要使用额外的外部编程/调试器(比如JLink),Bootloader一般提供UART/SPI/I2C/USB接口与上位机进行通信,与Bootloader配套使用的还有一个上位机软件,当芯片从BootROM启动后,通过这个上位机软件与BootROM建立连接,然后可以将你的Application代码(bin/s19/hex格式)下载进芯片FLASH。
总言之,BootROM中的核心功能就是两个:1.从存放Application的存储器中加载执行 2.通过支持的通信接口接收来自Host的Application数据完成更新。
BOOT MODE选择
当芯片既有ROM也有FLASH的时候,便会出现Boot位置选择问题,标准术语称为Boot Mode。芯片上电CPU到底是先从FLASH启动还是先从ROM启动?
Boot模式提供给用户使用的总共有三种模式,其中boot模式的选择是基于存储在内置BOOT_MODE寄存器中的值决定的,而BOOT_MODE寄存器的初始化是在POR_B引脚输入上升沿的同时采样BOOT_MODE0和BOOT_MODE1的输入来决定的。在对这些输入进行采样后,
它们的后续状态不会影响内部BOOT_MODE寄存器的内容。
此时就可以看项目中的原理图,发现硬件引脚配置BOOT_MODE0为通过电阻接地,BOOT_MODE1引脚接入DCDC3.3v,因此当前的Boot模式为Serial Downloader模式。
从上图Table 3-1可以看出i.MXRT支持三种存储类型:
1.0x00200000-0x00217FFF 96KB的ROM(BootROM) 蓝色
2.总容量是3*256KB的RAM(OCRAM/DTCM/ITCM) 绿色
3.额外分配给外部存储器接口控制器(SEMC/QSPI)的2GB存储空间 黄色
那么i.MXRT Boot方式主要就是借助BootROM从外部存储器加载Application到内部SRAM或者加载到外部SDRAM或者原地XIP执行。项目中所采用的是项目中FlexSPI所连接的是NOR FLASH,支持XIP执行,本项目中的boot方式是借助BootROM在外部存储器中原地XIP执行。
下面简单介绍一下启动模式之间的区别:
Boot From Fuses mode (BOOT_MODE[1:0] = 00b)
根据Fuse中的boot配置来选择从哪个外部存储器boot
Serial Downloader (BOOT_MODE[1:0] = 01b)
串行下载器提供了一种将程序映像下载到片上的方法RAM通过USB或UART串行连接。在这种模式下,通常一台主机可以使用串行下载协议与ROM引导程序通信。
在这种模式下,BootROM通过指定的USB或者UART口来接受Host的Application数据,并将其数据存储在SRAM中执行,这种从宏观上来看就是从SRAM启动,但是这种启动模式每次上电都需要重新将Application下载到SRAM中,无法做到脱机自动Boot,因此此模式的主要目的不是从SRAM中启动Application。
他的主要目的是用来从SRAM中启动Flashloader,Flashloader程序可以用来把Application程序下载进i.MXRTyyyy支持的所有非易失性存储器中,为后续从外部存储器启动做准备。在痞子衡这篇博客中详细介绍到Serial Downloader模式下Flashloader的命令行。
Internal Boot mode (BOOT_MODE[1:0] = 10b)
与Boot From Fuses模式类似,只是这个模式可以通过BOOT_CFG[x:0]pins输入状态来切换Boot配置,使用BOOT_CFG[x:0]会更加便捷。(博主痞子衡建议道:BOOT_CFG[x:0]主要用于产品开发过程中,待产品开发结束后,直接应用Fuse来锁定Boot配置)
在项目中BOOT_CFG[7:4]为0x0000即boot device选择为Serial NOR boot via FlexSPI
在这个模式时,处理器继续执行来自内部引导ROM的引导代码。引导代码执行硬件初始化,从所选的引导设备,使用HAB库执行映像验证(参见boot安全设置),然后跳转到从程序映像派生的地址。如果一个如果在内部引导过程中出现错误,则引导代码跳转到Serial Downloader(参见Serial Downloader (BOOT_MODE[1:0] = 01b))。使用HAB的安全引导是所有三种启动模式都是可行的。
Boot Device 具体配置
BootROM还是通过BOOT_CFG[x:0] pin 和 Fuse 来确定不同的Serial NOR芯片的特性。
出现IMXRT1020芯片锁死无法烧录问题
导致问题原因:在修改程序时钟频率时,超出修改限制。(尤其需要注意,这类错误编译器是不可能会帮助我们报错的,除非在库函数中加入断言)导致该代码烧入芯片后出现锁死的情况。
解决方法:将启动模式修改为Boot From Fuses,即修改BOOT_MODE0和BOOT_MODE1两个引脚(均接地)。这样芯片就能够正常识别并连接仿真器,接入J-Link/ST-Link后先擦除Flash,再重新写入正确(指时钟频率没有异常)的代码。将boot模式切换回Serial Downloader模式,便能能够正常运行。