笔者最近接触到一块IMXRT1160的双core板子,特依次来记录学习一下
1、IMXRT1160 板子介绍
介绍一下NXP的Demo板子,是一个双core的板子,Cortex-M7和Cortex-M4,总计1MB的RAM空间,256KB的ROM空间,提供了丰富的内存接口,包括SDRAM、Nand Flash、Nor Flash、SD/eMMC,QSPI以及HyperRAM FLash。支持从fuseboot、ISP 串行下载和内部boot启动。
模块结构框图如下:
板子框图如下:
内部boot启动支持多种启动:
支持DAP-Link和Jtag调试。DAP-LINK或者OpenSDA,可参考这篇文章:OpenSDA调试器背景与架构。
再来看一下其内核的特性:
CortexM7内核:一个core,基于arm V7E-M
- 64位,AMBA4 AXI总线,32位 AHB 外设端口,32位AMBA AHB 从机端口,AMBA APB Coresight debug组件
- 32KB的指令cache以及32KB的带ECC校验的数据cache
- 可配置的512KB TCM (默认256KB data 和256KB 指令)
- 16个region的MPU
- NMI + 240 IRQ
- 带WFI 、WFE的睡眠和深度睡眠
- 支持SWD以及JTAG
- 双core锁步机制。
CortexM4内核:1个core,基于ARMv7-ME指令集, - AHB LMEM (对于TCM和cache的memory控制)
- 可配置的256KB的TCM,(默认128KB的指令TCM和128KB的数据TCM)
- 16KB的code bus cache和16KB的系统bus cache
- 集成TCM的ECC校验和代码奇偶校验
- FPU(浮点运算单元)、集成NVIC(可嵌套中断)、WIC(唤醒中断控制器)、MPU(内存保护单元)、MMCAU(加密加速单元)和MCM(复杂控制模块)
2、IMXRT1160 内存布局
内存布局比较重要,外设访问,boot启动,代码缓存等等都与内存相关,可以看到一些相关的信息,尤其是双core,更是这样,涉及到共享内存,外设是否独立或者共享等等。
2.1 M7内存布局
memory说明:
- 0x80000000:SEMC接口,可以接SDRAM,
- 0x30000000:FlexSPI,可以作为QSPI访问Flash,作为mempory memory map的存放flash的地址。
- 0x20360000: 128KB的 专有的OCRAM/FlexRAM空间
- 0x20200000:64KB,可作为双core共享空间
- 0x202C0000:64KB,可作为双core共享空间
- 0x20200000:映射到M4的空间,256KB,作为CM4运行代码的位置,也是M4TCM的位置,这部分如果CM4 断电情况下,CM7无法访问。
- 0x20000000:DTCM的位置,可都配置数据TCM,,可以配置256 KB DTCM,可最大配置512KB
- 0x00000000:ITCM的位置,可都配置为指令TCM,也可以配置256 KB ITCM,可最大配置512KB
- 0x40000000 - 0x41000000:AIPS(ARM IP BUS)CM4和CM7的外设地址,从这里可以看出来,外设是共享的,两者都可以访问。
可以通过NXP的IDE MCUXPRESS的例程里面看到相关的memory配置。
通过上面可以看到,代码执行在0x30000000位置,0x20000000是CM7数据位置(DTCM,rpmsh_sh_mem是双核共享的空间。
当然从这里我们也可以推测其是XIP(excute in place),在Flash上面执行代码,因为没有其他的空间来存放代码,等下通过Boot启动来确认一下。
2.2 M4内存布局
memory说明:
- 0x20200000:64KB,可作为双core共享空间
- 0x202C0000:64KB,可作为双core共享空间
- 0x20200000:CM4的空间,256KB,OCRAM,可以用来放数据和代码,
- 0x20000000:System TCM(128KB),映射到 0x20220000,存放数据
- 0x1FE00000:Code TCM (128KB),映射到 0x20200000,存放代码,
- 0x08000000:FlexSPI,可以接QSPI,作为CM4的启动代码位置。
NXP的IDE MCUXPRESS的例程里面看到相关的memory配置。
2.3 ROM的空间
- 0x00200000:ROM的空间位于0x00200000,大小是256KB
- 0x20240000:ROM所占用的RAM空间,所以不能作为boot image的一部分,当ROM code执行完成之后,可以释放出来使用。如果ROM的API被用户使用,那么该空间需要保留出来。
简单说一下ROM的特性:
- 支持不同boot 设备启动
- 支持串行(UART、USB-HID)下载
- 支持Device Configuration Data 设置数据配置
- 支持secure boot,带签名的高保障性boot
- 支持拓展的内存配置数据
- 支持FlexSPI Nor加密的XIP方式(加密引擎和AES解密)
对于secure boot,就是对启动的Image进行检验,验证过了才可以执行,否则就停留在boot或者是老的Image。
-
引导ROM的一个关键功能是能够执行安全引导,也称为高保证引导(HAB)。这是由HAB安全库支持的,该库是ROM代码的子组件。HAB使用硬件和软件的组合以及公钥基础设施(PKI)协议来保护系统不执行未经授权的程序Image。
-
在HAB允许执行用户Image之前,必须对Image进行签名。签名过程在Image构建过程中完成私钥加密的过程,然后签名被包括作为最后程序Image的一部分。如果配置为这样做,则ROM使用程序Image中包含的公钥来验证签名。除了支持数字签名验证来验证程序Image之外,还支持加密引导。
-
加密引导可用于防止直接从引导设备克隆程序Image。可以在上支持的所有引导设备上使用HAB进行安全引导除了串行下载器之外的芯片。引导ROM中的HAB库还提供API功能,允许额外的引导链组件(例如引导加载器、应用程序)扩展安全引导链。SEC_CONFIG的出厂设置是开放配置,其中ROM/HAB执行Image认证,但忽略所有认证错误,并且仍然允许执行图像。
3、IMXRT1160板子 boot启动
IMXRT1160的启动方式较为多样,上面已经介绍,主要有以下几种方式。通过对Boot Mode的两个输入引脚采样,来决定才有什么方式来Boot。
boot的core也可以被配置,通过BT_CORE_SEL来进行选择,BT_CORE_SEL为0,则M7core启动,如果为1,则M4启动,M4启动相对慢一些。
- 从Fuse boot
- 串行download下载
- 内部boot
- NXP内部保留使用
3.1 Fuse Boot
与 Internal Boot 非常类似,只有一个不一样的点,那就是GPIO Boot PIn引脚被忽略。rom code只使用Boot efuse 的设置。
启动流程由BT_FUSE_SEL的值来决定,
- 如果为1,则从boot device来启动
- 如果来0,则从串行下载启动。
首次板子运行时,BT_FUSE_SEL的值可能为1,但是boot device里面没有Image,可能无法启动,这个时候需要强制设置BT_FUSE_VAL为0,下载一个引导程序到Boot device,然后修改了BT_FUSE_SEL的值,下一次ROM code根据新的eFUSE设置就从boot device启动了。
3.2 Serial Downloader
通过串口或者USB-HID遵循一定的命令协议,来把用户的程序下载到板子里面。例如STM32的FlyMCU,也叫做ISP模式。就是利用ROM的来进行下载。
3.3 Internal Boot
从内部设备进行启动,方式比较多,通过boot的引脚来决定,如前面所述,这里介绍了串行Flash启动的方式。
boot device的配置如下:配置串行Flash的实例,Flash类型,是否自动检测RAM还是XIP方式等
串行Flashboot的流程如下:
- 首先进入Flex Nor的boot流程。
- 配置Flex SPI的引脚和时钟(30MHZ)进行基本的读取配置参数的操作或者Flash是否存在的检测。这些参数位于NorFlash地址的0x400的偏移位置,参数大小为512Byte。
- 基于读到的参数进行基本的配置。
- 是否是加密的XIP模式使能?
- 读取boot device的数据,包括起始地址以及长度等信息,读取Image Vector Table信息,这是用户Image的header信息,填充了用户的Image的地址地址以及大小等信息,方便搬移等等操作。
- 如果Image Header无效,Image继续搜索
- 如果Image Header有效,则判断是否是XIP方式,XIP可以通过boot data判断,boot data的start地址与读参数的数据的地址一致,则为XIP方式,如果不一致,则为Plain Imgae 方式,则需要从Flasn搬移到对应的RAM地址运行。
- 确定好的Image是否有效(栈的空间有效,以及跳转的地址有效),则跳转到对应的地址执行。
Flash配置参数如下:(配置参数开放,方便支持串行Flash、以及hyper Ram等启动方式)
这个配置参数位置在代码开始位置的0x400偏移位置处。
典型参数配置如下:参考NXP IDE。
const flexspi_nor_config_t qspiflash_config = {
.memConfig =
{
.tag = FLEXSPI_CFG_BLK_TAG,
.version = FLEXSPI_CFG_BLK_VERSION,
.readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
.csHoldTime = 3u,
.csSetupTime = 3u,
// Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
.controllerMiscOption = 0x10,
.deviceType = kFlexSpiDeviceType_SerialNOR,
.sflashPadType = kSerialFlash_4Pads,
.serialClkFreq = kFlexSpiSerialClk_133MHz,
.sflashA1Size = 16u * 1024u * 1024u,
/* Enable flash configuration feature */
.configCmdEnable = 1u,
.configModeType[0] = kDeviceConfigCmdType_Generic,
/* Set configuration command sequences */
.configCmdSeqs[0] =
{
.seqNum = 1,
.seqId = 12,
.reserved = 0,
},
/* Prepare setting value for Read Register in flash */
.configCmdArgs[0] = (FLASH_DUMMY_VALUE << 3),
.lookupTable =
{
// Read LUTs
[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
[1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, FLASH_DUMMY_CYCLES, READ_SDR, FLEXSPI_4PAD, 0x04),
// Read Status LUTs
[4 * 1 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x04),
// Write Enable LUTs
[4 * 3 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0x0),
// Erase Sector LUTs
[4 * 5 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 0x18),
// Erase Block LUTs
[4 * 8 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xD8, RADDR_SDR, FLEXSPI_1PAD, 0x18),
// Pape Program LUTs
[4 * 9 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 0x18),
[4 * 9 + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x0),
// Erase Chip LUTs
[4 * 11 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0x0),
// Set Read Register LUTs
[4 * 12 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xC0, WRITE_SDR, FLEXSPI_1PAD, 0x01),
[4 * 12 + 1] = FLEXSPI_LUT_SEQ(STOP, FLEXSPI_1PAD, 0x00, 0, 0, 0),
},
},
.pageSize = 256u,
.sectorSize = 4u * 1024u,
.ipcmdSerialClkFreq = 0x1,
.blockSize = 64u * 1024u,
.isUniformBlockSize = false,
};
Image Vector Table:Image的向量表如下:
首先来说一下Image向量表的偏移位置,不同的Flash启动,其ROM 寻找的偏移位置不一样
本文介绍的FlexSPI Nor的偏移是0x1000,就是4K的位置。
Image向量表的结构如下,每个字段都是32位。
Image的header结构如下:Value=0x412000D1
通过最终的Imgae Code可以看到。
Entry:就是用户code的入口地址,便于ROM code跳转过去,
DCD:Device Configuration Data,设备的配置数据,用户如果有需要配置的外设信息,可以在此处按照相应的参数格式填写,没有填0
Boot Data:启动数据,Image的绝对地址,以及编程Image的大小信息,可以用来判断是否是XIP方式,如果是XIP方式,则boor data 里面的start地址就是Flash 的起始地方,否则就不是XIP方式。
不是XIP方式的boot data数据
是XIP方式的boot数据
self:指示着IVT 表的地址,rom code用来使用,确定IVT的地址是否合法。
4、IMXRT1160 代码下载
待补充