跟我一起学RT-Thread之IMX6ULL启动方式

IMX6ULL启动方式

  • 前言
  • 1.启动方式选择
    • 1.1.串行下载
    • 1.2.内部BOOT模式
  • 2.BOOT ROM初始化内容
  • 3.启动设备
  • 4.镜像烧写
    • 5.1.IVT和Boot Data
    • 5.2.DCD
  • 5.烧写软件源码解析
    • 5.1.源文件
    • 5.2.头文件
  • 6.代码地址重定向
    • 6.1.对IVT+Boot Data数据进行修改
    • 6.2.对链接地址进行修改
  • 7.总结

前言

I.MX6U 支持多种启动方式以及启动设备,比如可以从 SD/EMMC、 NAND Flash、 QSPI Flash
等启动。用户可以根据实际情况,选择合适的启动设备。不同的启动方式其启动方式和启动要求也不一样,比如从 SD卡启动就需要在 bin 文件前面添加一个数据头,其它的启
动设备也是需要这个数据头的。本章我们就来学习一下 I.MX6U 的启动方式,以及不同设备启动的要求。

1.启动方式选择

BOOT 的处理过程是发生在 I.MX6U 芯片上电以后,芯片上电复位后,就就会执行Boot Rom中的代码,会根据 BOOT_MODE[1:0]的设置来选择 BOOT 方式。

跟我一起学RT-Thread之IMX6ULL启动方式_第1张图片

BOOT_MODE[1:0]的值是可以改变的,有两种方式。

一种是改写 eFUSE(熔
丝),一种是修改相应的 GPIO 高低电平。第一种修改 eFUSE 的方式只能修改一次,后面就不能再修改了,所以我们不使用。我们使用的是通过修改 BOOT_MODE[1:0]对应的 GPIO 高低电平来选择启动方式,所有的开发板都使用的这种方式, I.MX6U 有一个 BOOT_MODE1 引脚和
BOOT_MODE0 引脚,这两个引脚对应这 BOOT_MODE[1:0]

跟我一起学RT-Thread之IMX6ULL启动方式_第2张图片

其中 BOOT_MODE1 和 BOOT_MODE0 在芯片内部是有 100KΩ下拉电阻的,所以默认是
0
。 BOOT_MODE1 和 BOOT_MODE0 这两个引脚我们也接到了底板的拨码开关上,这样我们就可以通过拨码开关来控制 BOOT_MODE1 和 BOOT_MODE0 的高低电平。

以 BOOT_MODE1
为例,当我们把 BOOT_CFG 的第一个开关拨到“ON”的时候,就相当于 BOOT_MODE1 引脚
通过 R88 这个 10K 电阻接到了 3.3V 电源,芯片内部BOOT_MODE1 又是 100K 下拉电阻接地,因此此时 BOOT_MODE1 的电压就是 100/(10+100)*3.3V= 3V,这是个高电平, 因此
BOOT_CFG 的中的 8 个开关拨到“ON”就是高电平,拨到“OFF”就是低电平。

而 I.MX6U 有四个 BOOT 模式,这四个 BOOT 模式由 BOOT_MODE[1:0]来控制,也就是
BOOT_MODE1 和 BOOT_MODE0 这两 IO 。

跟我一起学RT-Thread之IMX6ULL启动方式_第3张图片

1.1.串行下载

当 BOOT_MODE1 为 0, BOOT_MODE0 为 1 的时候此模式使能,串行下载的意思就是可
以通过 USB 或者 UART 将代码下载到板子上的外置存储设备中
,我们可以使用 OTG1 这个 USB
口向开发板上的 SD/EMMC、 NAND 等存储设备下载代码。我们需要将

BOOT_MODE1 拨到
“OFF”,将 BOOT_MODE0 拨到“ON”。这个下载是需要用到 NXP 提供的一个软件,一般用来最终量产的时候将代码烧写到外置存储设备中的。

1.2.内部BOOT模式

当 BOOT_MODE1 为 1, BOOT_MODE0 为 0 的时候此模式使能,在此模式下,芯片会执
行内部的 boot ROM 代码,这段 boot ROM 代码会进行硬件初始化(一部分外设),然后从 boot 设备(就是存放代码的设备、比如 SD/EMMC、 NAND)中将代码拷贝出来复制到指定的 RAM 中,
一般是 DDR 。

2.BOOT ROM初始化内容

当我们设置 BOOT 模式为“内部 BOOT 模式”以后, I.MX6U 内部的 boot ROM 代码就会
执行,这个 boot ROM 代码都会做什么处理呢?首先肯定是初始化时钟 。

跟我一起学RT-Thread之IMX6ULL启动方式_第4张图片

