||
LPC2000系列ARM处理器重映射原理的分析与实现
原文地址:http://blog.sina.com.cn/s/blog_4e0fe0510100iesw.html
摘要: 在ARM嵌入式软件开发过程中,经常会遇到一些重要的概念,比如重映射、分散加载等。本文结合具体的实例并以源代码的形式对这些概念进行了详细的分析,并给出了LPC2210处理器片外Flash启动和重映射的实现方法。
关键字:启动代码 重映射 ARM
多数嵌入式系统中,在进入主程序main之前,需要执行初始化序列对应用程序的运行环境进行配置。启动代码一般用汇编语言来编写,它主要对关键的设备进行初始化和配置,为应用程序的运行创造条件。在整个启动过程中,重映射是其中重要一环,正确的理解和实现重映射对于理解系统的工作原理极为重要。
本文的实验平台是EasyARM2210开发板,处理器为Philips LPC2210,它的片内只集成了一块位于0x40000000~0x40004000,大小为16K的SRAM,同时还扩展了一块位于0x80000000~0x801FFFFF,大小为8M字节的Flash。虽然本文的内容都是以LPC2100处理器为例来进行说明的,但对其它ARM系列的处理器来说也是适用的。
ARM处理器在复位后处于SVC模式,中断是禁止的,并且处于ARM状态。必须设置好各个异常模式堆栈的位置和大小,应用程序运行时所在的处理器模式和状态,并为它分配合适的堆栈和堆空间,以及使能中断和启用缓存(如果有的话)的时机。一般来说,你总是需要按照一个合理的顺序来初始化你的系统,图1从总体上描述了一个适用于ARM嵌入式系统的可能的初始化序列。
可以看出,整个初始化序列可以分为两个大的部分,用户代码和C库。C库初始化代码是由集成开发环境(这里使用的是ADS1.2)自动生成的,在完成任务之后,它最终将控制权转交给用户代码。__scatterload部分的作用相当于通常所说的bootloader,它会根据应用程序的设置(比如,我们可以通过分散加载文件精确的指定代码和数据在加载时和运行时的位置)自动生成代码将程序装载到用户希望的地址。__rt_entry部分的作用是执行运行时库的初始化工作。我们需要编码的是用户代码部分:首先设置各个模式的堆栈指针(由于LPC2210中没有MMU/MPU、缓存和TCM,因此这里只需要设置各个模式的堆栈指针即可,程序如list 1所示);其次,如果你使用了分散加载描述文件(由于实际系统中存储器类型的多样性,这几乎总是事实),那么必须实现函数__user_initial_stackheap( );最后是启用中断。
//list 1: 设置各种模式的堆栈指针值
Reset_Handler
设置完各个模式的堆栈指针之后,要对关键的I/O设备进行初始化,对处理器时钟、存储器加速模块以及外部存储器模块进行设置。然后跳转到C库的__main,首先由C库代码按照分散加载文件的描述将代码和数据从加载地址拷贝到运行地址并对未初始化数据进行清零,然后跳转到__rt_entry对C运行时库进行初始化,最后将控制权转交给用户代码(即主程序main)。
ARM是一个采用RISC体系结构的处理器内核,ARM公司本身并不生成芯片,它将ARM内核授权给生成和销售半导体的合作伙伴。虽然各个ARM芯片生产厂商所采用的内核是相同的,但是在一些细节上也是各有各的特色。本文所说的重映射都是针对LPC2000系列处理器来说的,其它公司比如Atmel、Intel等所采用的机制会有所不同。
所有的ARM系统都有一个异常向量表,它是跳转到各种异常处理程序的跳转指令列表。由于普通的跳转指令B label的跳转范围只有32M,为了实现4G范围内的任意跳转,可以采用指令LDR PC, target_addr,它将target_addr的值看作是一个地址值装载到PC中,于是跳转到那个地址处继续执行。这样向量表通常包括32字节的相对PC的跳转指令和32字节的异常处理程序地址。
通常系统对异常向量表的访问最为频繁,为了尽可能快的响应各种异常,必须考虑将异常向量表装载到何种类型的存储器中。片内RAM的访问速度最快,而且可以运行时对向量表进行修改,它无疑是向量表的理想选择。但是考虑到RAM不属于非易失性存储器,在掉电后不能保存它的内容,因此只能在系统启动后,将向量表复制到片内RAM中,并利用存储器重映射机制使向量表从片内RAM重新映射。在LPC2210中,重映射是通过寄存器MEMMAP来控制的,其用法如图2所示:
MEMMAP | 功能 | 描述 |
1:0 | MAP1:0 | 00:Boot装载程序模式。异常向量从bootblock重新映射。01:保留。该选项不使用。、 10:用户RAM模式。异常向量从片内RAM重新映射。 11:用户外部存储器模式。异常向量从外部存储器重新映射。 |
7:2 | 保留 | 保留,不要向其写入1。 |
图2: MEMAP寄存器
在LPC2000中,存储器重映射的部分包括异常向量区(32字节)和额外的32字节,一共是64字节,重新映射的代码位置与地址0x0~0x0000003F重叠。也就是说,当处于用户RAM模式时,如果访问0x0~0x3F的数据,实际上是在对0x40000000~0x4000003F进行访问。同样如果切换到外部存储器模式,并且同样对0x0~0x3F进行访问,就变成访问0x80000000~0x8000003F中的数据/指令了。
2.3.1 从RAM中重映射
//list 2:分散加载文件――异常向量从片内RAM重新映射
ROM_LOAD 0x80000000
{
}
2.3.2
//list 3:部分启动代码
CM_ctl_reg
RAM
Reset_Handler
Instruct_2