大家好, 我是痞子衡, 是正经搞技术的痞子. 今天痞子衡给大家介绍的是飞思卡尔 i.MX RT 系列 MCU 的 Parallel NOR 启动.
上一篇讲 i.MXRT 从 Raw NAND 启动的文章 飞思卡尔 i.MX RT 系列微控制器启动篇 (8)- 从 Raw NAND 启动 一经放出, 深入广大网友喜爱, 短时间内阅读量飙升, 这让痞子衡深入鼓舞, 所以趁热打铁继续把从 Parallel NOR 启动也顺便一起讲了, 为什么说是顺便呢? 因为 Parallel NOR 与 Raw NAND 都是并行接口, 属于同一门派, 且这两种外存设备在 i.MXRT 内部是通过同一 IP(SEMC) 实现底层接口通信的, 所以了解了 Raw NAND 启动, 再来看 Parallel NOR 启动会觉得简单很多. 话不多说, 开讲.
一, 支持的 Parallel NOR
依旧开门见山, i.MXRT 支持加载启动的主要是兼容 CFI 标准且内置 EPSCD 命令集的 ADM SLC Parallel NOR, 至于数据线宽度, x8,x16 都支持; 关于时钟模式, i.MXRT105x/i.MXRT102x 仅支持 Asynchronous,i.MXRT106x 既支持 Asynchronous 也支持 Synchronous. 关于 Parallel NOR 基本知识请先看一下痞子衡的另一篇文章 并行接口 NOR 标准 (CFI) 及 SLC Parallel NOR 简介.
Parallel NOR 厂商非常多, 对应 Parallel NOR 芯片型号也很多, 如果你在选型时不确定到底该为 i.MXRT 选择哪一款 Parallel NOR 时, 可选用下面三款芯片, 痞子衡均实测过:
- Micron MT28EW128ABA1LPC-0SIT (x8/x16 bits, 32B Page/128KB Block/128Mb Device, Non-ADM, Asynchronous)
- Winbond W29GL128CH9T (x8/x16 bits, 64B Page/128KB Sector/128Mb Device, Non-ADM, Asynchronous)
Spansion S29GL128S90TFI020 (x16 bits, 512B Page/128KB Sector/128Mb Device, Non-ADM, Asynchronous)
Note: ADM 即地址线与数据线复用, 为了减少 pin 脚, 有些 Parallel NOR 芯片会将低 bit 地址线与数据线复用, 但目前市面上主流 Parallel NOR 芯片还是 Non-ADM(即地址与数据是不复用的)居多, i.MXRT 虽不能直接连接 Non-ADM NOR 芯片, 但在 i.MXRT 与 Non-ADM NOR 芯片之间使用一片 74 系列锁存器桥接一下便能正常工作.
二, Parallel NOR 硬件连接
确定了 Parallel NOR 芯片选型后, 底下便进入 Parallel NOR 硬件电路设计及与 i.MXRT 的信号连接环节:
i.MXRT 对于 Parallel NOR 的底层接口支持是通过内部 SEMC 这个 IP 实现的, SEMC 最多能支持五种设备(SDRAM, NAND, NOR, SRAM, 8080 Display), 但 SEMC 接口信号是复用的, 所以同一时刻仅能支持一种设备. 下表是 SEMC 接口复用表, 关于 NOR 接口信号, 需要特别说一下的是 CE# 信号和地址线宽度, 从表中我们可以看到 NOR 的 CE4# 信号有 6 个, 即有 6 种配置选择, 但 i.MXRT BootROM 固定选择的是 SEMC_CSX[0], 至于地址线宽度, SEMC 本身最大可支持 28bits 地址宽度, 但是 i.MXRT BootROM 里最大只支持 24bits 地址宽度(即 A0-A23, 最大 128Mb), 这 2 点在设计 NOR 硬件连接时需要特别注意.
Note: 对于小容量 Paralle NOR 芯片 (比如 512KB, 地址线 A0-A18),i.MXRT 当然也可以支持, SEMC 未用的地址线(此处为 A19-A23) 可不用管.
如下是典型的 NOR 硬件连接设计, 示例 NOR 芯片是 MT28EW128ABA1LPC-0SIT, 该 NOR 芯片为 Non-ADM, 所以我们使用了一片 74ALVT16373 锁存器桥接了一下, 当 WEIM_ADV_B 信号为高电平时, 锁存器 Dx 会输出给 Qx, 即此时 WEIM_DATA[15:0]作为地址线输出给 A[15:0], 而 WEIM_ADV_B 信号为低电平时, WEIM_DATA[15:0]就是数据线(即此处 WEIM_ADV_B 作为 ADV# 信号是高有效, 这在后续配置 NOR eFUSE 时会涉及到).
三, Parallel NOR 加载启动过程
确保 Parallel NOR 硬件相关设计无误之后, 底下便是下载更新 Bootable Image 进 Parallel NOR 以供 BootROM 加载启动了, 在下载 Bootable image 之前有必要先了解 Parallel NOR 的加载启动过程:
痞子衡在启动系列文章的第六篇 飞思卡尔 i.MX RT 系列微控制器启动篇(6)- Bootable image 格式与加载(elftosb/.bd) 里的最后已经介绍过 non-XIP image 加载启动过程, 但实际上那个过程主要适用于存储在外部 NAND Flash 中 Bootable image 加载启动, 对于存储在外部 Parallel NOR 的 Bootable image 而言有一些区别, 我们知道 NOR Flash 是支持 XIP 执行的, 所以从 NOR 启动有两种选择, 一种是 Non-XIP, 另一种是 XIP.
对于 Non-XIP 启动而言, 其基本流程与第六篇里介绍的 non-XIP image 加载启动过程类似, 只有两点区别, 第一个区别是存储在 NOR Flash 里的 Bootable image 中 IVT 偏移地址是固定在 0x1000(对于 NAND Flash, 偏移固定是 0x400); 第二个区别是 BootROM 加载 initial image 的大小为 12KB(对于 NAND Flash,initial image 是 4KB), 且这个 initial image 的加载不需要经过 OCRAM 缓存, BootROM 是直接从 NOR 对应的 SEMC map region 去获取的.
对于 XIP 启动而言, 其基本流程与 non-XIP image 加载启动过程差异就比较大了, 因为整个 Bootable image 都不需要搬运, BootROM 直接从 NOR 对应的 SEMC map region 去获取 IVT,BootData,Application, 而 BootROM 中分配给 SEMC NOR 的 XIP 空间为 0x90000000 - 0x90FFFFFF, 所以 XIP 执行的 Application 需要链接在这个空间里.
有了前面的背景知识, NOR 的加载启动过程便是上电之后, BootROM 先从 NOR 起始地址处加载 initial image 数据(12KB), 再根据 initial image 里的 IVT 获取 Application 起始地址, 如 Application 地址是链接在 SRAM 里, 便认为这是个 Non-XIP Application, 然后再将 Application 拷贝到相应 SRAM 里去启动; 如 Application 地址是链接在 SEMC NOR XIP 空间里, 则不需要拷贝, 直接原地 XIP 执行启动.
四, 下载 Application 进 Parallel NOR
理解了 Parallel NOR 加载启动过程, 我们便可以开始使用 Flashloader 下载 Application 进 Parallel NOR 芯片中:
痞子衡在启动系列文章的第四篇 飞思卡尔 i.MX RT 系列微控制器启动篇(4)- Flashloader 初体验(blhost) 和第六篇 飞思卡尔 i.MX RT 系列微控制器启动篇(6)- Bootable image 格式与加载(elftosb/.bd) 里分别介绍了 Flashloader 的基本使用以及如何将你的 Application 制作成 Bootable image, 但那里面制作的 Bootable image 主要是用于 NAND 启动, 而对于 NOR 启动, 其用于生成 Bootable image 的 BD 文件稍有不同.
先来看 Non-XIP 的情况, 下面是一个 Non-XIP 的 BD 文件示例, ivtOffset 必须设 0x1000, 因为 startAddress = 0x8000, initialLoadSize = 0x3000, 所以 Application 只读段应从 0xb000 处开始链接:
- options {
- flags = 0x00;
- # Note: This is an example address, it can be any non-zero address in ITCM region
- startAddress = 0x8000;
- ivtOffset = 0x1000;
- initialLoadSize = 0x3000;
- # Note: This is required if the default entrypoint is not the Reset_Handler
- # Please set the entryPointAddress to Reset_Handler address
- // entryPointAddress = 0xd531;
- }
- sources {
- elfFile = extern(0);
- }
- section (0)
- {
- }
再来看 XIP 的情况, 下面是一个 XIP 的 BD 文件示例, ivtOffset 也必须设 0x1000, 因为 startAddress = 0x90000000, initialLoadSize = 0x3000, 所以 Application 只读段应从 0x90003000 处开始链接:
- options {
- flags = 0x00;
- startAddress = 0x90000000;
- ivtOffset = 0x1000;
- initialLoadSize = 0x3000;
- # Note: This is required if the default entrypoint is not the Reset_Handler
- # Please set the entryPointAddress to Reset_Handler address
- // entryPointAddress = 0x90005531;
- }
- sources {
- elfFile = extern(0);
- }
- section (0)
- {
- }
假定你已经制作好 Bootable image 并且使用 blhost 工具与 Flashloader 建立了基本通信, 正要开始将 Bootable image 下载进 Parallel NOR.
与 Raw NAND 启动一样, Parallel NOR 也支持 configuration block, 只不过 configuration block 对于 BootROM 启动而言不是必需的, configuration block 必须放在 NOR Flash 起始地址处, 下面是其结构原型(如果你还有印象的话, 你会发现它跟 Raw NAND 的 semc_nand_config_t 很像), 如果想使能 configuration block, 你需要手动创建这 256bytes 数据, 并且用其覆盖 bootable image 的前 256bytes, 在本文里暂不使能 configuration block.
- #define SEMC_NOR_INIT_IMG_SIZE (12u * 1024)
- #define SEMC_NOR_MAX_SIZE (16U * 1024 * 1024)
- #define SEMC_MEM0_BASE (0x80000000u)
- #define SEMC_MEM1_BASE (0x90000000u)
- #define SEMC_MEM2_BASE (0xA0000000u)
- #define SEMC_MEM3_BASE (0xC0000000u)
- #define SEMC_MEM_NOR_AXI_BASE SEMC_MEM1_BASE
- typedef struct __semc_nor_config
- {
- semc_mem_config_t memConfig; //!< [0x000-0x04f]
- uint8_t vendorType; //!< [0x050-0x050]
- uint8_t acTimingMode; //!< [0x051-0x051]
- uint8_t deviceCommandSet; //!< [0x052-0x052]
- uint8_t reserved0[77]; //!< [0x053-0x09f]
- uint32_t pageSizeInBytes; //!< [0x0a0-0x0a3]
- uint32_t blockSizeInBytes; //!< [0x0a4-0x0a7]
- uint32_t blockCount; //!< [0x0a8-0x0ab]
- uint32_t reserved1[21]; //!< [0x0ac-0x0ff]
- } semc_nor_config_t;
前面铺垫了这么多, 终于来到关键地方了, 到底怎么样将 Bootable image 数据下载进 Parallel NOR 中呢? 当然还是靠 Flashloader 工具, 我们只需要提供简化的 4byte 配置数据即可. 下面是一种 Application 下载更新示例(该示例适用于第二节里介绍的 NOR 硬件连接):
// 在 SRAM 里临时存储 Parallel NOR 配置数据
blhost -p COMx -- fill-memory 0x2000 0x4 0xD0000600 (Configure to CSX0, ADV high active, 16bits IO, safe AC timing mode)
// 使用 Parallel NOR 配置数据去配置 Parallel NOR 接口
blhost -p COMx -- configure-memory 0x8 0x2000
在上述示例里痞子衡首先使用了 fill-memory 命令在 0x2000 地址处暂存了 4byte 配置数据, 然后通过 config-memory 将这 4byte 数据里的信息配置到 Flashloader 的 Parallel NOR 接口中, 实际上这 2 个命令成功执行后, 你就可以开始使用 Flashloader 下载 Bootable image 了. 那么这 4byte 配置数据到底是怎么组织的? 详见下表:
从上表我们可以知道, 其实这 4byte 数据提供的配置信息主要是 NOR 配置, 这 4byte 里真正需要注意的只有两个地方(ADV# Polarity,Data Port Size), 其余可用固定配置.
configure-memory 命令执行成功之后, 底下 image 的下载很简单, 只需要将 Bootable image 从 SEMC NOR 起始 map 地址开始下载即可, 具体步骤如下:
// 擦除 Parallel NOR 并将 image 下载进 Parallel NOR
blhost -p COMx -- flash-erase-region 0x90000000 0x20000
blhost -p COMx -- write-memory 0x90000000 ivt_image.bin
Note: 实测发现, RT1050 Flashloader 1.1 里使用 USB 接口去下载 Parallel NOR 会报 kStatus_SemcNOR_ProgramVerifyFailure 错误, 而使用 UART 接口下载则正常, 应该是 USB 下载对 NOR 的支持有缺陷, 期望在后续版本的 Flashloader 里修复这个问题.
Bootable image 下载成功之后, 我们可以试着用 read-memory 从 NOR 芯片里读回 IVT,BootData,Application 确认一下, Bootable image 起始地址在 0x90000000, 那么 IVT,BootData 应该在 0x90001000,Application 应该在 0x90003000:
Non-XIP Bootable image 读回情况如下, 检查初始 PC 可知其链接在 SRAM 空间
XIP Bootable image 读回情况如下, 检查初始 PC 可知其链接在 SEMC NOR map 空间
Note: 如果 Application 是 XIP 在 SEMC NOR 空间, 其时钟初始化代码不能覆盖 BootROM 里对于 SEMC 的相关配置, 否则 XIP 可能会失败.
至此, Application 的下载工作便结束了.
五, 进入 Parallel NOR 启动模式
Application 已经被成功下载进 Parallel NOR 芯片之后, 此时我们便可以开始设置芯片从 Parallel NOR 启动:
在进入 Boot Device 选择之前, 你首先需要确定 BOOT_MODE[1:0]=2'b00, 即芯片处于 Boot From Fuses 模式, 并且将 BT_FUSE_SEL(eFUSE 偏移 0x460 处的 32bit 配置数据的 bit4)烧写为 1'b1, 这里看不懂的朋友请温习痞子衡前面的文章 飞思卡尔 i.MX RT 系列微控制器启动篇(2)- Boot 配置(BOOT Pin/eFUSE).
设置好正确 Boot 模式后, 再来选择 Boot Device,, 你还需要将 BOOT_CFG1[7:4](eFUSE 偏移 0x450 处的 32bit 配置数据的 bit7:4)烧写成 4'b0001, 此时便进入了从 SEMC NOR 启动模式.
如果想确保 i.MXRT 芯片一定正在从 Parallel NOR 启动, 可在芯片上电时使用 Jlink 调试器或者借助 Flashloader 读取芯片内部 2 个寄存器的值, 这 2 个寄存器分别是 SRC_SBMR1/2, 我们设的关于启动模式的 BOOT_MODE pins/BOOT_CFG pin/eFUSE 偏移 0x450 配置值在上电时会自动加载到 SRC_SBMR1/2 寄存器里, BootROM 主要是根据 SRC_SBMR1/2 寄存器的值来判断启动模式的.
PS: BOOT_MODE[1:0]也可以设为 2'b10, 即芯片处于 Internal Boot 模式, 此时需要确保 BT_FUSE_SEL(eFUSE 偏移 0x460 处的 32bit 配置数据的 bit4)为 1'b0 和 BOOT_CFG1[7:4]这四个 pin 的输入状态设为 4'b0001.
六, 配置 eFUSE 启动 Parallel NOR
设置好芯片启动模式是从 Parallel NOR 启动之后, 我们还需要最后关注一下与 Parallel NOR 相关的具体特性配置:
你应该记得我们在使用 Flashloader 下载 Application 的时候提供过 4bytes 的 NOR 配置数据, 这 4bytes 的 NOR 配置数据是为了让 Flashloader 能够正确初始化 Parallel NOR 接口去访问 NOR 芯片(主要是写 Bootable image), 同样 BootROM 上电也需要初始化 Parallel NOR 接口去访问 NOR 芯片(主要是读 Bootable image), 所以 BootROM 也需要类似这 4bytes NOR 配置数据, 而 BootROM 的 NOR 配置便放在如下的 eFUSE 区域里:
七, 几个注意事项
市面上 Parallel NOR 从内置命令集角度分为两大类, 一类是以 Micron MT28EW 系列为代表的 EPSCD 命令集, 另一类是以 Micron MT28GU 为代表的 SFMCD 命令集, BootROM 本身对于这两类 NOR 芯片都是支持的, 但 Flashloader 目前只支持内置 EPSCD 命令集的 NOR 芯片.
至此, 飞思卡尔 i.MX RT 系列 MCU 的 Parallel NOR 启动痞子衡便介绍完毕了, 掌声在哪里~~~
来源: https://www.cnblogs.com/henjay724/p/9188252.html