有所追求
分类: BSD
2008-03-12 12:56:34
前言:
基于ARM核的微处理器是目前嵌入式领域应用最广泛的RISC微处理器,以其低成本、低功耗、高性能等优点占据了嵌入式系统应用领域的领先地位。基于ARM核的芯片多数为复杂的片上系统集成, 在芯片上电或复位时,需要专门的一段代码来完成对系统的初始化。启动代码就是芯片上电或复位后进入应用程序main( )函数前执行的一段代码,它主要为运行C程序提供基本的运行环境。
1 启动代码的流程
Bootloader(启动)代码类似于PC机的BIOS(基本输入输出系统),它从系统上电或复位开始接管CPU,Bootloader根据实现的功能不同,其复杂程度也各不相同,一般随具体的目标系统和开发系统有所区别,使得每一种芯片的启动代码差别较大,不易编出统一的启动代码,但通常包括以下几个步骤:
·设置程序入口指针
·设置中断向量表
·初始化存储器系统
·初始化CPU各种模式的堆栈和寄存器
·初始化目标系统中要使用的各种片内外设
·初始化用户程序执行环境
·引导主应用程
2 基于LPC2210的Bootloader关键代码设计
2.1 LPC2210的Bootloader代码流程:
根据前面介绍的一般步骤,利用ARM公司推出的ADS开发工具,设计出LPC2210的Bootloader的具体流程(如图1)和关键代码。
Philips公司生产的LPC2210是基于ARM7TDMI核的RISC微处理器,特别适用于工业控制、医疗系统、访问控制。ADS是ARM公司推出的ARM核微处理器集成开发工具,成熟的版本是ADS1.2, ADS由命令行开发工具、ARM实时库、GUI开发环境、实用程序和支持软件组成,支持软件调试及JTAG硬件仿真调试,支持汇编、C和C++源程序。
2.2设置中断向量表
ARM芯片上电或复位后,系统进入管理模式、ARM状态、PC(R15)指向0x00000000地址处,所以必须保证向量表代码定位在0x00000000处,或者映射到0x00000000处,LPC2210系统上电或复位时,存储器映射控制寄存器(MEMMAP)等于0,Boot Block被重映射到地址0x00000000处,选择从Boot Block读取中断向量。中断向量表为每一个中断设置1个字(4个字节)的存储空间,存放一条跳转指令,通过这条指令使PC指针指向相应的中断服务程序入口,继而执行相应的中断处理程序。LPC2210的中断向量表和其它基于ARM核的芯片中断向量表较类似,只要注意LPC2210要使向量表所有数据32位累加和为零(0x00000000~0x0000001C的8个字的机器码累加), 才能使用户的程序脱机运行,限于篇幅,在此省略中断向量表的代码。
2.3初始化存储器系统
初始化存储器系统是初始化代码中的一个重要部分,因为许多操作系统在开始运行之前,希望了解存储器的组织情况。存储器系统初始化是通过软件设定FLASH、RAM存储器的地址范围,数据总线宽度。由于LPC2210是总线开放型芯片,具有4个Bank的存储器组,总线宽度可设置为8位、16位或32位。初始化存储器系统代码如下:
ResetInit
LDR R0, =PINSEL2
IF :DEF: EN_CRP
LDR R1, =0x0f814910 ;芯片加密,禁止JTAG调试
ELSE
LDR R1, =0x0f814914 ;设置总线的I/O引脚
ENDIF
STR R1, [R0]
LDR R0, =BCFG0
LDR R1, =0x1000ffef
STR R1, [R0] ;设置外部第0个存储区
LDR R0, =BCFG1
LDR R1, =0x1000ffef
STR R1, [R0] ;设置外部第1个存储区
LDR R0, =BCFG2
LDR R1, =0x2000ffef
STR R1, [R0] ;设置外部第2个存储区
LDR R0, =BCFG3
LDR R1, =0x2000ffef
STR R1, [R0] ;设置外部第3个存储区
2.4 初始化堆栈、改变处理器模式
ARM处理器有7种处理器模式,分别为:用户模式(usr)、快速中断模式(fiq)、普通中断模式(irq)、管理模式(svc)、数据访问中止模式(abt)、未定义指令中止模式(und)、系统模式(sys)。除用户模式之外的其他6种模式称为特权模式,在这些模式下,程序可以访问所有的系统资源,也可以任意进行处理器模式的切换。
每一种模式的堆栈指针寄存器(SP)都是独立的,因此对程序中需要用到的每一种模式都要给SP寄存器定义一个堆栈地址。方法是改变状态寄存器CPSR中的状态位,使处理器切换到相应的模式,然后再给SP赋值。这里有两点要注意:一、要尽量给堆栈分配快速和高带宽的存储器,因为堆栈性能的好坏对系统整体性能有非常重要的影响。二、在处理器模式切换时,不要过早地进入用户模式,因为进入用户模式就不能对CPSR进行修改切换到别的模式,这样会对接下去地程序造成影响,一般在系统初始化的最后阶段才将运行模式切换到用户模式。初始化堆栈代码如下:
InitStack
MOV R0, LR ;因芯片模式切换,故将程序返回地址保存到R0,同时在初始化堆栈完成后使用R0返回
MSR CPSR_c, #0xd3
LDR SP, StackSvc ;设置管理模式堆栈
MSR CPSR_c, #0xd2
LDR SP, StackIrq ;设置中断模式堆栈
MSR CPSR_c, #0xd1
LDR SP, StackFiq ;设置快速中断模式堆栈
MSR CPSR_c, #0xd7
LDR SP, StackAbt ;设置中止模式堆栈
MSR CPSR_c, #0xdb
LDR SP, StackUnd ;设置未定义模式堆栈
MSR CPSR_c, #0xdf
LDR SP, =StackUsr ;设置用户模式堆栈
MOV PC, R0
2. 5初始化目标系统
为了LPC2210基本能够工作,在进入main( )函数前,须对目标系统进行一些基本的初始化工作。如:LPC2210有不同的存储器映射方式,须根据硬件来设置存储器映射方式;为了避免混乱,最好在进入main( )函数前设置系统各部分时钟等,关键代码如下:
void TargetResetInit(void)
{
#ifdef __DEBUG
MEMMAP = 0x3;
#endif
#ifdef __OUT_CHIP
MEMMAP = 0x3;
#endif
#ifdef __IN_CHIP
MEMMAP = 0x1; /*根据预定义的宏,设置存储器映射方式*/
#endif
/* 设置系统各部分时钟 */
PLLCON = 1; /*使能PLL(锁相环),但不连接PLL*/
#if (Fpclk / (Fcclk / 4)) == 1
VPBDIV = 0;
#endif
#if (Fpclk / (Fcclk / 4)) == 2
VPBDIV = 2;
#endif
#if (Fpclk / (Fcclk / 4)) == 4
VPBDIV = 1;
#endif /*设置外设时钟(VPB时钟pclk)与系统时钟(cclk)的分频比*/
#if (Fcco / Fcclk) == 2
PLLCFG = ((Fcclk / Fosc) - 1) | (0 << 5);
#endif
#if (Fcco / Fcclk) == 4
PLLCFG = ((Fcclk / Fosc) - 1) | (1 << 5);
#endif
#if (Fcco / Fcclk) == 8
PLLCFG = ((Fcclk / Fosc) - 1) | (2 << 5);
#endif
#if (Fcco / Fcclk) == 16
PLLCFG = ((Fcclk / Fosc) - 1) | (3 << 5); /*根据PLL的电流控制振荡器和系统时钟的频率比,设置PLL的乘因子和除因子*/
#endif
PLLFEED = 0xaa;
PLLFEED = 0x55; /*使用芯片要求的访问序列把数据写入PLL相关寄存器*/
while((PLLSTAT & (1 << 10)) == 0); /*等待PLL跟踪完成*/
PLLCON = 3;
PLLFEED = 0xaa;
PLLFEED = 0x55; /*使PLL连上系统*/
/* 设置存储器加速模块(MAM) */
MAMCR = 0; /*关闭MAM*/
#if Fcclk < 20000000
MAMTIM = 1;
#else
#if Fcclk < 40000000
MAMTIM = 2;
#else
MAMTIM = 3; /*根据Fcclk的大小来设置MAM定时寄存器*/
#endif
#endif
MAMCR = 2; /*使能MAM*/
/* 初始化VIC */
VICIntEnClr = 0xffffffff ;禁止所有中断
VICVectAddr = 0 ;设置向量地址寄存器(VICVectAddr)的值为0
VICIntSelect = 0 ;将所有中断设置为IRQ中断
程序中的Fcclk、Fcco、Fpclk须在头文件中定义。
2.6 初始化应用程序
当所有的初始化工作完成后,调用ADS提供的__main, __main是ADS的编译系统提供的一个函数,负责完成C运行时库的初始化和应用程序执行环境的初始化,最后自动跳转到用户的main( )函数。代码为:
B __main
3 结论
启动代码是嵌入式程序的开头部分,它直接面对处理器内核和硬件控制器进行编程,并首先在系统上运行,因此写好启动代码是设计好嵌入式系统的关键。本文介绍的Bootloader代码已经在Philips公司的LPC2210处理器上测试通过并运行稳定。对不同的ARM核芯片编写Bootloader代码,不但要了解ARM内核结构、指令系统,还要了解具体芯片的结构和各种片上资源。
参考文献
1 杜春雷.ARM体系结构与编程[M].北京:清华大学出版社.2004
2 马忠梅等.ARM嵌入式处理器结构与应用基础[M].北京:北京航空航天大学出版社.2003
3 周立功等.ARM微控制器基础与实践[M].北京:北京航空航天大学出版社.2003
4 Andrew N.Sloss、Dominic Symes、Chris Wright著.ARM嵌入式系统开发―软件设计与优化[M].沈建华译.北京:北京航空航天大学出版社.2005