Chinaunix首页 | 论坛 | 博客
  • 博客访问: 538669
  • 博文数量: 139
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 1840
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-11 22:40
文章分类

全部博文(139)

文章存档

2011年(1)

2009年(3)

2008年(135)

我的朋友

分类:

2008-07-27 15:55:40

5.2  裸机底层驱动设计方法

所谓裸机在这里主要是指系统软件平台没有用到操作系统。在基于ARM处理器平台的软件设计中,如果整个系统只需要完成一个相对简单而且独立的任务,那么可以不使用操作系统,只需要考虑在平台上如何正确地执行这个单任务程序。不过,在这种方式下同样需要一个Boot Loader,这个时候的Boot Loader一般是自己写的一个简单的启动代码加载程序。大家所熟悉的各种Boot Loader下的设备驱动,其实就是很好的裸机驱动程序。比如说U-Boot下的网卡驱动、串口驱动、LCD驱动等。

在裸机方式下,ARM的软件集成开发环境就显得极为重要,因为在这种方式下可以把所有代码都放在这个环境里面编写、编译和调试。在这种方式下测试驱动程序,首先要完成CPU的初始化,然后把需要测试的程序装载到系统的RAM区/或者SDRAM中。当然,如果需要处理一些复杂的中断处理的话,最好也把CPU的复位向量表放到RAM区中。把所有程序都调试好之后,再把最后的程序烧写到Flash里面去执行。

5.2.1  复位向量表

所谓复位向量表,其实就是一些跳转指令表,这些跳转指令就是针对ARM处理器的多种异常处理的,有关处理器的工作模式及异常处理的介绍,读者可以回顾本书1.4的介绍。复位向量表通常是放在CPU复位执行的第一块内存地址空间中,一般来说都是0x00000000这个地址。

在32位ARM系统中,都是在中断向量表中放置一条分支指令或PC寄存器加载指令,来实现程序跳转到中断服务例程的功能。例如:

     IRQEntry    B  HandleIRQ                     ;跳转范围较小一般在64KB之内

                    B  HandleFIQ                        ;

    或

     IRQEntry    LDR  PC,HandleIRQ ;跳转的范围是任意32位地址空间

                    LDR PC,HandleFIQ

LDR伪指令等效于生成一条存储读取指令和一条32位常数定义指令。32位常数存储在LDR指令附近的存储单元中,相对偏移小于4KB。该32位数据就是要跳转到中断服务程序的入口地址。之所以使用LDR伪指令,是因为ARM的RISC指令为单字指令,不能装载32位的立即数(常数),无法直接把一个32位常数数据或地址数据装载到寄存器中。下面一段程序与上述伪指令功能等效,但中断向量表描述得更为清晰。其中VectorTable为相对LDR指令的偏移量。

IRQEntry  LDR PC,VectorTable+0  ;与LDR PC,=HandleIRQ 等效

          LDR PC,VectorTable+4 ;与LDR PC,=HandleFIQ 等效

                   ……

VectorTable  DCD HandleIRQ

            DCD HandleFIQ

            ……

HandleIRQ

……

HandleFIQ

一个典型的复位向量表的例子(Nucleus系统中比较常用)如例程5-2所示。

例程5‑2  典型复位向量表

;**********************************

;* VECTOR TABLE                 *

;**********************************

    .sect   "vectors"

    .def    INT_Vectors

INT_Vectors

     LDR    pc, INT_Initialize_Addr                     ; 复位异常中断地址

     LDR    pc, INT_Undef_Inst_Addr                         ; 未定义指令异常中断地址

     LDR    pc, INT_Software_Addr                          ; 软件异常中断地址

     LDR    pc, INT_Data_Abort_Addr                         ; 取数据错误异常中断地址

     LDR    pc, INT_Reserved_Addr                        ; 保留

     LDR    pc, INT_IRQ_Addr                         ; IRQ异常中断地址

     LDR    pc, INT_FIQ_Addr                         ;  快速IRQ异常中断地址

