I.MAX6ULL启动流程

目录

前言

一、原理

1、源码编译

2、I.MX6ULL镜像文件

二、实现过程

1、源码编写

2、源码编译

3、镜像文件制作、烧写、运行

参考资料


前言

I.MAX6ULL是一款NXP出品的,528~900MHz的Cortex-A7内核的MPU

一、原理

1、源码编译

一个工程中肯定有很多的.c源文件和.s汇编文件,要想让这些文件在I.MAX6ULL芯片上能运行起来是需要经历一系列过程的,如下图,中间还经历了预处理、编译、汇编、链接几个过程。

 

其中链接是将众多的.o目标文件(芯片可认识的二进制文件)文件链接到一个指定的链接位置(运行地址)上去,然后生成一个可运行的可执行文件。我的理解就是汇编只是将源文件转换成了芯片可识别的二进制文件,这些二进制数据要想在芯片上运行,肯定还得在芯片运行的地址上才行啊,这样芯片才能挨个去执行。就好比一个小孩在一个大桌子上吃饭,桌子上面很多菜他都知道是可以吃的,但是他够不着啊,只能够着自己碗里的,没办法想吃就只能让大人帮他把菜夹到他的碗里。链接就是将将菜(二进制文件)夹到小孩碗里(跟运行地址关联起来)的过程。

这里要说明下两个概念:

“存储地址”:就是可执行文件存储的地方。在STM32单片机中,就是单片机的内部FLASH,地址从0x08000000开始的。但是I.MAX6ULL中,这个存储地址可以随意选择的,虽然I.MAX6ULL内部有96K的ROM,但是这 96K的ROM是 NXP自己用的,不向用户开放。所以相当于说I.MAX6ULL没有内部FLASH,但是I.MAX6ULL支持将代码存储到NAND、SD卡、EMMC等这些外部存储器中。

“运行地址(链接地址)”:代码运行的时候所处的位置,在STM32中,运行地址就是代码的存储起始地址,都是丛0x08000000开始的。在I.MX6ULL中,可以在内部 128KB RAM中(0x900000~0x91FFFF),也可以在外部的 DDR(0x80000000开始)中。

2、I.MX6ULL镜像文件

经过上述过程得到一个.bin的可执行文件,直接将其烧写到指定的存储位置后就可以运行起来了吗?不是的!!!根据NXP的规定,还必须在bin文件的头部添加一些信息。因为在选择了内部BOOT模式启动的时候,芯片会执行内部的 boot ROM代码,这段 boot ROM代码会初始化CPU、时钟等,初始化内存(一般是DDR),初始化启动设备比如 SD、EMMC、NAND,从启动设备上把程序读入内存,运行内存的程序。添加的头部信息就是boot ROM运行所需的配置信息,这样boot ROM才能正确的将代码拷贝到指定的RAM中。综上所述:还需要在bin文件中添加一些头部信息组成一个镜像文件,才能再烧到启动设备中去。

这个头部信息包含哪些内容呢?图镜像文件的组成如下图所示:

I.MAX6ULL启动流程_第1张图片

注意:IVT中的地址信息都是Dest Memory的地址,而不是启动设备中地址

(1) IVT(Image vector table):IVT里面包含了一系列的地址信息,这些地址信息在ROM中按照固定的地址存放着。boot ROM 程序会根据这些地址来确定镜像文件中其他部分在哪里。格式如下:

I.MAX6ULL启动流程_第2张图片

IVT中个字段含义如下:

字段

说明

header

包含了tag 、 l ength 、 version 。 length 表示IVT的大小,它是32字节。要注意是的,它是大字节序的

entry

应用程序的链接地址,就是应用程序被复制到内容的哪里

dcd

镜像文件被复制到内存以后,DCD数据的地址

boot data

镜像文件被复制到内存以后,Boot data数据的地址

self

镜像文件被复制到内存以后,IVT自己所处的地址

(2) Boot data(启动数据):包含了镜像文件要拷贝到哪个地址,拷贝的大小是多少

Boot data中个字段含义如下:

字段

说明

start

映像文件在内存中的地址,它不等IVT在内存中的地址(IVT中self字段)。比如IVT被保存在启动设备SD卡1024偏移地址处,IVT被复制到内存地址 0x87000000那么 start= 0x87000000-1024 。boot ROM会把启动设备开头的数据也复制到内存中去,而不仅仅是从IVT开始复制

length

保存在启动设备上的整个镜像文件长度+镜像文件相对启动设备开始地址的偏离长度

plugin

插件,boot ROM支持有限的启动设备。用于设置支持更多的启动设备

(3) DCD(设备配置数据):设备配置信息,其实就是 I.MX6U寄存器地址和对应的配置信息集合,Boot ROM会使用这些寄存器地址和配置集合来初始化相应的寄存器,比如开启某些外设的时钟、初始化 DDR等等。命令格式如下:

