标题:
深入理解ARM嵌入式系统引导过程—基于AT91SAM9261微处理器
[打印本页]
作者:
yuyang911220
时间:
2014-12-22 16:18
标题:
深入理解ARM嵌入式系统引导过程—基于AT91SAM9261微处理器
3
系统初始化
3.1
第一条指令
ARM
核总是从地址
0x0
取出第一条指令开始引导过程。在本文中映像文件烧写到
NorFlash
中,为了从
NorFlash
引导,
BMS
引脚接地,这样复位时,
NorFlash
重映射到地址
0x0
。
cstartup
区域部分代码如下所示:
AREA cstartup, CODE
ENTRY
resetHandler
; The first instruction Set pc to actual code location (i.e. not in remap zone)
LDR pc, =label
label
LDR r0, = |Image$$ARM_LIB_STACK$$ZI$$Limit|
MOV sp, r0
; other codes
由于
cstartup
区域定位于
NorFlash
的起始位置,因此执行的第一条指令是
LDR pc, =label
。这是一条伪指令,汇编器将
label
的值放在一个文字池(
literal pool
)中,并生成一个相对
PC
寻址的
LDR
指令从文字池中装载该值。这可以从
IDA-The Interactive Disassembler
反汇编生成的
.axf
文件的输出得到确认:
0x10000000 ldr pc, [pc, #0x34] ;34 F0 9F E5
…
0x1000003C DCD 0x10000004
可以看到
label
的值等于
0x10000004
,它存储在地址
0x1000003C
处。首条指令的编码为
34 F0 9F E5
,即
ldr pc, [pc, #0x34]
,执行此指令后,
PC=PC+0x8+0x34=PC+0x3C
,取出当前指令地址偏移
0x3C
处的值(即
0x10000004
),赋给
PC
寄存器,也就是跳转到绝对地址
0x10000004
处继续执行。其后的两条汇编语句设置临时堆栈,为调用
C
语言编写的函数
LowLevelInit
做准备。
3.2
关键外围设备
系统引导时必须首先初始化一些关键的外围设备,例如
晶振和锁相环,高级中断控制器,看门狗等,它们都是在
LowLevelInit
函数中完成的。由于不同的应用程序的外设初始化代码相差较大,因此此处不做详细说明。
3.3
重映射异常向量和异常处理器
所有的
ARM
系统在地址
0x0
都有一个向量表。向量表虽然不是初始化序列的一部分,但是必须存在,它是转到各个异常处理器的跳转指令表。当发生异常时(例如,数据中止,未定义指令,
IRQ
等),
ARM
核立即取出位于地址
0x0
和
0x1C
之间的
8
条指令中的一条,并执行它。如果程序不需要处理这个异常,那么可以放置一个无限循环,例如:
undefVector
b undefVector
如果必须处理这个异常,例如复位异常,那么可以放置一个相对
PC
的跳转指令,例如:
LDR pc, =resetHandler
很明显,当前的存储器布局不能满足这种要求,因为地址
0x0-0xF,FFFF
此时映射到
NorFlash
,而
NorFlash
的起始位置存储的是
cstartup
区域,而不是异常向量。为了满足
ARM
核对异常向量的位置要求,引导过程的下一步就是将片内
SRAM
重映射到
0x0-0xF,FFFF
,这是通过调用
BOARD_RemapRam
函数完成的。注意,此时异常向量并未真正就绪,只有当随后使用分散加载机制将
VECTOR
区域从加载区拷贝到片内
SRAM
的起始处后,才能访问异常向量。
最后调用
BOARD_ConfigureNorFlash
函数配置外部总线接口片选
0
(
EBI CS0
),因为默认配置参数并不是最优的,所以需要根据存储器特性进行重新配置。
3.4
设置各种模式的堆栈
ARM
处理器的堆栈主要有两个特点,其一每种模式都有自己的堆栈指针
SP
,其二堆栈是递减的。设置方法是依次进入各种模式,赋给
SP
正确的值。一般
Supervisor
和
User
模式的堆栈最大,
IRQ
和
FIQ
模式次之,其它模式经常只需要几个字节。在本文中,首先设置
IRQ
模式堆栈设置到片内
SRAM
顶部,然后设置
Supervisor
模式的堆栈,同时使能
IRQ
和
FIQ
。
3.5
从加载视图到执行视图
链接器生成可执行映像的同时也定义了映像中各个符合的绝对地址,只有将它们移动到对应的地址,应用程序才能正常运行。以可读写的
RW
节为例,如果在改写它的值之前,没有将其从
Flash
存储器移动到可读写的
RAM
存储器,那么必然会发生异常。
ARM
库中的
__main
例程负责将加载视图转变为执行视图,最后调用
C
语言编写的
main
函数。
__main
例程的主要功能有三个:拷贝需要移动的区、零初始化
ZI
区和初始化堆栈和堆,分别对应于图
2
中的①②③。
大多数
RO
属性的节都位于
NorFlash
中,它的加载视图和执行视图的起始地址相同,因此不需要移动。
Relocate_region
区的加载视图和执行视图的起始地址不同,因此需要移动。将
VECTOR
节定位到片内
SRAM
主要是为了满足
ARM
架构对异常向量的位置要求,在执行完初始化序列中的
SRAM
重映射之后,就可以在地址
0x0
访问异常向量。
board_lowlevel.o
和
board_memories.o
紧随
VECTOR
之后,之所以将它们定位到片内
SRAM
主要是为了提高系统性能。
最后放置属性为
ZI
的节。
ZI
节在映像中不占据空间,它们在
SRAM
中创建和零初始化。
ARM_LIB_STACK
执行区用来为各种模式分配堆栈空间,它自
SRAM
顶部,即地址
0x328000
,开始向下增长。
ARM_LIB_HEAP
执行区,即堆空间,它自地址
0x326000
开始向上增长。
图
2
从加载视图到执行视图
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0