一、硬件平台:
正点原子I.MX6U阿尔法开发板
二、启动方式选择
I.MX6U 支持多种启动方式以及启动设备,比如可以从 SD/EMMC、NAND Flash、QSPI Flash 等启动。用户可以根据实际情况,选择合适的启动设备。
芯片上电以后,芯片会根据 BOOT_MODE[1:0] 的设置来选择 BOOT 方式, BOOT_MODE[1:0] 的值有两者控制方式
eFUSE(熔丝) 控制电平:修改 eFUSE 的方式通过熔断对应的熔丝修改电平,该方式只能修改一次(不推荐)
修改 BOOT_MODE[1:0] 对应的 GPIO 高低电平来选择启动方式
I.MX6U 使用的是控制 IO 电平来控制启动方式,原理图上位置如下:
BOOT_MODE[1:0] 与启动方式关系:
BOOT_MODE[1:0] | BOOT 类型 |
---|---|
00 | 从FUSE 启动 |
01 | 串行下载 |
10 | 内部BOOT 模式 |
11 | 保留 |
一般我们使用 01 和 10 启动方式
2.1 串行下载
BOOT_MODE[1:0] 为 01;
串行下载:可以通过 USB 或者 UART 将代码下载到板子上的外置存储设备中,比如载串行下载模式下,我们可以使用 OTG1 这个 USB 口向开发板上的 SD/EMMC、NAND 等存储设备下载代码
2.2 内部BOOT模式
BOOT_MODE[1:0] 为 10;
此模式下,芯片会执 行内部的 boot ROM 代码,这段 boot ROM 代码会进行部分硬件初始化,然后从 boot 设 备(就是存放代码的设备、比如 SD/EMMC、NAND)中将代码拷贝出来复制到指定的 RAM 中, 一般是 DDR
2.3 BOOT ROM初始化内容
在内部 BOOT 模式下,芯片执行 BOOT ROM 初始化内容,BOOT ROM 如何执行呢?
首先 BOOT ROM 代码先初始化时钟,按下下图初始化各个时钟总线的分配器
同时内部 boot ROM 为了加快执行速度会打开 MMU(内存管理单元) 和 Cache(缓存),下载镜像的时候 L1 ICache(1级指令缓存) 会打 开,验证镜像的时候 L1 DCache、L2 Cache 和 MMU 都会打开。一旦镜像验证完成,boot ROM 就会关闭 L1 DCache、L2 Cache 和 MMU
之后中断向量偏移会被设置到 boot ROM 的起始位置,当 boot ROM 启动了用户代码以后就可以重新设置中断向量偏移了
2.4 内部BOOT启动设备
当 BOOT_MODE 设置为内部 BOOT 模式以后,可以从以下设备中启动:
接到 EIM 接口的 CS0 上的 16 位 NOR Flash
接到 EIM 接口的 CS0 上的 NAND Flash
接到 GPMI 接口上的 MLC/SLC NAND Flash,NAND Flash 页大小支持 2KByte、4KByte 和 8KByte,8 位宽。
Quad SPI Flash。
接到 USDHC 接口上的 SD/MMC/eSD/SDXC/eMMC 等设备。
SPI 接口的 EEPROM
关于启动设备的选择,I.MX 6U 同样提供了 eFUSE 和 GPIO 量种配置方式,常用的是 GPIO 选择启动设备
启动设备是通过 BOOT_CFG1[7:0]、BOOT_CFG2[7:0]和 BOOT_CFG4[7:0]这 24 个配置 IO,这 24 个配置 IO 刚好对应着 LCD 的 24 根数据线 LCD_DATA0~LCDDATA23,当启动完成以后这 24 个 IO 就可以 作为 LCD 的数据线使用。这 24 根线和 BOOT_MODE1、BOOT_MODE0 共同组成了 I.MX6U 的启动选择引脚
虽然有 24 个 IO,但是实际需要调整的只有那几个 IO,其它的 IO 全部下拉 接地即可,如下图,大部分 IO 一直保持下拉接地,只有几个 IO (BOOT_CFG2[7:0]和 BOOT_CFG1[7:0])需要我们关注:
IO 与启动设备的关系如下图:
各个模式间切换时,许多 IO 是基本保持不变的,所以进一步简化,只需要 LCD_DATA3 ~ LCDDATA7、LCD_DATA11 这 6 个 IO 也被引出来了,其中 LCD_DATA11 就 是 BOOT_CFG2[3],LCD_DATA3~LCD_DATA7 就是 BOOT_CFG1[3]~BOOT_CFG1[7]
对应的设备模式如下:
所以 I.MX6U 开发板从 SD 卡、EMMC、NAND 启动 的时候拨码开关各个位设置方式如表
三、镜像烧写
学习 STM32 的时候我们可以直接将编译生成的.bin 文件烧写到 STM32 内部 flash 里面,但 I.MX6U 不能直接烧写编译生成的.bin 文件,我们需要在.bin 文件前面添加一些头信息构成 满足 I.MX6U 需求的最终可烧写文件
I.MX6U 的最终可烧写文件组成如下:
Image vector table,简称 IVT,IVT 里面包含了一系列的地址信息,这些地址信息在 ROM 中按照固定的地址存放着
Boot data,启动数据,包含了镜像要拷贝到哪个地址,拷贝的大小是多少等等
Device configuration data,简称 DCD,设备配置信息,重点是 DDR3 的初始化配置
用户代码可执行文件,比如 led.bin
所以烧写文件的最终组成为: IVT + Boot data + DCD + usr.bin;其中 IVT + Boot data + DCD 大小为3KB
IVT 包含了镜像程序的入口点、指向 DCD 的指 针和一些用作其它用途的指针。内部 Boot ROM 要求 IVT 应该放到指定的位置,不同的启动设备位置不同,而 IVT 在整个 load.imx 的最前面,其实就相当于要求 imx 文件在烧写的时候应该烧写到存储设备的指定位置去。整个位置都是相对于存储设备的起始地址的偏移
3.1 IVT + Boot data 存放内容:
header:
Tag 为一个字节长度,固定为 0XD1,Length 是两个字节,保存着 IVT 长度,大端格式(高字节保存在低地址)最后的 Version 是一个字节,为 0X40 或者 0X41
entry:入口地址,也就是镜像第一行指令所在的位置。 0X87800000 就是我们的链接地址
reserved1:保留位
dcd:DCD 地址,镜像地址为 0X87800000,IVT+Boot Data+DCD 整个大小为 3KByte。因此 .imx 文件的起始地址就是 0X87800000-0XC00=0X877FF400
Boot Data:boot 地址,header 里面已经设置了 IVT 大小是 32 个 字节,其结构如下:
start 整个 load.imx 的起始地址,包括前面 1KByte 的地址偏移。
length 镜像大小,这里设置 2MByte。镜像大小不能超过 2MByte。
plugin 插件
self: IVT 复制到 DDR 中以后的首地址
csf: CSF 地址
reserved2:保留,未使用
3.2 DCD数据
复位以后,I.MX6U 片内的所有寄存器都会复位为默认值,但是这些默认值往往不是我们想要的值,有些外设我们必须在使用之前初始化它。为此 I.MX6U 提出了一个 DCD (Device Config Data) 的概念,和 IVT、Boot Data 一样,DCD 也是添加到 load.imx 里面的,紧跟在 IVT 和 Boot Data 后面,IVT 里面也指定了 DCD 的位置。
DCD 其实就是 I.MX6U 寄存器地址和对应的配置信息集合,Boot ROM 会使用这些寄存器地址和配置集合来初始化相应的寄存器,比如 开启某些外设的时钟、初始化 DDR 等等。DCD 区域不能超过 1768Byte !
DCD 里面的初始化配置主要包括三方面:
设置 CCGR0~CCGR6 这 7 个外设时钟使能寄存器,默认打开所有的外设时钟
配置 DDR3 所用的所有 IO
配置 MMDC 控制器,初始化 DDR3