在图中 BT_FREQ 模式为 0,可以看到,boot ROM 会将 I.MX6U 的内核时钟设置为
396MHz, 也就是主频为 396Mhz。 System PLL=528Mhz, USB PLL=480MHz, AHB=132MHz,
IPG=66MHz。

内部 boot ROM 为了加快执行速度会打开 MMU 和 Cache,下载镜像的时候 L1 ICache 会打开,验证镜像的时候 L1 DCache、 L2 Cache 和 MMU 都会打开。一旦镜像验证完成, boot ROM
就会关闭 L1 DCache、 L2 Cache 和 MMU。

3.启动设备

当 BOOT_MODE 设置为内部 BOOT 模式以后,可以从以下设备中启动:

①、接到 EIM 接口的 CS0 上的 16 位 NOR Flash。

②、接到 EIM 接口的 CS0 上的 OneNAND Flash。

③、接到 GPMI 接口上的 MLC/SLC NAND Flash, NAND Flash 页大小支持 2KByte、 4KByte
和 8KByte, 8 位宽。

④、 Quad SPI Flash。

⑤、接到 USDHC 接口上的 SD/MMC/eSD/SDXC/eMMC 等设备。

⑥、 SPI 接口的 EEPROM。

这些启动设备如何选择呢? I.MX6U 同样提供了 eFUSE 和 GPIO 配置两种, eFUSE 就不讲
解了。我们重点看如何通过 GPIO 来选择启动设备,因为所有的 I.MX6U 开发板都是通过 GPIO
来配置启动设备的。正如启动模式由 BOOT_MODE[1:0]来选择一样,启动设备是通过 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
的启动选择引脚 。

跟我一起学RT-Thread之IMX6ULL启动方式_第5张图片

通过图中的 26 个启动 IO 即可实现 I.MX6U 从不同的设备启动, BOOT_MODE1 和
BOOT_MODE0 已经讲过了。看到这 24 个 IO 是不是头大?调整这 24 个 IO 的高低电平得多复杂啊?其实不然,虽然有 24 个 IO,但是实际需要调整的只有那几个IO,其它的IO全部下拉接地即可,也就是设置为 0。打开 I.MX6U-ALPHA 开发板的核心板原理图,这 24 个 IO 的默认设置如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FzWaGKuD-1612008200985)(upload\image-20210130183656858.png)]

可以看出在上图中大部分的 IO 都接地了,只有几个 IO 接高,尤其是 BOOT_CFG4[7:0]
这 8 个 IO 都 10K 电阻下拉接地,所以我们压根就不需要去关注 BOOT_CFG4[7:0]。我们需要
重点关注的就只剩下了 BOOT_CFG2[7:0]和 BOOT_CFG1[7:0]这 16 个 IO。这 16 个配置 IO 含
义在原理图的左侧已经贴出来了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4CMgqgAx-1612008200986)(upload\image-20210130183810817.png)]

看着是不是也很头大,BOOT_CFG1[7:0]和 BOOT_CFG2[7:0]这 16 个 IO 还能不能在减少呢?可以!打开 I.MX6U-ALPHA 开发板的底板原理图,底板上启动设备选择拨码开关原理图如下图所示:

跟我一起学RT-Thread之IMX6ULL启动方式_第6张图片

在上图中,除 了 BOOT_MODE1 和 BOOT_MODE0 必 须 引 出 来 ,
LCD_DATA3~LCDDATA7、 LCD_DATA11 这 6 个 IO 也被引出来了,可以通过拨码开关来设置其对应的高低电平,拨码开关拨到“ON”就是 1,拨到“OFF”就是 0。其中 LCD_DATA11 就
是 BOOT_CFG2[3], LCD_DATA3~LCD_DATA7 就是 BOOT_CFG1[3]~BOOT_CFG1[7],这 6 个
IO 的配置含义如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tZZb0GsJ-1612008200987)(upload\image-20210130184016984.png)]

根据表中的 BOOT IO 含义, I.MX6U-ALPHA 开发板从 SD 卡、 EMMC、 NAND 启动
的时候拨码开关各个位设置方式如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IkKBZS8p-1612008200988)(upload\image-20210130184059399.png)]

4.镜像烧写

前面我们设置好 BOOT 以后就能从指定的设备启动了,但是你的设备里面得有代码啊,我们使用 imxdownload这个软件将 led.bin 烧写到了 SD 卡中。imxdownload 会在 led.bin
前面添加一些头信息,重新生成一个叫做 load.imx 的文件,最终实际烧写的是 laod.imx。那么肯定就有人问: imxdownload 究竟做了什么? load.imx 和 led.bin 究竟是什么关系?我们就来详细的讲解一下 imxdownload 是如何将 led.bin 打包成 load.imx 的。