INT_Initialize_Addr

        .word   _INT_Initialize

INT_Undef_Inst_Addr

        .word   _INT_Undef_Inst

INT_Software_Addr

        .word   _INT_Software

INT_Prefetch_Abort_Addr

        .word   _INT_Prefetch_Abort

INT_Data_Abort_Addr

        .word   _INT_Data_Abort

INT_Reserved_Addr

        .word   _INT_Reserved

INT_IRQ_Addr

        .word   _INT_IRQ

INT_FIQ_Addr

        .word   _INT_FIQ

从上面的复位向量程序可以看出,CPU判断如果是复位异常则会跳转到_INT_Initialize执行,如果是未定义指令异常则跳转到_INT_Undef_Inst执行程序,其他几个异常也是同样的处理方式。

一般ARM嵌入式系统的程序都是固化在从0x00000000开始的低端ROM空间中,中断向量表VectorTable也固化在ROM中,所以上述两种方法都无法在程序运行时动态、随机地修改中断向量表。不论对于初学ARM处理器的程序员还是有经验的程序员,设置中断向量都相当烦琐,必须修改ARM的C程序启动代码。

还有一点需要指出的是,如果CPU有REMAP功能的话,一定要在初始化程序的结尾把整个程序包含复位向量表一起复制到RAM中,然后执行REMAP,如果没有REMAP功能,则需要把复位向量表单独转移到RAM中去。

5.2.2  中断服务程序

ARM处理器的中断处理程序实际可以称为对于处理器的异常处理程序。在对这些异常进行处理时就需要一定的中断服务程序。一般在进入中断服务程序之前,都要完成对程序现场和一定数据、堆栈的保护,然后跳转到中断服务程序执行中断服务,完成中断服务之后,在退出中断服务程序之前恢复保存的数据、堆栈信息等。在ARM处理器设计中通常把复位初始化程序也算到异常中断处理程序中。对应处理器的8个异常,分别有如下8个处理程序。

n  _INTCPU_Initialize:用来处理CPU复位初始化异常中断;

n  _INT_Undef_Inst:用来处理未定义指令异常中断;

n  _INT_Software:用来处理软件异常中断;

n  _INT_Prefetch_Abort:用来处理取指溢出异常中断;

n  _INT_Data_Abort:用来处理数据溢出异常中断;

n  _INT_Reserved:保留异常中断;

n  _INT_FIQ:用来处理FIQ异常中断;

n  _INT_IRQ:用来处理IRQ异常中断。

在8个异常中断处理函数里面,常用的主要是处理器复位异常中断、软件异常中断、常规异常中断(IRQ)、快速异常中断(FIQ)4个。

下面结合实际的异常处理源码来具体分析这8个异常中断程序。这些代码针对的ARM处理器是OMAP5910。

1)CPU复位初始化异常中断处理INTCPU_Initialize,该异常中断处理的主要功能有:

(1)初始化处理器系统控制寄存器。

(2)初始化中断向量表。

(3)初始化系统堆栈指针。

(4)跳转到高级初始化函数,进行高级初始化。

该异常处理函数的具体代码通常如例程5-3所示。

例程5‑3  INTCPU_Initialize

    .def    _c_int00

_c_int00

.def  _INTCPU_Initialize

_INTCPU_Initialize:

    ; //确保处理器进入Super模式

    MRS     r0,CPSR                              ; 获取当前CPSR值

    BIC      r0,r0,#MODE_MASK                    ; 清除CPSR中对应的CPU模式位

    ORR     r0,r0,#SUP_MODE             ; 设置supervisor模式位

    ORR     r0,r0,#LOCKOUT              ; 确保 IRQ/FIQ 中断被禁止

    MSR     CPSR,r0                               ; 设置新的CPSR参数值

    ;//清除未初始化的BSS区域

    LDR     r0,BSS_Start                     ; 获取BSS段的起始地址

    MOV    r2,#0                                  ; 清除r2寄存器值

    LDR     r1,BSS_End                    ; 获取BSS段的结束地址

