LPC2220芯片初始化代码研究(转)

一般来讲,在32位ARM应用系统中,软件大多数采用C语言进行编程,并且以嵌入式操作系统为开发平台,这样就大大的提高了开发效率及软件性能。由于C语 言程序的运行需要具备一定的条件,例如分配好的外部数据空间、堆栈空间和中断入口等。因此,在编写应用程序时必须在程序的入口处加入一些必要的初始化代码 (启动代码),使系统在执行C语言程序之前先完成对自身的初始化,从而才能正确地执行用户代码。

1 、启动代码要点与示例
    为了能够进行系统初始化,采用一个汇编文件作启动代码是最常用的做法,典型的初始化程序必须完成以下任务:
  • 定义入口地址;
  • 建立异常中断处理向量表,实现向量表定义;
  • 初始化存储器系统;
  • 初始化堆栈;
  • 系统变量初始化;
  • 中断系统初始化;
  • 时钟初始化、I/O初始化;
  • 进入C语言程序的运行。
    LPC2220 初始化示例代码:
;声明要引入的外部标号
    IMPORT FIQ_Exception                     ;快速中断异常处理程序
    IMPORT __main                            ;C语言主程序入口
IMPORT TargetResetInit                   ;目标板基本初始化函数
         CODE32                               ;指明32位代码
         AREA    vectors,CODE,READONLY
         ENTRY                                ;指明入口地址
;中断向量表
Reset
         LDR     PC, ResetAddr                ;跳到复位处理
        LDR     PC, UndefinedAddr            ;跳到未定义异常处理
        LDR     PC, SWI_Addr                 ;跳到软件中断处理
        LDR     PC, PrefetchAddr             ;跳到预取指中止处理
        LDR     PC, DataAbortAddr            ;跳到数据中止处理
        DCD     0xb9205f80                   ;保留的异常
LDR     PC, [PC, # -0xff0]           ;跳到IRQ中断处理
        LDR     PC, FIQ_Addr                 ;跳到FIQ中断处理
ResetAddr        DCD     ResetInit
UndefinedAddr    DCD     Undefined
SWI_Addr           DCD     SoftwareInterrupt
PrefetchAddr      DCD     PrefetchAbort
DataAbortAddr    DCD     DataAbort
Nouse              DCD     0
IRQ_Addr           DCD     0
FIQ_Addr           DCD     FIQ_Handler
Undefined          ;未定义指令
        B       Undefined
SoftwareInterrupt ;软中断
    B       SoftwareInterrupt
     PrefetchAbort     ;取指令中止
        B       PrefetchAbort
DataAbort          ;取数据中止
        B       DataAbort
FIQ_Handler        ;快速中断
        STMFD      SP!, {R0-R3, LR}       ;R0-R3, LR入栈
        BL         FIQ_Exception          ;跳到快速中断处理程序,用户编写
        LDMFD      SP!, {R0-R3, LR}       ;出栈恢复R0-R3, LR数据
        SUBS       PC, LR, #4           ;FIQ返回
     ResetInit                            ;复位处理,下一节讲述
Undefined          ;未定义指令
        B       Undefined
SoftwareInterrupt ;软中断
    B       SoftwareInterrupt
     PrefetchAbort     ;取指令中止
        B       PrefetchAbort
2 、初始化代码分析
    ARM公司只设计核心,不自己生产芯片,只是把核心授权给其他厂商,其他厂商购买了授权后加入自己的外设后生产各具特色的芯片,这样就促进了基于ARM处 理器核的芯片多元化,但也使得每一种芯片的启动代码差别很大,不易于编写出统一的初始化代码。所以启动代码与芯片的特性有着紧密的联系,本章以 LPC2200系列的ARM芯片为基础,详细分析一下LPC2220的初始化代码。
    1)定义入口地址
    初始化代码中必须指明入口地址,一般采用ARM汇编语言中的ENTRY语句。
         CODE32                               ;指明32位代码
         AREA    vectors,CODE,READONLY
         ENTRY                                ;指明入口地址
    2)向量表定义
    初始化代码首先必须建立起所需要的异常中断向量表(即异常中断处理程序地址表)。ARM芯片复位后,系统进入管理模式、ARM状态,PC寄存器(运行指 针)的值为0x00,所以必须保证向量表代码定位在0x00处,或者映射到0x00处。实际上,中断向量表就是一系列分支语句,每条分支语句跳转到相应的 中断处理程序。
    LPC2220处理器上的中断向量表地址为0x0000 0000 ~ 0x0000 001C,LPC2220的启动代码中,向量表的定义如下所列。