学习 STM32 的时候我们可以直接将编译生成的.HEX文件烧写到 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。

可以看出最终烧写到 I.MX6U 中的程序其组成为: IVT+Boot data+DCD+.bin。imxdownload 所生成的 load.imx 就是在 led.bin 前面加上 IVT+Boot data+DCD。

内部 Boot
ROM 会将 .bin 拷贝到 DDR 中
,用户代码是要一定要从 0X87800000 这个地方开始的,因为链接地址为 0X87800000(该地址可以修改), load.imx 在用户代码前面又有 3KByte 的 IVT+Boot Data+DCD 数
据,下面会讲为什么是 3KByte,因此 load.imx 在 DDR 中的起始地址就是 0X87800000-
3072=0X877FF400。

5.1.IVT和Boot Data

load.imx 最前面的就是 IVT 。 IVT 包含了镜像程序的入口点、指向 DCD 的指针和一些用作其它用途的指针。内部 Boot ROM 要求 IVT 应该放到指定的位置,不同的启动设备位置不同,而 IVT 在整个 load.imx 的最前面,其实就相当于要求 load.imx 在烧写的时候应该烧写到存储设备的指定位置去。整个位置都是相对于存储设备的起始地址的偏移。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nxFxqkpa-1612008200989)(upload\image-20210130185001759.png)]

以 SD/EMMC 为例, IVT 偏移为 1Kbyte, IVT+Boot data+DCD 的总大小为 4KByte-
1KByte=3KByte。假如 SD/EMMC 每个扇区为 512 字节,那么 load.imx 应该从第三个扇区开始烧写,前两个扇区要留出来。 load.imx 从第 3KByte 开始才是真正的.bin 文件。

那么 IVT 里面究竟存放着什么东西呢? IVT 里面存放的内容如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFZ6kdCI-1612008200990)(upload\image-20210130185117119.png)]

从上图可以看到,第一个存放的就是 header(头), header 格式如下图所示:

在上图中, Tag 为一个字节长度,固定为 0XD1, Length 是两个字节,保存着 IVT 长
度,为大端格式,也就是高字节保存在低内存中。最后的 Version 是一个字节,为 0X40 或者 0X41。

Boot Data 的数据格式如下图所示:

实际情况是不是这样的呢?我们用 winhex 软件打开 load.imx 一看便知。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bAzYUACC-1612008200992)(upload\image-20210130185447777.png)]

上图是我们截取的 load.imx 的一部分内容,从地址 0X00000000~0X000025F,共 608
个字节的数据。我们将前 44 个字节的数据按照 4 个字节一组组合在一起就是: 0X402000D1、
0X87800000、 0X00000000、 0X877FF42C、 0X877FF420、 0X877FF400、 0X00000000、 0X00000000、
0X877FF000、 0X00200000、 0X00000000。

这 44 个字节的数据就是 IVT 和 Boot Data 数据。

IVT 和 Boot Data 所对应的内容如下所示:

跟我一起学RT-Thread之IMX6ULL启动方式_第7张图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mdvkQcuG-1612008200993)(upload\image-20210130185800882.png)]

如上图所示,我们详细的列出了 load.imx 的 IVT+Boot Data 每 32 位数据所代表的意义。
这些数据都是由 imxdownload 这个软件添加进去的。

5.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 区域结构如下图所示:

跟我一起学RT-Thread之IMX6ULL启动方式_第8张图片

DCD 的 header 和 IVT 的 header 类似,结构如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SXoEgHe1-1612008200995)(upload\image-20210130190106167.png)]

其中 Tag 是单字节,固定为 0XD2, Length 为两个字节,表示 DCD 区域的大小,包含 header,
同样是大端模式, Version 是单字节,固定为 0X40 或者 0X41。

CMD 就是要初始化的寄存器地址和相应的寄存器值 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R0jeRZkr-1612008200995)(upload\image-20210130190147072.png)]

图中 Tag 为一个字节,固定为 0XCC。 Length 是两个字节,包含写入的命令数据长度,包含 header,同样是大端模式。 Parameter 为一个字节,这个字节的每个位含义如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RC05Y5Kp-1612008200996)(upload\image-20210130190236072.png)]

图中的 bytes 表示是目标位置宽度,单位为 byte,可以选择 1、 2、和 4 字节。 flags
是命令控制标志位。
图中的 Address 和 Vlalue/Mask 就是要初始化的寄存器地址和相应的寄存器值,注意采用的是大端模式! DCD 结构就分析到这里,在分析 IVT 的时候我们就已经说过了, DCD
数据是从图的 0X2C 地址开始的。根据我们分析的 DCD 结构可以得到 load.imx 的 DCD
数据下表所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SfwbLCum-1612008200996)(upload\image-20210130190356448.png)]