INT_BSS_Clear_Loop:       

    STR     r2,[r0],#4                         ; 进入循环清空BSS段数据

INT_BSS_Clear_Check:       

    CMP     r0,r1                                 ; 与BSS结束地址比较

    BNE     INT_BSS_Clear_Loop               ; 如果相等,表示BSS段清空了

    ; 判断C运行段是否需要自动初始化. 

    LDR     r0, c_cinit

    CMN     r0, #1

    BLNE    _auto_init

    ; 打开I-Cache (针对 TI 925T 处理器)

    MRC     p15,#0,r1,C1,C0,#0                  ; 获取CP15 协处理器中寄存器的值

    ORR     r1,r1,#0x1000                     ; 使能指令cache I-cache

    NOP

    MCR     p15,#0,r1,C1,C0,#0                  ; 写CP15协处理器的寄存器.

; 建立向量表装载标识位,主要是为让系统中的其他调用了解默认的向量表是否已经装载了。

; 如果INT_Loaded_Flag 为1, 表示所有的默认的向量表已经装载

; 否则, 如果INT_Loaded_Flag 为 0, 可以通过登记一个LISR来使得默认的向量被装载

; 在 ARM60系统应用中,这个变量总是为1

; 所有的向量必须通过这个函数建立

;    INT_Loaded_Flag =  0;

    MOV     r0,#1                        ; 设定所有的向量被装载(通过设置Loaded_Flag=1)

    LDR      r1,Loaded_Flag                   ;

    STR      r0,[r1,#0]                        ; 初始化Loaded_Flag

; 初始化系统堆栈指针。  通常在BSS段清空之后完成这个初始化,

; 原因是TCD_System_Stack也是一个BSS段里的变量。

; 这里定义在BSS段之后的ram空间为可以使用的堆栈空间。

;

    LDR    r10,System_Stk_Limit           

    LDR    r3,System_Limit                     ; 获取系统堆栈Limit地址

    STR    r10,[r3, #0]                          ; 保存该地址

    LDR    sp,System_Stack_SP                  ; 建立系统堆栈指针

    LDR    r3,System_Stack                     ; 获取系统堆栈地址

    STR    sp,[r3, #0]                          ; 保存堆栈指针

    MRS    r0,CPSR                                ; 获取当前的CPSR

    BIC     r0,r0,#MODE_MASK                     ; 清除模式位

    ORR    r0,r0,#IRQ_MODE              ; 设置IRQ_mode位

    MSR    CPSR,r0                                ;

    LDR    sp,IRQ_Stack_SP                  ; 建立IRQ堆栈指针

    MRS    r0,CPSR                               ; 获取当前的CPSR

    BIC     r0,r0,#MODE_MASK                     ; 清除模式位

    ORR    r0,r0,#FIQ_MODE                ; 设置FIQ_mode位

    MSR    CPSR,r0                               ;

    LDR     sp,FIQ_Stack_SP                  ; 建立FIQ堆栈指针

    MRS     r0,CPSR                              ; 获取当前的CPSR

    BIC      r0,r0,#MODE_MASK                    ; 清除模式位

    ORR     r0,r0,#SUP_MODE             ; 设置supervisor模式位

    MSR     CPSR,r0                              ; 建立了所有异常的堆栈之后

                                                 ;  返回supervisor模式

; 定义全局数据结构

; 初始化该数据结构。

;

;    TMD_HISR_Stack_Ptr =        (VOID *) r2;

;    TMD_HISR_Stack_Size =       TIMER_SIZE;

;    TMD_HISR_Priority =         TIMER_PRIORITY;

    LDR     r2,HISR_Stack_Mem               ; 获取HISR_Stack_Mem变量地址

    LDR     r3,HISR_Stack_Ptr                  ; 获取HISR_Stack_Ptr变量地址

    STR      r2,[r3, #0]                         ; 建立timer HISR堆栈指针

    MOV     r1,#HISR_STACK_SIZE        ; 获取HISR_STACK_SIZE参数值

    LDR      r3,HISR_Stack_Size                ; 获取HISR_Stack_Size变量地址

    STR      r1,[r3, #0]                         ; 设置timer HISR 堆栈大小

    MOV     r1,#HISR_PRIORITY           ; 获取HISR 优先级参数

                                                 ; HISR_PRIORITY的值(0-2)

    LDR      r3,HISR_Priority                   ; 获取HISR_Priority变量地址

    STR      r1,[r3, #0]                         ; 设置HISR 优先级

/*BL调用中断向量表建立函数*/

/*BL调用初始化Timer函数*/

    BL      _INT_Install_Vector_Table        ; 调用装载向量表子函数

    BL      _INT_Timer_Initialize           ; 调用初始化Timer函数

;

;

;   调用INC_Initialize分配第一个可用的ram地址,通常都是上层来进行调用的

;     INC_Initialize(first_available_memory);

    LDR     r0,First_Avail_Mem           ; 获取First_Avail_Mem地址

/*跳转到_INC_Initialze高级初始化部分*/

    B       _INC_Initialize                ; 跳转到高级初始化部分,注意使用B指令

复位异常处理是CPU上电复位之后第一个执行代码。复位异常中断处理不论是在裸机设计方式中,还是基于操作系统的软件设计方式中,都是最重要的异常处理程序之一。上述程序完成CPU的初始化,堆栈空间的初始化等工作。那么下面再看看其他几个异常处理函数的定义部分。

2)未定义指令异常服务程序

未定义指令异常在通常的系统设计中都不做深入处理,在完成对现场的保护后,在服务程序中打印出相关的提示信息。其服务程序通常如下:

.def _INT_Undef_Inst

_INT_Undef_Inst

    STMDB   sp!,{r0-r3,lr}

    LDMIA   sp!,{r0-r3,lr}                       ;保存寄存器组

    BX       LR

B        _INT_Undef_Inst

3)软件中断服务程序

这是一个由用户定义的中断指令,可用于用户模式下的程序调用特权操作。软件中断服务程序在基于操作系统的嵌入式系统设计中十分重要,可以通过该机制实现系统功能调用。软件中断服务程序的常规流程一般是先得到软件中断号,然后根据中断号执行不同的代码。常规的处理方式如下。

; The CPSR Register is not accessible User mode, so a switch to the

; privileged mode is done by the assembly instruction SWI.

.state32      

; 使能异常,建立堆栈

; Works only if called from 16-bit (THUMB) mode

;/-------------------------------------------------------------------

    .def _INT_Software

_INT_Software:

         LDRH  r4, [LR, #-2]                 ;得到软件中断指令

           AND          r4, r4, #0xFF                        ;把中断号放到寄存器R4中

/*对R4 进行判别,从而进入不同的处理,一系列的CMP和BEQ指令*/

           CMP    r4, #0xF6

         BEQ    SetFIQIRQBit

         …

         …  /*类似的CMP和BEQ指令*/

           CMP r4, #0xF3

           BEQ ClearFIQBit

           B       ExitSwi           ;

SetSupervisor:      //切换CPU模式到Supervisor模式

           MRS r7, SPSR                        ; 保存SPSR副本

           BIC   r7,r7,#MODE_MASK           ; 清除模式位

           ORR r7,r7,#SUP_MODE          ; 设置Supervisor模式位

           MSR SPSR, r7                        ; 写回SPSR参数

           B       ExitSwi                           ;

SetUser:         //切换CPU模式到User模式

           MRS r7, SPSR                               ; 保存SPSR副本

           BIC   r7, r7, #MODE_MASK          ; 清除模式位    

           ORR r7, r7, #USR_MODE         ; 设置User模式位

           MSR SPSR, r7                               ; 写回SPSR参数

           B       ExitSwi                               ;

EnableIRQ://使能IRQ

         MOV   r5, #IRQ_MODE

         MOV   r6, #IRQ_MASK

         B      DoIt

EnableFIQ://使能FIQ

         MOV   r5, #FIQ_MODE

         MOV   r6, #FIQ_MASK

      B      DoIt

Set_SVC_Stack://建立Supervisor模式下的堆栈              

           ;STACK  MANIPULATION

         MOV    SP, r0                          ; 堆栈地址

      MOV      r1,r1,lsl #2                    ; 转换字地址到字节地址

         ADD    SP, r1, SP                         ; 在初始化SP上累加

      B    ExitSwi

Set_Abort_or_Udef_Stack:

           MRS r2, CPSR

           BIC   r2, r2, #MODE_MASK

           ORR r2, r2, r5

           MSR CPSR, r2                                   ; 设置Udef模式位

         MOV   SP, r0                          ; 堆栈地址

           MOV         r1,r1,lsl #2                     ; 转换字地址到字节地址

         ADD   SP, r1, SP                         ; 在初始化SP上累加

           BIC   r2, r2, #MODE_MASK

           ORR r2, r2, #SUP_MODE

           MSR CPSR, r2                            ; 保存Supervisor模式位

           B       ExitSwi

SetIRQBit:

           MOV   r5, #IRQ_MASK

         MOV   r6, #SET_BIT

           B      SetClearFIQIRQ

ClearIRQBit:

           MOV   r5, #IRQ_MASK

         MOV   r6, #CLEAR_BIT

           B      SetClearFIQIRQ

SetFIQBit:

           MOV   r5, #FIQ_MASK

         MOV   r6, #SET_BIT

           B      SetClearFIQIRQ

ClearFIQBit:

           MOV   r5, #FIQ_MASK

         MOV   r6, #CLEAR_BIT

           B      SetClearFIQIRQ      

SetFIQIRQBit:

           MOV   r5, #FIQ_IRQ_MASK

         B      SetFIQIRQ

RestoreFIQIRQBit:

           MOV   r5, #FIQ_IRQ_MASK

         B      RestoreFIQIRQ

SetFIQIRQ:

           MRS   r7, SPSR                         ; 读取保存的SPSR

           ;

           AND          r0, r7, #0xC0                     ; 屏蔽FIQ、IRQ位,写入r0寄存器.

           ORR    r7, r7, r5                           ; 设置FIQ、IRQ位,保存SPSR

         B            STORE_SPSR

RestoreFIQIRQ:

           MRS    r7, SPSR                       ; 读取保存的SPSR值

           BIC   r7, r7, r5

           ORR    r7, r7, r0                           ; 设置FIQ、IRQ位,保存SPSR

           B                STORE_SPSR

SetClearFIQIRQ:

           MRS    r7, SPSR                        ; 读取保存的SPSR值

           BIC     r7, r7, r5                           ; 清除FIQ、IRQ位

           CMP r6, #CLEAR_BIT              ; 判断是否等于 #CLEAR_BIT

           BEQ STORE_SPSR                       ; 相等的话,调到STORE_SPSR

         ORR    r7, r7, r5                    ; 不相等,则设置FIQ、IRQ位,保存SPSR

STORE_SPSR:

         MSR    SPSR, r7                          ;保存SPSR

           B                ExitSwi

DoIt:

           ;

         MRS    r4, CPSR                         ; 读取保存的SPSR值

         BIC     r4,r4,#MODE_MASK  ; 清除所有的模式位

         ORR    r4,r4,r5                    ;

         MSR    CPSR, r4                ;

           ;STACK  MANIPULATION

         MOV    SP, r0                            ; 堆栈地址

MOV          r1,r1,lsl #2            ;

         ADD     SP, r1, SP               ;

           BIC      r4,r4,#MODE_MASK ;

         ORR     r4,r4,#SUP_MODE        

         MSR     CPSR, r4              ;

         MRS     r4,SPSR              ;

         BIC      r4,r4,r6                 ;

         MSR     SPSR,r4              ;       

                   

ExitSwi:

           MOVS    PC, R14                              ; 从SWI返回

取指异常、数据异常、保留异常中断处理函数都是比较简单的,通常都不做详细地处理,具体代码如4)、5)、6)所示。

4)取指异常中断服务程序如下所示

;********************************************************************

    .def _INT_Prefetch_Abort

_INT_Prefetch_Abort

    MOV     r0, lr

B       _INT_Prefetch_Abort

5)数据异常中断服务程序如下所示