;中断向量表
Reset
         LDR     PC, ResetAddr                ;跳到复位处理                0x0000 0000
        LDR     PC, UndefinedAddr            ;跳到未定义异常处理          0x0000 0004
        LDR     PC, SWI_Addr                 ;跳到软件中断处理            0x0000 0008
        LDR     PC, PrefetchAddr             ;跳到预取指中止处理          0x0000 000C
        LDR     PC, DataAbortAddr            ;跳到数据中止处理            0x0000 0010
        DCD     0xb9205f80                    ;保留的异常                  0x0000 0014
LDR     PC, [PC, # -0xff0]           ;跳到IRQ中断处理            0x0000 0008
        LDR     PC, FIQ_Addr                 ;跳到FIQ中断处理            0x0000 001C
ResetAddr        DCD     ResetInit
UndefinedAddr    DCD     Undefined
SWI_Addr           DCD     SoftwareInterrupt
PrefetchAddr      DCD     PrefetchAbort
DataAbortAddr    DCD     DataAbort
Nouse              DCD     0
IRQ_Addr           DCD     0
FIQ_Addr           DCD     FIQ_Handler
    3)系统变量初始化
    如果一旦产生中断,微控制器会切换到相应的模式,并跳转到向量表指定地址去执行程序。例如:一旦产生FIQ中断,处理器将会切换到FIQ模式,并跳转到向 量表0x0000001C地址执行程序。程序将跳到FIQ_Handler标号处,处理FIQ中断服务程序。各个标号定义如下:
Undefined          ;未定义指令
        B       Undefined
SoftwareInterrupt ;软中断
    B       SoftwareInterrupt
     PrefetchAbort     ;取指令中止
        B       PrefetchAbort
DataAbort          ;取数据中止
        B       DataAbort
FIQ_Handler        ;快速中断
        STMFD      SP!, {R0-R3, LR}       ;R0-R3, LR入栈
        BL         FIQ_Exception          ;跳到快速中断处理程序,用户编写
        LDMFD      SP!, {R0-R3, LR}       ;出栈恢复R0-R3, LR数据
        SUBS       PC, LR, #4           ;FIQ返回
    4)中断系统初始化
    建立好中断向量表后,一旦芯片上电或复位,程序就会跳转到 ResetInit 处执行。将会对中断系统进行初始化。
    //-----------------初始化VIC中断系统-------------------
    VICIntEnClr = 0xffffffff;        //关闭所有中断,并且中断地址清0
    VICVectAddr = 0;
    VICIntSelect = 0;
    5)初始化存储器系统
    再对存储器的初始化(即配置外部总线控制器)
    //-----------------初始化存储器系统-------------------
    BCFG0 = 0x1000ffef;     //外部存储器Bank0~Bank3控制器设置,配置成最慢的外部总线速度
    BCFG1 = 0x1000ffef;
    BCFG2 = 0x2000ffef;
    BCFG3 = 0x2000ffef;
   
    6)初始化堆栈
    然后调用 InitStack子程序 来初始化各个模式下的堆栈;
;定义各个模式下的堆栈大小
USR_STACK_LEGTH        EQU          256
SVC_STACK_LEGTH        EQU         0
FIQ_STACK_LEGTH        EQU         0
IRQ_STACK_LEGTH        EQU         256
ABT_STACK_LEGTH        EQU         0
UND_STACK_LEGTH        EQU         0
    ;* * * * * * 初始化堆栈 * * * * * *
