weiqi7777

基于S3C6410的ARM11学习(二) bootloader开发准备

0
阅读(2586)

程序之旅,首先就是要写bootloader。对于我们这种初学者来说,肯定是要去参考行业老大uboot的代码了。看看别人写的bootloader的流程是怎么样的。毕竟,ARM11STM32是不一样的,执行main函数之前的工作都需要自己写代码,而不像开发STM32,直接调用ST公司提供的启动start_up.S启动代码。

通过查资料以及看视频,最终得到下面这个uboot流程的思维导图。

视频的话,推荐国嵌的嵌入式linux视频。

clip_image002

程序阶段有两段,第一段程序是用汇编编写的,第二段是用C编写的。

上面是uboot的流程,我们,现在初学,就不用写那么复杂,把基本的代码编写即可。先实现简单的功能,能让板子跑起来,后面在扩展。

我给我写的这个bootloaderqboot

qboot-s3c6410

整个流程,就是这样。然后就按照这个流程,就可以开始编写代码了。

这里,给大家推荐这个思维导图的软件,Edram Mind Map

clip_image005

画个思维导图,整个流程都要清晰很多。

这里,在对比下STM32的开发

我们在使用STM32的时候,建立工程的第一步就是把对应芯片的启动代码给加入到工程中,这个启动代码,就实现了中断向量表的建立,时钟,NVIC,跳转到_main函数,对C语言环境进行设置,其实就是设置堆栈,将程序中的变量拷贝到ram中,这样才能对变量进行写了。最后跳转到我们写的main函数。可见在执行main函数之前的操作,启动代码都帮我们实现了。整个开发,我们不需要写任何一句汇编代码。

clip_image002

上面,就是一个启动代码的一个片段。也就是上电执行的一段代码。

这里,有一个

EXPORT Reset_Handler[WEAK]

可能很多人对这个语句有点疑惑。这个意思就是将Reset_Handler导出,这样外部就可以使用或者改写这个函数,但是我们知道,程序中,是不能有两个函数同名的,否则编译就会报错。所以这里后面就多了一个[WEAK],表示这个Reset_Handler系统自带函数是弱函数,当其他程序没有定义这个Reset_Handler函数时,就使用这个系统自带的函数。而当其他程序有定义这个Reset_Handler函数时,就使用外部定义的Reset_Handler函数,就把系统自带的这个函数给覆盖掉了。

先执行SystemInit函数。其实就是对时钟和NVIC进行初始化。然后跳转到_main。这个_main是看不到代码的。不过可以使用软件仿真,去看看这个_main函数的汇编代码。其实就是实现堆栈初始化,以及将变量拷贝到内存中。执行main函数。

以下是软件仿真去看_main函数。

clip_image004

可以看到_main的值是0x08000130。那么程序会跳转到0x08000130去执行。

clip_image006

去汇编代码查找0x08000130地址的代码,知道首先是要调用_scatterload函数。_scatterload函数地址是0x0800370c。去汇编代码看看,就是以下的代码,执行一些操作,这些操作我也没有去分析,因为用的不是ARM指令,而是THUMB指令。然后跳转到_main_after_scatterload标号去。_main_after_scatterload值是0x0800138。不就跳转到上图中的_main_after_scatterload地方去了。

clip_image007

然后然后就执行

LDRr0,[pc,#0];

PC指针是当前指令的下两条指令,所以这个时候PC指针的位置是0x0800013c。取出这个地址的值给r0,然后在跳转到r0数据的地址出,也就是跳转到0x01A7去。STM32使用的是THUMB2指令,指令有16位的。跳转地址最后一位为1的话,表示跳转到地址后,执行16位的指令,就相当于跳转到0x01A6地址去,当然前面还有0x0800。所以就是0x080001A6

然后我们在去看看这个0x080001A6地址指令,就是main函数地址。所以就跳转到main函数去了。


clip_image008

这样,就跳转到main函数来了。还可以发现,指令都是2字节对齐的,也就是16位的。

上述,就是STM32的启动流程了。这还是第一次这么底层的去了解STM32的底层启动。

Baidu
map