;********************************************************************

    .def _INT_Data_Abort

_INT_Data_Abort:

    STMDB   sp!,{r0-r3,lr}

    LDMIA   sp!,{r0-r3,lr}              

    BX      LR                          

B       _INT_Data_Abort

6)保留异常中断服务程序如下所示

;********************************************************************

    .def _INT_Reserved

_INT_Reserved:

    MOV     r0, lr

    B       _INT_Reserved

7)IRQ中断服务程序

当ARM处理器的外部中断请求有效,而且CPSR寄存器的I控制位被清除时,ARM处理器产生外部中断请求IRQ异常中断。一般来说系统中的各个外设通常都是通过该异常中断请求ARM处理器服务的。IRQ中断服务程序如下所示。

;********************************************************************

        .def    _INT_IRQ

_INT_IRQ:

; ARM Core Check

    STMDB   sp!, {r1}

    MRS     r1, SPSR

    TST     r1, #IRQ_BIT

    LDMIA   sp!, {r1}

    SUBNES  pc,lr,#4

    STMDB   sp!,{r0-r4}                     ; 保存R0~R4到当前的IRQ堆栈空间中

    SUB     lr,lr,#4                          ; 调整IRQ返回地址

;********************************

;* Begin Hardware Specific Code *

;********************************

    LDR     r3, INT_CNTRL_BASE_1            ;

    LDR     r4, [r3,#INT_CNTRL_MIR]         ;

;******************************

;* End Hardware Specific Code * 

;******************************

    STMDB   sp!,{r4}  ;

    MVN     r4,#0       ;

;********************************

;* Begin Hardware Specific Code *

;********************************

    LDR     r2, [r3,#INT_CNTRL_ITR]         ;

;******************************

;* End Hardware Specific Code *

;******************************

 LDR     r3, IRQ_Priority                ;

;以下流程在向量表里面进行优先级识别

IRQ_VECTOR_LOOP

    LDR     r0, [r3,#0]                    ; 从优先级表里面检查装载的第一个向量表

    MOV     r1, #1                           ;

    MOV     r1, r1, LSL r0                    ;

    TST     r1, r2                           ;

    BNE     IRQ_VECTOR_FOUND             ;

    BIC     r4,r4,r1                        ; 清除屏蔽位保证高级优先级

    ADD     r3, r3, #4                     ;

    ADR     r0, Priority_End          ;

    CMP     r0, r3   ;

    BNE     IRQ_VECTOR_LOOP        ;

    ;

    ADD     sp,sp,#4                                          ;

    LDMIA   sp!,{r0-r4}                                         ; 保存r0-r4

    STMDB   sp!,{lr}                                          ; 保存返回值

    LDMIA   sp!,{pc}^                               ; 保存SPSR等参数,返回

IRQ_VECTOR_FOUND

;********************************

;* Begin Hardware Specific Code *

;********************************

   LDR    r3, INT_CNTRL_BASE_1       

   MVN    r2, r1                      

   STR    r2, [r3,#INT_CNTRL_ITR]

   LDR    r2, [r3,#INT_CNTRL_MIR]        

   ORR    r4, r2, r4

   STR     r4, [r3,#INT_CNTRL_MIR]         ; 屏蔽所有低优先级中断

   MOV     r1, #1                                ; 清除pending中断

   STR     r1, [r3,#INT_CNTRL_CONTROL_REG]       ;

;******************************

;* End Hardware Specific Code *

;******************************

   LDR     r3, IRQ_Vectors                  ; 获取IRQ向量地址

   MOV     r2, r0, LSL #2        

    ADD     r3, r3, r2                                 ; 调整向量表地址到当前偏移量

   LDR     r2, [r3,#0]                       ; 从向量表转载跳转地址

   MOV     PC, r2                               ; 修改PC,进行跳转

; END: INT_IRQ

8)FIQ中断服务程序

当ARM处理器的快速中断请求有效,并且CPSR寄存器的F控制位被清除时,ARM处理器产生FIQ异常中断。FIQ中断服务程序如下所示。

;*************************************************************

    .def _INT_FIQ

_INT_FIQ

    .if $$isdefed("NU_FIQ_DEMO")

    STMDB   sp!, {r1}

    MRS     r1, SPSR

    TST     r1, #FIQ_BIT                        ;

    LDMIA   sp!, {r1}

    SUBNES  pc, lr, #4

    SUB     lr,lr,#4                                 ; 调整返回地址

    STMDB   sp!,{r0-r7,lr}                              ; 保存寄存器等到当前的FIQ堆栈空间

    LDR     r3, INT_CNTRL_BASE              ; 装载INT_CNTRL_BASE

    MOV     r1, #2                                          ; 清除pending中断

    STR     r1,[r3,#INT_CNTRL_CTRL_REG]  ;

    BL      _FIQ_LISR                                   ; 跳转到FIQ中断服务程序

    LDMIA   sp!,{r0-r7,pc}^                           ;

    .else

    B    _INT_FIQ

.endif

当然如果系统中很多中断没有用,那么对应的中断处理函数可以写得较为简单一些,甚至一条空语句就可以表示。主要的中断处理函数是IRQ和FIQ两个,在两个服务程序里面来判断中断状态寄存器,得到中断的产生源,然后分发出去。

在介绍了ARM处理器的复位向量表,以及相关的8个异常中断处理机制之后,接下来探讨一下在裸机方式下的常用程序调试方式。

5.2.3  程序调试方式

最常用的也是最方便的一种程序调试方式就是把程序加载到RAM区中去调试,在ADS集成开发环境下实现通常都需要一个入口函数。一个简单的例子程序代码如下。

    IMPORT  C_Entry

AREA    Init,CODE,READONLY

ENTRY

LDR R0,=0x3FF0000        ;初始化系统配置寄存器,它的地址为0X3FF0000

LDR R1,=0xE7FFFF80     ; Start_addr = 0x3FF00000

STR  R1,[R0]                   ; 4KB Cache,4KB SRAM,WB disable

   LDR      SP,=0x3FE1000      ;初始化用户堆栈,

BL    C_Entry                   ;跳转到函数C_Entry()处执行的C/C++代码

B.

END                                ;标识汇编代码的结束

在ADS下可以通过“Debug Settings”窗口设置RO Base(程序段的起始地址)和RW Base(数据段的起始地址),在“Options”选项卡中要注意指定程序实体entry(调试入口)的地址和“Equivalent Command Line”里面的组合语句的产生。在如图5-1所示的Debug Settings界面中,Image Entry point是0x40010000。注意一下图中红色圈里面的地址,这些地址都是在RAM区里面的。如果有多个程序时,可以在“Layout”选项卡里面指定第一个程序模块.o和第一个段名(Section)。通常填中断向量所在的模块。

图5‑1  Debug Settings界面

通过上面的介绍,现在就可以开始裸机驱动程序的设计了,不过要注意,主程序的入口函数一定是C_Entry()函数。裸机串口驱动的代码可以参考本书7.3介绍的代码例子。

阅读(2115) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~