i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

厌伴老儒烹瓠叶,强随举子踏槐花。这篇文章主要讲述i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式相关的知识,希望能为你提供帮助。


一、i.MX6ULL启动方式 1. 启动代码Boot CodeBoot ROM是i.MX6ULL芯片内部的一小段存储空间,用于存放Boot Code(启动代码),i.MX6ULL芯片上电之后(Power-On Reset,POR)永远会执行?Boot ROM中存放的启动代码?。
boot code 使用内部寄存器BOOT_MODE[1:0]的值、eFUSEs配置、相关GPIO电平配置来决定启动流程。
boot code的特性如下:


  • 支持从多种boot devices启动
  • 支持串行下载(USB OTG或者UART)
  • 支持DCD(Device Configuration Data,用来配置启动设备的参数)
  • 支持基于HAB(High-Assurance Boot)的数字签名和解密
  • 支持从低功耗模式唤醒

2. 启动过程的干预i.MX6ULL的启动过程非常复杂:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

其实启动流程中的一些选择项是取决于寄存器的,寄存器的值改变方式主要有两种:

  • eFuse:熔丝方式,这种方式只能烧录一次,适用于量产产品时使用;
  • GPIO:GPIO电平方式,在启动时利用相应GPIO读取电平,启动后恢复普通引脚

3. 启动模式选择(Boot Mode)i.MX6ULL有四个启动模式,如下表,具体使用哪种启动模式通过内部寄存器 BOOT_MODE 中的值来选择,如图:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

只不过?在上电时,芯片对BOOT_MODE0引脚和BOOT_MODE1引脚采样?,获得 BOOT_MODE 寄存器的初始值,通过该寄存器决定?启动代码下一步的行为?:

  • Boot From Fuses:根据Fuses中的配置来选择外部存储器
  • Serial Downloader:开始等待用户通过串口/USB接口下载程序
  • Internal Boot:继续执行启动代码,并根据用户GPIO引脚配置来选择外部存储器

在采样完成之后,BOOT_MODE0和BOOT_MODE1引脚的电平不会对BOOT_MODE寄存器的值产生影响。
4.外部启动设备配置(Boot Devices)当启动模式选择为Internal Boot后,boot code进入下一步:从用户选择的启动设备加载镜像文件。
4.1. 启动设备选择
i.MX6ULL支持的外部启动设备非常多,如下:

  • Nor Flash
  • Nand Flash
  • OneNand Flash
  • SD/MMC/
  • 串行Nor Flash(SPI)/EEPROM
  • QuadSPI(QSPI)Flash

用户通过设置 ?BOOT_CFG1[7:4]? 的值来选择使用哪种类型的设备,如图:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

针对这个复杂的表,原子的教程中总结出了一个表,并指出了寄存器位与GPIO引脚的对应:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

本文中我所使用的i.MX6ULL开发板,启动配置拨码开关的原理图如下:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

拨码开关不同的设置对应的启动设备如下:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

4.2. 启动设备属性配置
在访问每种外部存储器设备时,都需要配置一些基本参数,比如位宽、工作频率、访问时序等必要参数,i.MX6ULL针对每种存储器设备都提供了配置方式。该部分内容较多,可以在参考手册中查看。
除了使用 eFUSEs和GPIO配置两种方式外,还支持 ?DCD配置?,DCD是程序镜像中包含的一些配置信息,用来配置外设的参数,比较灵活。
5. 串行下载除了正常启动外,启动代码的串行下载模式还?支持通过串口/USB接口接收PC端上位机工具(mfgtool)发送的程序镜像?,适用于量产产品时的程序烧录。
二、i.MX6ULL镜像格式i.MX6ULL对加载的用户程序镜像有要求,由以下内容组成:

  • Image vector table(IVT):位于固定地址的指针列表,ROM检查它以确定程序映像的其他组件位于何处;
  • Boot data:指出程序镜像位置、以字节为单位的程序镜像大小和插件标志的一张表;
  • Device configuration data(DCD):IC配置数据,比如DDR的初始化配置;
  • User code and data:用户代码和数据,比如用户编译出的普通bin文件。

1. Image vector table映像向量表(Image Vector Table, IVT)是ROM Code从启动设备读取的数据结构,该设备提供包含执行成功启动所需的数据组件的程序映像。
IVT包括程序镜像入口地址、DCD指针和其它指针:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