InitStack   
        MOV      R0, LR               ;保存链接寄存器LR的值
;设置管理模式堆栈
        MSR     CPSR_c, #0xd3        ;切换到管理模式
        LDR     SP, StackSvc         ;设置管理模式下的堆栈指针SP
;设置中断模式堆栈
        MSR     CPSR_c, #0xd2        ;切换到中断模式
        LDR     SP, StackIrq         ;设置中断模式下的堆栈指针SP
;设置快速中断模式堆栈
        MSR     CPSR_c, #0xd1
        LDR     SP, StackFiq
;设置中止模式堆栈
        MSR     CPSR_c, #0xd7
        LDR     SP, StackAbt
        
;设置未定义模式堆栈
        MSR     CPSR_c, #0xdb
        LDR     SP, StackUnd
;设置系统模式堆栈
        MSR     CPSR_c, #0x5f        ;切换到系统模式,并打开中断
        LDR     SP, =StackUsr
        MOV     PC, R0               ;程序返回
     ;定义字单元,保存各个模式下的堆栈栈底
StackSvc         DCD     SvcStackSpace + (SVC_STACK_LEGTH - 1)* 4
StackIrq         DCD     IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4
StackFiq         DCD     FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4
StackAbt         DCD     AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4
StackUnd         DCD     UndtStackSpace + (UND_STACK_LEGTH - 1)* 4
;定义数据段MyStacks,给各个模式分配堆栈空间
        AREA    MyStacks, DATA, NOINIT, ALIGN=2
SvcStackSpace      SPACE   SVC_STACK_LEGTH * 4   ;管理模式堆栈空间
IrqStackSpace      SPACE   IRQ_STACK_LEGTH * 4   ;中断模式堆栈空间
FiqStackSpace      SPACE   FIQ_STACK_LEGTH * 4   ;快速中断模式堆栈空间
AbtStackSpace      SPACE   ABT_STACK_LEGTH * 4   ;中止义模式堆栈空间
UndtStackSpace     SPACE   UND_STACK_LEGTH * 4   ;未定义模式堆栈
         END
    7)时钟初始化、I/O初始化
    时钟是芯片各部分正常工作的基础,虽然时钟可以在任何时候设置,但为了避免混乱,最好在进入main函数之前设置好,时钟初始化如下:
    //-----------------初始化系统时钟-------------------
    PLLCON = 1;                                //PLL使能
     /*根据Fpclk和Fcclk的设置(在whole.h头文件里定义了),配置VPBDIV寄存器*/
     #if (Fpclk / (Fcclk / 4)) == 1  
    VPBDIV = 0;                         
     #endif
     #if (Fpclk / (Fcclk / 4)) == 2
    VPBDIV = 2;
     #endif
     #if (Fpclk / (Fcclk / 4)) == 4
    VPBDIV = 1;
     #endif
     /*根据Fcco和Fcclk的设置(在whole.h头文件里定义了),配置PLLCFG寄存器*/
     #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);
     #endif
    
     PLLFEED = 0xaa;
    PLLFEED = 0x55;                            //两个连续的PLLFEED写操作,确定以上的配置生效
    while((PLLSTAT & (1 << 10)) == 0);    //等待PLL锁定,否则一直等
    PLLCON = 3;                                //PLL使能,并且PLL连接
    PLLFEED = 0xaa;
    PLLFEED = 0x55;
   
···
/*IO口初始化*/
PINSEL0 = 0x00055555;       //使能UART0、IIC、SPI0、UART1模块的引脚连接
PINSEL1 = 0x2e8036a9;       //使能SPI1模块的引脚连接
PINSEL2 = 0x0fe14914;       //PINSEL2寄存器设置
         //以上3个PINSEL的设置,使得用户在使用实验板时,不需另行配置引脚连接模块了
    8)进入C语言程序的运行
    最后调用ADS提供的 __main ,初始化库函数执行环境并进入用户的main( )函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值