跟我一起学RT-Thread之IMX6ULL启动方式_第9张图片

从上图中可以看出, DCD 里面的初始化配置主要包括三方面:

①、设置 CCGR0~CCGR6 这 7 个外设时钟使能寄存器,默认打开所有的外设时钟。

②、配置 DDR3 所用的所有 IO。

③、配置 MMDC 控制器,初始化 DDR3。

1.总结一下,我们编译出来的.bin 文件不能直接烧写到 SD 卡中,需要在.bin 文件前面加上 IVT、 Boot Data 和 DCD 这三个数据块。这三个数据块是有指定格式的,
我们必须按照格式填写,然后将其放到.bin 文件前面,最终合成的才是可以直接烧写到 SD 卡
中的文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yrpN0VWs-1612008200997)(upload\image-20210130191804211.png)]

2.随着工程代码量的增加,如果镜像大小超过了2MB,一定要对Boot Data数据结构中的Length进行修改,否则会出现问题。

3.这一点非常重要:Boot rom中的代码当检测到SD卡就是启动设备之后,就会将image文件全部拷贝到指定的DDR3内存地址中,image文件的大小就是红色箭头所指向的内容。千万要注意,镜像文件的起始地址加上镜像文件的大小要介于DDR3的内存地址之间,对于ALPHA开发板来说,DDR3内存地址大小范围位0X8000 0000 ~ 0X9FFFF FFFF 。

5.烧写软件源码解析

先上源码

5.1.源文件

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "imxdownload.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_TAB		0	
/*
 * 介绍: 此软件是针对NXP的IMX6U系列芯片的,软件用来烧写bin文件到SD卡里面,
 *        本软件会自动添加IVT、DCD等信息到原始的bin文件里面,主要用于裸机和uboot的烧写。
 * 使用方法: 1、编译好原始的二进制bin文件,如,u-boot.bin等,并将编译好的.bin文件和本
 *             软件放置到同一个目录下!!!!
 *        	2、执行命令sudo ./imxdownload  
 *             如烧写u-boot.bin到/dev/sdd中即可使用如下所示命令:
 *             sudo ./imxdownload u-boot.bin /dev/sdd
 */

/*
 * 输出一些信息
 */
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>  \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("Can't 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("Cant't 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;	
}

5.2.头文件

#ifndef _IMXDOWNLOAD_H
#define _IMXDOWNLOAD_H
/* 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,
};

#endif

这个烧写软件的逻辑很简单,一句话概括就是:在bin文件前面添加头部信息

比较麻烦的就是这个头文件里面的16进制数据,我们要对相关的寄存器进行配置,要知道它的地址还有要配置的值,并且还是大端模式。如果想自己去配置一个新的开发板的头部数据,真的会非常麻烦。

6.代码地址重定向

如果要实现代码重定向,只需要实现如下两个步骤。

6.1.对IVT+Boot Data数据进行修改

IVT+Boot Data数据总共就44个字节。就是镜像文件的前44个字节。

如上图所示

我们只需要对其中红色箭头所指向的数据进行修改,不同数据之间的关系在镜像烧写那节已经说明了。

6.2.对链接地址进行修改

跟我一起学RT-Thread之IMX6ULL启动方式_第10张图片

红色箭头所指向的文件不知道大家有没有关注过。

我们来看看要对这个文件中的什么内容进行修改

跟我一起学RT-Thread之IMX6ULL启动方式_第11张图片

我们只需要对红色箭头所指向的bin文件起始地址进行修改就可以了。

7.总结

本篇博文主要对IMX6ULL的启动方式进行了详细的解答,并对正点原子的代码烧写工具进行了解析,代码的逻辑很简单,就是头文件里的数据要花很多的时间去做。代码地址重定向也非常重要,特别需要注意的是:Boot rom中的代码当检测到SD卡就是启动设备之后,就会将image文件全部拷贝到指定的DDR3内存地址中,image文件的大小就是红色箭头所指向的内容。千万要注意,镜像文件的起始地址加上镜像文件的大小要介于DDR3的内存地址之间,对于ALPHA开发板来说,DDR3内存地址大小范围位0X8000 0000 ~ 0X9FFFF FFFF 。
还有一个非常重用的知识点,这个是正点原子讲授出错的地方,boot rom里面的代码并不是把整个镜像文件拷贝到DDR3中,而是把.bin文件拷贝到DDR3中。

你可能感兴趣的:(RTT,物联网,IMX6ULL)