ROM Code 从不同启动设备的?固定地址?加载IVT,每个启动设备类型的IVT从基地地址偏移量和初始加载区域大小在下表中定义:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

IVT的格式如下,每个entry都是32-bit:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

其中IVT header的格式如下:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

2. Boot databoot data必须遵从下面的格式,每个entry 32bit:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

3. Device configuration data(DCD)DCD是包含在程序映像(ROM外部)中的配置信息,ROM code解析该数据来配置芯片上的各种外围设备。
ROM Code根据位于IVT中的信息确定DCD表的位置,下图所示的DCD表是允许的DCD命令的大端字节数组,DCD最大限制为1768B。
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

DCD Header的格式如下,占用4个字节:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

DCD命令有Write data command、Check data command、NOP command、Unlock command,这里不做展开,有兴趣可以查看IMX6ULLRM文档8.7.2章节。
4. imx格式镜像生成imx格式镜像就是在普通镜像的基础上,添加IVT+Boot data+DCD,左神写了一个小工具,直接将官方uboot.imx文件的头部信息读出来,然后添加到我们自己的镜像中去,还是很好用的。
5. 文件烧写到sd卡中将生成的imx格式镜像使用dd命令烧写到sd中即可,左神的小工具中一起写了。
三、imxdownload工具


工具作者:左忠凯。


1. 源码imxdownload.c:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#define SHELLCMD_LEN(200)
#define BIN_OFFSET(3072)

/* 此宏指明是否打印u-boot.imx的IVT DCD表信息,不同的开发板其IVT和DCD
* 表的数据是不同的,因此需要获取所使用的开发板的IVT和DCD表信息,最
* 简单的方法就是读取开发板配套资料里面的u-boot.imx的前1KB数据,理论上
* 应该读取3KB的数据,但是表信息远远没有3K这么多,因此读1KB即可
*/
#define PRINT_TAB0
/*
* 介绍: 此软件是针对NXP的IMX6U系列芯片的,软件用来烧写bin文件到SD卡里面,
*本软件会自动添加IVT、DCD等信息到原始的bin文件里面,主要用于裸机和uboot的烧写。
* 使用方法: 1、编译好原始的二进制bin文件,如,u-boot.bin等,并将编译好的.bin文件和本
*软件放置到同一个目录下!!!!
*2、执行命令sudo ./imxdownload < soucre_bin> < sd_device>
*如烧写u-boot.bin到/dev/sdd中即可使用如下所示命令:
*sudo ./imxdownload u-boot.bin /dev/sdd
*/

/* IMX6U IVT DCD表信息暂时定义为1K Bytes,此表是读取的u-boot.imx前1K Bytes
* imx6_ivedcd_table[9]是指明代码长度的,本应该根据实际的代码长度来修改
* 这里为了方便,就直接定义为2M Bytes,即
*/

const int imx6_512mb_ivtdcd_table[256] =
0X402000D1,0X87800000,0X00000000,0X877FF42C,0X877FF420,0X877FF400,0X00000000,0X00000000,
0X877FF000,0X00200000,0X00000000,0X40E801D2,0X04E401CC,0X68400C02,0XFFFFFFFF,0X6C400C02,
0XFFFFFFFF,0X70400C02,0XFFFFFFFF,0X74400C02,0XFFFFFFFF,0X78400C02,0XFFFFFFFF,0X7C400C02,
0XFFFFFFFF,0X80400C02,0XFFFFFFFF,0XB4040E02,0X00000C00,0XAC040E02,0X00000000,0X7C020E02,
0X30000000,0X50020E02,0X30000000,0X4C020E02,0X30000000,0X90040E02,0X30000000,0X88020E02,
0X30000C00,0X70020E02,0X00000000,0X60020E02,0X30000000,0X64020E02,0X30000000,0XA0040E02,
0X30000000,0X94040E02,0X00000200,0X80020E02,0X30000000,0X84020E02,0X30000000,0XB0040E02,
0X00000200,0X98040E02,0X30000000,0XA4040E02,0X30000000,0X44020E02,0X30000000,0X48020E02,
0X30000000,0X1C001B02,0X00800000,0X00081B02,0X030039A1,0X0C081B02,0X0B000300,0X3C081B02,
0X44014801,0X48081B02,0X302C4040,0X50081B02,0X343E4040,0X1C081B02,0X33333333,0X20081B02,
0X33333333,0X2C081B02,0X333333F3,0X30081B02,0X333333F3,0XC0081B02,0X09409400,0XB8081B02,
0X00080000,0X04001B02,0X2D000200,0X08001B02,0X3030331B,0X0C001B02,0XF3526B67,0X10001B02,
0X630B6DB6,0X14001B02,0XDB00FF01,0X18001B02,0X40172000,0X1C001B02,0X00800000,0X2C001B02,
0XD2260000,0X30001B02,0X23106B00,0X40001B02,0X4F000000,0X00001B02,0X00001884,0X90081B02,
0X00004000,0X1C001B02,0X32800002,0X1C001B02,0X33800000,0X1C001B02,0X31800400,0X1C001B02,
0X30802015,0X1C001B02,0X40800004,0X20001B02,0X00080000,0X18081B02,0X27020000,0X04001B02,
0X2D550200,0X04041B02,0X06100100,0X1C001B02,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000
;

