arm电子相册项目——启动加载篇startup.s

《arm电子相册项目——启动加载篇startup.s》

 

工具:keil4 , arm开发板(Mini2451)(s3c2451) , 串口线

功能:显示照片(自动切换 / 手动切换 / 暂停切换)

            显示时钟(精确显示 / 可设置)

进度:第1篇——startup.s

描述:启动开发板最先运行的是这段汇编程序,通过这段启动代码设置异常向量表,关闭看门狗,设置中断允许,跳转到main函数

    AREA Init , CODE , READONLY    ;定义一个代码段,只读。格式:AREA 段名,属性1,属性2
 
	PRESERVE8    ;8位对齐
	ENTRY    ;汇编程序入口点

start    ;启动代码中设置异常向量表
	b reset    ;重启异常
	b halt
	b halt
	b halt
	b halt
	b halt
	b _irq    ;中断异常
	b halt

reset
	ldr r0,=0x53000000    ;r0中放地址
	ldr r1,=0x0    ;r1中放值
        str r1,[r0]    ;将r1中的值,赋值给r0的地址中去(关闭看门狗)
	
	ldr sp,=(0x32000000+0x100000)    ;设置栈指针
	mov r0,#0x53
	msr CPSR_cxsf,r0    ;设置ARM9的工作模式和中断允许
	
	IMPORT clock_init    ;声明,启动时加载clock_init函数
	IMPORT Main    ;声明,在汇编中可以调用c函数
	
	bl clock_init    ;启动时加载clock_init函数(设置晶振最高800M)
	bl Main    ;从汇编跳转到c函数,接下来都用c语言写,易读,移植性好
	
	EXPORT delay    ;声明,c函数可以调用汇编中delay
	
delay    ;延时
	ldr r0,=0x1000000    ;赋初值,让其自减
delay_loop
	cmp r0,#0    ;比较是否等于0
	sub r0,r0,#1    ;自减算法
	bne delay_loop    ;若不等于0,就跳转到delay_loop继续,类似于c循环
	mov pc,lr    ;当等于0时跳出,跳转到原来调用delay时的位置

halt
	b halt    ;当是其它异常时,循环(无视其它异常,不处理)

_irq

	ldr sp,=(0x31000000 + 0x100000)    ;设置栈指针
	stmdb sp!,{r0-r12,lr}    ;入栈
	IMPORT do_irq    ;声明,汇编可以调用c函数
	bl do_irq    ;跳转到中断函数
	ldmia sp!,{r0-r12,pc}^    ;出栈(有点类似保护/恢复现场的意思)
	
END    ;和ENTRY相对应,结束标志。


以上代码是做arm电子相册的时候写的,刚开始也就是懵懵懂懂写着,做完了之后准备整理一遍,加深自己的理解,同时也做一个分享。

 

1.BootLoader(启动装载)

系统启动前引导程序

在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。在一个基于ARM7TDMI core的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。

Bootloader启动大多数都分为两个阶段。第一阶段主要包含依赖于CPU的体系结构硬件初始化的代码,通常都用汇编语言来实现。这个阶段的任务有:

基本的硬件设备初始化(屏蔽所有的中断、关闭处理器内部指令/数据Cache等)。

为第二阶段准备RAM空间。

如果是从某个固态存储媒质中,则复制Bootloader的第二阶段代码到RAM。

设置堆栈。

在第一阶段中为什么要关闭Cache?通常使用Cache以及写缓冲是为了提高系统性能,但由于Cache的使用可能改变访问主存的数量、类型和时间,因此Bootloader通常是不需要的。

跳转到第二阶段的C程序入口点。

第二阶段通常用C语言完成,以便实现更复杂的功能,也使程序有更好的可读性和可移植性。这个阶段的任务有:

初始化本阶段要使用到的硬件设备。

检测系统内存映射。

将内核映像和根文件系统映像从Flash读到RAM。

为内核设置启动参数。

调用内核。

 

2.AREA

语法格式:

AREA 段名 属性1,属性2,……

AREA伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“|”括起来,如|1_test|。

属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:

— CODE属性:用于定义代码段,默认为READONLY。

— DATA属性:用于定义数据段,默认为READWRITE。

— READONLY属性:指定本段为只读,代码段默认为READONLY。

— READWRITE属性:指定本段为可读可写,数据段的默认属性为READWRITE。

— ALIGN属性:使用方式为ALIGN 表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。

— COMMON属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元。

一个汇编语言程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段。

使用示例:

AREA Init,CODE,READONLY

指令序列

;该伪指令定义了一个代码段,段名为Init,属性为只读

 

3. ENTRY

语法格式:

ENTRY

ENTRY伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个ENTRY(也可以有多个,当有多个ENTRY时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个ENTRY(可以没有)。

使用示例:

AREA Init,CODE,READONLY

ENTRY ;指定应用程序的入口点

……

 

4.为什么ARM汇编程序前要加PRESERVE8?

这是字节对齐关键词,以前用ADS编译器的时候可以不用,但是后来的keil编译器时需要加上(譬如用周立功模板时,将ADS工程转到keil工程时就必须加上)。require8和preserve8,c和汇编有8位对齐的要求,这两个伪指令可以满足此要求,另外,REQUIRE8和PRESERVE8并不完成8 byte 对齐的操作,对齐由ALIGN完成。

 

5.  ldr r0,=0x53000000

    ldr r1,=0x0

    str r1,[r0]

LDR R0,=0x53000000是将0x53000000放到R0中。

LDR R1,=0x0是将立即数0放到R1中。

STR R1,[R0]是一个典型的存储指令,将R1中的值放到以R0中的值为地址的存储单元去。实际就是将0放到地址为0x53000000的存储单元中去。




你可能感兴趣的:(arm电子相册项目——启动加载篇startup.s)