i.MX6ULL 启动方式 启动方式
I.MX6ULL 支持多种启动方式,可以从 EMMC、SD 卡、NAND FLASH、USB、QSPI 等设备启动。通过查看《IMX6ULL 参考手册.pdf》手册的第 8 章 System Boot,可我们可以了解到 i.MX6ULL 在上电以后,芯片 ROM里面固化的程序会根据 BOOT_MODE[1:0]寄存器的值来选择启动方式。
BOOT_MODE[1:0]寄存器的值有两种方式可以修改:一种是采用 eFuses(熔丝)的方式;另一种是是通过设置 BOOT_MODE[1:0]对应的 GPIO 的状态。我们在平常使用的时候基本都是采用设置 BOOT_MODE[1:0]对应的 GPIO 状态来选择启动方式的。
BOOT_MODE[1:0]对应的 GPIO 引脚是 BOOT_MODE1 和 BOOT_MODE0,如下图所示:
BOOT_MODE1 和 BOOT_MODE0 这两个引脚在芯片内部默认有 100K 的下拉,所以这两个引脚在悬空状态下默认是低电平(0)。我们把这两个引脚引到了底板上,并连接到了拨码开关上,拨码开关对应的另一端通过 10K 电阻接到了 3.3V 电源上,这样我们可以通过拨码开关来设置这两个 IO 的状态了(高电平或低电平)。如下图所示:
从上面的截图我们,可以看到如果我们要设置 BOOT1 和 BOOT0 为高电平我们需要将对应的拨码开关设置到“ON”位置,这样就通过 10K 电阻上拉到 3.3V,芯片内部有 100K 的下拉,所以此时这两个 IO 的电平是:100/(10+100)*3.3V=3V,属于高电平。
从参考手册我们看到 BOOT_MODE[1:0]两个 IO 可以设置四种状态,对应着四种启动方式,如下图所示:
从上图可以看到 BOOT_MODE[1:0]:设置为 00 的时候从 Fuses 启动,设置为 01 的时候串行下载,设置为 10 的时候内部 Boot 模式,设置为 11 作为保留使用。我们用到的是“串行下载”和“内部 Boot”模式这两种。
首先我们来看下“串行下载”,它是指可以通过 USB 接口(板子的 OTG1 接口)将代码下载到板子上然后运行。通过此方式我们可以实现开发板镜像的烧写(我们将在后面章节介绍具体的烧写方法)。
然后我们看下“内部 Boot 模式”,它是指在此种模式下,芯片会执行内部 ROM 里面固化的 boot 程序。这段程序会进行硬件的初始化,然后从 Boot 设备(EMMC、SD 卡、NAND FLASH)中读取出镜像到内存中。如果在“内部 Boot 模式”运行过程中发生错误,则会进入“串行下载模式”。
当 BOOT_MODE 设置为“内部 Boot 模式”后,i.MX6ULL 可以从 SPI,EIM,NOR,SD,MMC,QSPI 等设备启动,同时也可以配置相应的参数(例如 SD 的总线宽度,速度等等)。启动设备和对应的参数我们可以使用 eFUSEs 的方式设置,也可以通过 GPIO 来配置(我们主要使用 GPIO 的方式)。下面我们来看一下如何通过 GPIO 设置启动设备。
从参考手册我们可以看到启动设备主要通过三组 IO 来设置,他们分别是 BOOT_CFG1[7:0],
BOOT_CFG2[7:0],BOOT_CFG4[7:0]这三组 IO。如下图所示:
从上图我们可以看到这三组决定启动设备的 IO 正好用到的 RGB 的 24 根数据 IO,在 i.MX6ULL 芯片刚开始上电的时候这 24 个 IO 先作为“选择启动设备”的功能来使用,在 ROM 中的固化程序把启动镜像从启动设备加载到内存,并开始从启动镜像(Uboot)开始运行的时候,这 24 个 IO 就可以当做 RGB 来使用了。
现在我们来总结一下,i.MX6ULL 启动流程:首先根据 BOOT_MODE 的两个 IO(BOOT_MODE1,BOOT_MODE0)先确定启动方式,如果是串行下载模式,就会进入 USB 启动模式。如果是“内部 Boot”启动方式,然后就根据 BOOT_CFG1,BOOT_CFG2,BOOT_CFG4 这三组 IO 的配置来决定从哪种设备启动(读取启动镜像到内存,并开始启动)。
接下来我们看下 BOOT_CFG1,BOOT_CFG2,BOOT_CFG4 这三组 IO 是怎么配置启动方式的,在我们的底板原理图上有如下图表:
上图中最左侧一列是支持的启动设备,后面的每一列分别对应 BOOT_CFG 的 IO,我们可以看到决定启动方式的是由 BOOT_CFG1 和 BOOT_CFG2 这两组 IO 决定。打击爱也许觉得这么多 IO 需要配置,操作起来太麻烦了,实际上这些 IO 中大部分都是默认下拉的,需要配置的只有 6 个,从我们的原理图可以看到(因为我们用了一个 8 位的拨码开关,其中有两位是 BOOT_MOD 的),如下图所示:
从上面的原理图我们可以看到 8 位的拨码开关一端上拉到 3.3V,另一端分别接到了 BOOT_MODE1,BOOT_MODE0,BOOTCFG2[3],BOOTCFG1[3],BOOTCFG1[4],BOOTCFG1[5],BOOTCFG1[6],BOOTCFG1[7]。所以我们设置启动方式,只需要修改这 8 位(有两位是 BOOT_MODE)IO 的状态,我们看下负责启动方式的这 6 个 IO 的含义,如下表所示:
根据上面的表格,我们设置开发板分别从串行下载,EMMC,SD 卡,NAND FLASH 启动的时候,可以按照下面的表格设置,如下表:
下面是 i.MX6ULL 终结者底板上的拨码开关书屋图片,如下图所示:
上图中的 8 位拨码,拨到上面“ON”位置就是 1,拨到下面就是“0”,8 位拨码按照表 2.1 中的设置就可以按照对应的方式启动
5.2 镜像格式 镜像格式
I.MX6ULL 的镜像文件由下面几部分组成:
1.Image vector table 简称 IVT。
2.Boot data,启动数据。
3.Device configuration data,简称 DCD,主要是芯片的配置信息
4.用户代码生成的执行文件。比如 uboot 等。
所以 i.MX6ULL 的镜像组成为:IVT+Boot Data+DCD+用户程序。
我们首先看下 IVT 部分:它里面包含了程序的入口点,一个指向设备配置数据(DCD)的指针,以及其他在启动过征中程被 ROM 固化程序用到的指针。IVT 被存储在启动设备固定的位置(但是不同的启动设备保存的位置可能会不一样)。IVT 在镜像文件的最前面,下图是不同启动设备,IVT 所在的位置偏移(相对于设备首地址):
这里我们以 EMMC 为例,从上表可以看出他的偏移是 1Kbyte(1024 字节),假设 EMMC 的每个扇区是 512字节,那么我们的 IVT 要从第三个扇区开始保存。我们从《IMX6ULL 参考手册.pdf》的 8.7.1.1 章节可以看到IVT 的数据格式如下图所示:
其中的 Tag 是一个字节设置为 0xD1,length 是 2 个字节,按照大端模式存储,表示 IVT 的长度,对后一个Version 是版本信息,占用一个字节,通常为 0x40 或 0x41。由于《IMX6ULL 参考手册.pdf》文档只有 header的描述其它几个字节的描述没有涉及。我们可以打开编译生成的Uboot镜像uboot.imx查看下它里面的内容。
接下来是 Boot data,它的数据格式如下所示:
从上图可以看出 Boot data 一共是三个字段,每个字段 32 位。
然后是 DCD,DCD 紧跟在 Boot Data 后面,IVT 里面也定义了 DCD 的位置。DCD 主要是初始化片内的寄存器。
DCD 的数据格式如下图所示:
第一个是 Header 包头信息,他是一个 32 位的包头,具体定义如下所示:
Tag 占一个字节,被设置为 0xD2;Length 占两个字节,按照大端模式存储,表示 DCD 的区域大小(包含包头的长度),Version 占一个字节,设置为 0x40 或 0x41。
Header 后面的是 CMD 配置寄存器的字节,每个 CMD 的结构如下图所示:
CMD 域的第一个是 Tag,占一个字节,设置为 0xcc;然后是 Lehgth 占两个字节,按照大端模式存储,表示该 CMD 的长度(包含 CMD 的包头),Parameter 占一个字节,这个字的每个为含义如下图所示:
上图中的 bytes 表示目标位置宽度,单位为 byte,可以设置为 1,2,4 字节。Flags 是命令控制标志位。
然后 CMD 域后面的是 Address 和 Value/Mask。这两个分别是要初始化的寄存器地址,设置的值。
紧接着 DCD 的就是我们的程序生成的.bin 文件。至此关于 i.MX6ULL 镜像的组成格式我们就分析完成了。只是看上面的介绍大家也许感觉到会很枯燥,接下来我们结合 uboot.imx 镜像,来一起看看这些数据的组织格式。我们使用 winhex 软件(在光盘资料的“i.MX6UL 终结者光盘资料\02_开发所需软件”目录下面)打开光盘资料的“i.MX6UL 终结者光盘资料\06_开发板系统镜像\uboot\emmc\u-boot.imx”文件,如下图所示:
从上图可以看出是按照小端方式显示的,我们首先把前面 44 个字节按照 4 个字节一组的方式组合在一起就
是:0x402000D1,0x87800000,0x00000000,0x877FF42C,0x877FF420,0x877FF400,0x00000000,0x00000000。
这 8 组数据是 IVT 的数据,我们整理成下表:
然后是 Boot Data 域,我们把接下来的 12 个字节按照 4 个字节一组的方式组合在一起就是 0x877FF000,
0x0007E000,0x00000000。我们整理成下表所示:
从上面的表格我们可以看到 DCD 主要做了下面的配置:
1. 使能所有外设的时钟。
2. 配置 DDR3 所用的所有 IO。
3. 配置 MMDC 控制器,初始化 DDR3。
关于 i.MX6ULL 的启动流程和启动镜像文件格式我们就介绍到这里。通过本章的讲解我们可以掌握 i.MX6ULL的启动设置了。我们编译出的二进制.bin 文件,不能直接烧写到 EMMC 中,需要在它前面加上 IVT,Boot Data和 DCD 这三部分的数据域。我们之中烧写到 EMMC 的镜像文件时:IVT+Boot Data+CDC+用户的.bin 文件。