const int imx6_256mb_ivtdcd_table[256] =
0X402000D1,0X87800000,0X00000000,0X877FF42C,0X877FF420,0X877FF400,0X00000000,0X00000000,
0X877FF000,0X00076000,0X00000000,0X40E801D2,0X04E401CC,0X68400C02,0XFFFFFFFF,0X6C400C02,
0XFFFFFFFF,0X70400C02,0XFFFFFFFF,0X74400C02,0XFFFFFFFF,0X78400C02,0XFFFFFFFF,0X7C400C02,
0XFFFFFFFF,0X80400C02,0XFFFFFFFF,0XB4040E02,0X00000C00,0XAC040E02,0X00000000,0X7C020E02,
0X30000000,0X50020E02,0X30000000,0X4C020E02,0X30000000,0X90040E02,0X30000000,0X88020E02,
0X30000C00,0X70020E02,0X00000000,0X60020E02,0X30000000,0X64020E02,0X30000000,0XA0040E02,
0X30000000,0X94040E02,0X00000200,0X80020E02,0X30000000,0X84020E02,0X30000000,0XB0040E02,
0X00000200,0X98040E02,0X30000000,0XA4040E02,0X30000000,0X44020E02,0X30000000,0X48020E02,
0X30000000,0X1C001B02,0X00800000,0X00081B02,0X030039A1,0X0C081B02,0X04000000,0X3C081B02,
0X3C013C01,0X48081B02,0X38324040,0X50081B02,0X28304040,0X1C081B02,0X33333333,0X20081B02,
0X33333333,0X2C081B02,0X333333F3,0X30081B02,0X333333F3,0XC0081B02,0X09409400,0XB8081B02,
0X00080000,0X04001B02,0X2D000200,0X08001B02,0X3030331B,0X0C001B02,0XF352433F,0X10001B02,
0X630B6DB6,0X14001B02,0XDB00FF01,0X18001B02,0X40172000,0X1C001B02,0X00800000,0X2C001B02,
0XD2260000,0X30001B02,0X23104300,0X40001B02,0X47000000,0X00001B02,0X00001883,0X90081B02,
0X00004000,0X1C001B02,0X32800002,0X1C001B02,0X33800000,0X1C001B02,0X31800400,0X1C001B02,
0X30802015,0X1C001B02,0X40800004,0X20001B02,0X00080000,0X18081B02,0X27020000,0X04001B02,
0X2D550200,0X04041B02,0X06100100,0X1C001B02,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
;



/*
* 输出一些信息
*/
void message_print(void)

printf("I.MX6ULL bin download software\\r\\n");
printf("Edit by:zuozhongkai\\r\\n");
printf("Date:2019/6/10\\r\\n");
printf("Version:V1.1\\r\\n");
printf("log:V1.0 initial version,just support 512MB DDR3\\r\\n");
printf("V1.1 and support 256MB DDR3\\r\\n");


int main(int argc, char *argv[])

FILE *fp;
unsigned char *buf;
unsigned char *cmdbuf;
int nbytes, filelen;
int i = 0, j = 0;
int ddrsize = 0; /* 0为512MB,1为256MB,2为128MB...... */

message_print();