I.MAX6ULL启动流程_第3张图片

(4) Application:用户的应用程序,也就是上面生成的bin文件

以上4 部分内容合并成为一个映像文件,烧写在 EMMC 、SD 卡或TF卡等启动设备的某个固定地址,bootROM 程序去这个固定地址读出映像文件。启动设备不同,固定地址不同,如下图:

I.MAX6ULL启动流程_第4张图片

 

I.MAX6ULL启动流程_第5张图片

二、实现过程

假如有main.c、start.s、两个源文件,在main.c中中调用了初始化LED灯控制LED闪烁,start.s初始化C语言运行环境。那么上述过程是怎么实现的呢?这里以正点原子的I.MA6ULL开发板点灯例程说明

1、源码编写

第一步:使用汇编初始化C语言运行环境,也就是初始化SP指针,因为C语言中的函数调用涉及到出栈入栈,出栈入栈就要对堆栈进行操作,这里就是开辟一段RAM用作栈并将SP指针指向这块内存。因为I.MX6ULL的内部RAM是不开放给用户的,所以SP指向的是片外的DDR,而DDR已经在boot ROM中初始化了,所以不需要初始化DDR了,否则还需要初始化DDR。

start.s启动文件:

.global _start  		/* 全局标号 */

/*
 * 描述:	_start函数,程序从此函数开始执行,此函数主要功能是设置C
 *		 运行环境。
 */
_start:

	/* 进入SVC模式 */
	mrs r0, cpsr		/*将特殊寄存器CPSR里面的数据复制到 R0中。*/
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x13 	/* r0或上0x13,表示使用SVC模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/

	ldr sp, =0X80200000	/* 设置栈指针			 */
	b main				/* 跳转到main函数 		 */

第二步I.MX6ULL    IO 初始化、控制

  • ①、使能时钟:CCGR0~CCGR6这7个寄存器控制着6ULL所有外设时钟的使能。为了简单,设置 CCGR0~CCGR6这7个寄存器全部为0XFFFFFFFF,相当于使能所有外设时钟。
  • ②、IO复用:将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的bit3~0设置为0101=5,这样GPIO1_IO03就复用为GPIO。
  • ③、寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03是设置GPIO1_IO03的电气属性。包括压摆率、速度、驱动能力、开漏、上下拉等。
  • ④、配置GPIO功能,设置输入输出。设置GPIO1_DR寄存器bit3为1,也就是设置为输出模式。设置GPIO1_DR寄存器的bit3,为1表示输出高电平,为0表示输出低电平。

2、源码编译

1、arm-linux-gnueabihf-gcc 将源文件编译成.o的目标文件

2、arm-linux-gnueabihf-ld 将众多的.o文件链接到一个指定的链接位置

3、arm-linux-gnueabihf-objcopy 格式转换,需要将led.elf文件转换成led.bin文件

4、 arm-linux-gnueabihf-objdump 反汇编,将elf链接后的文件反汇编成汇编代码以便调试代码

//-g选项是产生调试信息 GDB能够使用这些调试信息进行代码调试。
//-c选项是编译源文件,但是不链接。
//-o选项是指定编译产生的文件名字
arm-linux-gnueabihf-gcc -g -c led.s -o led.o 

//-Ttext选项就是指定链接地址,0x87800000是外部DDR中的地址
//-o选项指定链接生成的elf文件名
arm-linux-gnueabihf-ld -Ttext 0x87800000 led.o -o led.elf

//-O选项指定以什么格式输出,后面的 binary表示以二进制格式输出
//-S表示不要复制源文件中的重定位信息和符号信息
//-g表示不复制源文件中的调试信息
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin

//-D选项表示反汇编所有的段,反汇编完成以后就会在当前目录下出现一个名为led.dis文件
arm-linux-gnueabihf-objdump -D led.elf > led.dis

3、镜像文件制作、烧写、运行

使用正点原子的 “imxdownload” 软件可以将编译出来的bin文件制作成一个镜像文件然后烧写到SD卡中。过程为:

第一步:将SD卡通过读卡器插到电脑的USB上,然后连接到Ubuntu下

第二步:给予 imxdownload可执行权限

I.MAX6ULL启动流程_第6张图片

 

第三步:在电脑的Ubuntu下将执行imxdownload软件完成烧写

格式:./imxdownload <.bin file> 

执行命令:./imxdownload ledc.bin /dev/sdb

I.MAX6ULL启动流程_第7张图片

第四步:将SD卡从电脑拔出插入到开发板的TF卡槽中,复位开发板,就会看见小灯欢快的闪起来了

 

参考资料

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.3》

《嵌入式Linux应用开发完全手册第2版_韦东山全系列视频文档全集》

 

 

 

你可能感兴趣的:(Linux)