首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

深入理解ARM嵌入式系统引导过程—基于AT91SAM9261微处理器

深入理解ARM嵌入式系统引导过程—基于AT91SAM9261微处理器

3 系统初始化3.1 第一条指令ARM核总是从地址0x0取出第一条指令开始引导过程。在本文中映像文件烧写到NorFlash中,为了从NorFlash引导,BMS引脚接地,这样复位时,NorFlash重映射到地址0x0cstartup区域部分代码如下所示:
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核立即取出位于地址0x00x1C之间的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函数配置外部总线接口片选0EBI CS0),因为默认配置参数并不是最优的,所以需要根据存储器特性进行重新配置。
3.4 设置各种模式的堆栈ARM处理器的堆栈主要有两个特点,其一每种模式都有自己的堆栈指针SP,其二堆栈是递减的。设置方法是依次进入各种模式,赋给SP正确的值。一般SupervisorUser模式的堆栈最大,IRQFIQ模式次之,其它模式经常只需要几个字节。在本文中,首先设置IRQ模式堆栈设置到片内SRAM顶部,然后设置Supervisor模式的堆栈,同时使能IRQFIQ
3.5 从加载视图到执行视图链接器生成可执行映像的同时也定义了映像中各个符合的绝对地址,只有将它们移动到对应的地址,应用程序才能正常运行。以可读写的RW节为例,如果在改写它的值之前,没有将其从Flash存储器移动到可读写的RAM存储器,那么必然会发生异常。
ARM库中的__main例程负责将加载视图转变为执行视图,最后调用C语言编写的main函数。__main例程的主要功能有三个:拷贝需要移动的区、零初始化ZI区和初始化堆栈和堆,分别对应于图2中的①②③。
大多数RO属性的节都位于NorFlash中,它的加载视图和执行视图的起始地址相同,因此不需要移动。
Relocate_region区的加载视图和执行视图的起始地址不同,因此需要移动。将VECTOR节定位到片内SRAM主要是为了满足ARM架构对异常向量的位置要求,在执行完初始化序列中的SRAM重映射之后,就可以在地址0x0访问异常向量。board_lowlevel.oboard_memories.o紧随VECTOR之后,之所以将它们定位到片内SRAM主要是为了提高系统性能。
最后放置属性为ZI的节。 ZI节在映像中不占据空间,它们在SRAM中创建和零初始化。
ARM_LIB_STACK执行区用来为各种模式分配堆栈空间,它自SRAM顶部,即地址0x328000,开始向下增长。ARM_LIB_HEAP执行区,即堆空间,它自地址0x326000开始向上增长。

2 从加载视图到执行视图

继承事业,薪火相传
返回列表