if((argc != 3) & & (argc != 4))
printf("Error Usage! Reference Below:\\r\\n");
printf("sudo ./%s < -512m or -256m> < source_bin> < sd_device> \\r\\n", argv[0]);
return -1;


/* 查找参数,获取DDR容量 */
for(i = 0; i < argc; i++)

char *param = argv[i];
if(param[0] != -)
continue;
if(strcmp(param, "-256m") == 0)/* 256MB */
ddrsize = 1;
else if(strcmp(param, "-512m") == 0)/* 512MB */
ddrsize = 0;

if(argc == 3) /* 三个参数,也就是不输入DDR容量的话默认为512MB */
ddrsize = 0;

/* 打开bin文件 */
fp = fopen(argv[1], "rb"); /* 以二进制只读方式打开bin文件 */
if(fp == NULL)
printf("Cant Open file %s\\r\\n", argv[1]);
return -1;


/* 获取bin文件长度 */
fseek(fp, 0L, SEEK_END);
filelen = ftell(fp);
fseek(fp, 0L, SEEK_SET);
printf("file %s size = %dBytes\\r\\n", argv[1], filelen);

/* 读取bin文件到缓冲区buf中 */
buf = malloc(filelen + BIN_OFFSET);
if(buf == NULL)
printf("Mem Malloc Failed!\\r\\n");
fclose(fp);
return -1;

memset(buf, 0, filelen + BIN_OFFSET); /* 清零 */
/* 读取bin源码文件 */
fread(buf + BIN_OFFSET, 1, filelen, fp);

/* 关闭文件 */
fclose(fp);

#if PRINT_TAB
printf("IVT DCD Table:\\r\\n");
for(i = 0; i < 1024/32; i++)
for(j = 0; j < 8; j++)

printf("0X%08X,",*(int *)(buf + BIN_OFFSET + (((i * 8) + j) * 4)));

printf("\\r\\n");

free(buf);
return 0;
#endif

/* 添加IVT DCD等表信息到bin文件里面 */
if(ddrsize == 0)/* 512MB */
printf("Board DDR SIZE: 512MB\\r\\n");
memcpy(buf, imx6_512mb_ivtdcd_table, sizeof(imx6_512mb_ivtdcd_table));

else if (ddrsize == 1)/* 256MB */
printf("Board DDR SIZE: 256MB\\r\\n");
memcpy(buf, imx6_256mb_ivtdcd_table, sizeof(imx6_256mb_ivtdcd_table));


/* 现在我们已经在buf中构建好了可以用于下载的bin文件,将buf中的数据保存到
* 到一个文件中,文件命名为load.imx
*/
printf("Delete Old load.imx\\r\\n");
system("rm -rf load.imx"); /* 先删除旧的load.imx文件*/

printf("Create New load.imx\\r\\n");
system("touch load.imx"); /* 创建新的load.imx文件*/
fp = fopen("load.imx", "wb"); /* 打开laod.imx*/
if(fp == NULL)
printf("Cantt Open load.imx!!!\\r\\n");
free(buf);
return -1;

nbytes = fwrite(buf, 1, filelen + BIN_OFFSET, fp);
if(nbytes != (filelen + BIN_OFFSET))
printf("File Write Error!\\r\\n");
free(buf);
fclose(fp);
return -1;

free(buf);
fclose(fp);

/* 构建烧写的shell命令 */
cmdbuf = malloc(SHELLCMD_LEN);
sprintf(cmdbuf, "sudo dd iflag=dsync oflag=dsync if=load.imx of=%s bs=512 seek=2",argv[2]);
printf("Download load.imx to %s......\\r\\n", argv[2]);

/* 执行上面的shell命令 */
system(cmdbuf);
free(cmdbuf);
return 0;

2. 编译
gcc imxdownload.c -o imxdownload

3. 使用方法
sudo ./imxdownload < -512m or -256m> < source_bin> < sd_device>

推荐在usr/local/bin 文件夹下建立软链接,后续可以直接使用imxdownload命令:
sudo ln -s ~/imx6ull/tools/imxdownload/imxdownload /usr/local/bin/imxdownload

i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片

测试一下:
i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式

文章图片



【i.MX6ULL开发笔记 | 02 - i.MX6ULL启动方式与镜像格式】


    推荐阅读