基于ARM核的Bootloader代码的分析与设计(zhuan )

 


关键词:ARM7TDMI核   ADS   Bootloader代码   LPC2210

前言:

基于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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值