嵌入式系统资源有限,程序通常都固化在ROM总运行。ROM中程序执行前,需要对系统硬件和软件运行环境进行初始化,这些工作是用汇编语言编写的启动程序完成。启动程序是嵌入式程序的开头部分,应与应用程序一起固化在ROM中,应首先在系统上运行的启动程序应包含各模块中可能出现的所有段类,并合理安排他们的次序。
启动程序一般流程如下:
(1) 设置入口指针
(2) 设置中断向量
ARM7要求中断向量必须设置从0地址开始,连续8*4字节的空间,分别是复位、未定义指令错误、软件中断、预取指令中断、数据存取错误、IRQ、FIQ和一个保留的中断向量
(如果ROM位于0地址,向量表包含一系列指令跳转到中断服务程序,否则向量必须被动态初始化。可以在启动程序中添加一段代码,使其在运行时将向量表拷贝到0地址开始的存储空间)
对于各未用的中断,用一个只包含返回指令的哑函数,以防止错误引起系统的混乱。
(3) 初始化堆栈和寄存器
取决于使用了哪些中断,一般系统需要处理哪些错误类型。一般来说管理者堆栈必须设置,如果使用了IRQ中断,则IRQ堆栈必须设置。
如果系统使用了DRAM或者其他的外设,则需要设置相关的寄存器,以确定其刷新频率,数据总线宽度等信息
(4) 初始化存储器系统
有些芯片可通过寄存器编程初始化存储器系统,而对于复杂系统通常集成了MMU来管理内存
(5) 如果有必要改变处理器模式、状态
如果系统应用程序是运行在用户模式下,可在此处将系统改为用户模式并初始化用户的堆栈指针。
(6) 初始化C语言所需要的存储器空间
为正确运行应用程序,在初始化期间应将系统需要读写的数据和变量从ROM拷贝到RAM里;一些要求快速响应的程序,如中断处理程序,也需要在RAM中运行; 如果使用FLASH,对FALSH的檫除和写入也一定要在RAM里运行。ARM公司软件开发工具包中的链接器提供了分布装载的功能,可以实现这一目的。
(7) 呼叫C语言
ARM有两种指令集:16位的Thumb指令集和32位的指令集。使用16位的存储器可以降低成本,在这种情况下,Thumb指令集的整体执行速度要比ARM32位指令集体,而且提高了代码密度,所以一般用Thumb 编译器将C语言 程序编译成16位代码。
处理器在一开始总是处于ARM状态,可使用BX指令转换到Thumb状态呼唤C语言程序,要注意的是用C语言编写的嵌入式程序时,要避免使用不能被固化到ROM的库函数。
技术难点分析
(1) MMU的使用
MMU 是存储器管理单元的缩写,是用来管理虚拟内存系统的器件。MMU通常是CPU的一部分,本身有少量的存储空间存放从虚拟地址到物理地址的匹配表。此表称作TLB(转换旁置缓冲区)。所有数据请求都送往MMU,由MMU决定数据只在RAM中还是在大容量的存储器设备内。如果数据不在存储空间内,MMU将产生页面错误中断
MMU的两个主要功能是:
将虚拟地址转换为物理地址
控制存储器存取允许。MMU关掉时,虚地址直接输出到物理地址总线。
在实践中,使用MMU解决了以下几个问题:
a. 使用DRAM作为大容量存储器时,如果DRAM行列是非平方的,会导致该DRAM的物理地址不连续,这将给程序的编写调试造成极大的不方便,而适当的配置MMU可将其转换成虚拟地址连续的空间
b. ARM内核的中断向量表放在0地址,对于ROM在0地址的情况,无法调用中断服务程序,所以在调试阶段有必要将可读写的存储器空间映射到0地址。
c. 系统的某些地址是不允许被访问的,否则会产生不可预料的后果,为避免这类错误,可以通过MMU匹配表的设置将这些地址设为用户不可以存取类型;
d. 启动程序中生成的匹配表中包含地址映射,存储页面大小(1M、64K 或者4K)以及是否允许存取等信息。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。