STM32与ARM启动代码比较分析

STM32与ARM启动代码比较

原创: xiaoyunsoft@163.com

转载请保持本文完整性

 

从ARM转到STM开发,开发工具也由ADS转到了Keil。借助STM的固件库,使得开发效率更加高效,比如你可以不用关心启动代码的具体实现,只需要专注于具体的应用代码,嵌入式开发也变得越来越“傻瓜”。此事好坏,暂且不论,来看看STM启动代码的特点,或者说相对于ARM的区别。

 

通常的启动代码结构:

1.  首先是中断向量表的定义.

Ø         ARM

ARM代码在这块的代码为跳转语句,因为指令长度的限制,4个字节也就能放个跳转语就差不多了。通常两种实现方式:

1.       B   Reset_Handler

2.       LDR PC, Reset_Handler

其实都是一个意思,跳转到真正实现Reset_Handler功能的地方去。ARM中断向量在这里总共有8条(复位、未定义、SWI、指令、数据异常、预留、IRQ、FIQ),具体的当前中断类型,在IRQ或FIQ的中断实现里面判断,之后再转到对应的中断处理函数里面。

注意,仔细看,想一想,这里的中断向量处存放的是机器指令码。然而,STM在中断向量处存放的是实现中断功能的入口地址,而不是指令功能码。

 

Ø         STM

正如上面所说,STM中断向量处存放的是目标地址。但是要注意的是,第一条中断向量存放的堆栈的地址,真正的传统意义上的中断向量从第二条开始。除此之外,STM的中断向量表很长,它不像ARM由IRQ或FIQ进行判断后再处理,而是将所有的中断处理函数入口地址全列在这里:

 

__Vectors      DCD     __initial_sp          ; Top of Stack

                DCD     Reset_Handler         ; Reset Handler

                DCD     NMI_Handler           ; NMI Handler

                DCD     HardFault_Handler     ; Hard Fault Handler

                DCD     MemManage_Handler     ; MPU Fault Handler

                DCD     BusFault_Handler      ; Bus Fault Handler

                DCD     UsageFault_Handler    ; Usage Fault Handler

                DCD     0                       ; Reserved

                DCD     0                       ; Reserved

                DCD     0                      ; Reserved

                DCD     0                      ; Reserved

                DCD     SVC_Handler           ; SVCall Handler

                DCD     DebugMon_Handler     ; Debug Monitor Handler

                DCD     0                      ; Reserved

                DCD     PendSV_Handler       ; PendSV Handler

                DCD     SysTick_Handler      ; SysTick Handler

 

                ; External Interrupts

                DCD     WWDG_IRQHandler      ; Window Watchdog

                DCD     PVD_IRQHandler       ; PVD through EXTI Line detect

                DCD     TAMPER_IRQHandler    ; Tamper

                …………….

 

 

2.  中断函数的跳转实现

这块功能的实现依赖于编译器、链接器的功能,实现方法各不相同。

Ø         ARM

        CODE32

                AREA    Startup,CODE,READONLY

Vectors

LDR     PC, ResetAddr

              LDR     PC, UndefinedAddr

              LDR     PC, SWI_Addr

              LDR     PC, PrefetchAddr

              LDR     PC, DataAbortAddr

              B            .

              LDR       PC, IRQ_Addr ;跳转至标号IRQ_Addr处

              LDR     PC, FIQ_Addr

 

ResetAddr              DCD     Reset

UndefinedAddr      DCD     Undefined

SWI_Addr               DCD     SoftwareInterrupt

PrefetchAddr         DCD     PrefetchAbort

DataAbortAddr      DCD     DataAbort

Nouse                    DCD     0

IRQ_Addr              DCD     IRQ_Handler ; IRQ_Addr定义为IRQ_Handler地址

FIQ_Addr               DCD     FIQ_Handler

 

; IRQ_Handler在这里定义

IRQ_Handler

           SUB SP, SP, #4

           STMFD SP!, {R8-R9}   

           LDR R9, =INTOFFSET

           LDR R9, [R9]

           LDR       R8, =HandleEINT0

           ADD R8, R8,R9,LSL #2

           LDR R8, [R8]

           STR R8, [SP,#8]

           LDMFD SP!,{R8-R9,PC}

 

注意上面的HandleEINT0标号,它是中断函数的入口首地址,加上当前中断编号的偏移值INTOFFSET。具体对应到哪里呢?看下面:

;这是定义(或者说预留)一个段指定位置开始的内存空间.

         MAP (0x33FFBF00)      

SysRstVector    #     4    

UdfInsVector     #     4    

SwiSvcVector    #     4

InsAbtVector     #     4

DatAbtVector     #     4

ReservedVector       #     4

IrqSvcVector      #     4

FiqSvcVector     #     4

 

HandleEINT0        #   4

HandleEINT1          #   4

HandleEINT2          #   4

HandleEINT3          #   4

HandleEINT4_7     #   4

….

实际上这里也可以理解为定义一个结构体变量,各个标号对应结构体的域,跟C语言不同的是,这里定义的结构体变量可以指定它在内存空间中的地址。

好了,如果当前来了一个IRQ类型的EINT3中断,按照上面的代码应该是跳转至以HandleEINT3这个域存储的值为地址处。那么HandleEINT3这个域里存储的值是什么呢?

下面的代码即可在C语言中定义了。

#define _ISR_STARTADDRESS   0x33FFBF00

#define pISR_EINT3     (*(unsigned *)(_ISR_STARTADDRESS+0x2c))

pISR_EINT3 = (unsigned int)EINT3_Handler; 

static void __irq EINT3_Handler(void)

{

}

 

Ø         STM32

STM32中断处理实现跟ARM不一样。来看代码:

启动代码处的中断向量表(我们以EXTI0为例):

__Vectors      DCD     __initial_sp              ; Top of Stack

                DCD     Reset_Handler           ; Reset Handler

                DCD     NMI_Handler             ; NMI Handler

                DCD     HardFault_Handler       ; Hard Fault Handler

                DCD     MemManage_Handler    ; MPU Fault Handler

                DCD     BusFault_Handler        ; Bus Fault Handler

                DCD     UsageFault_Handler      ; Usage Fault Handler

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     SVC_Handler             ; SVCall Handler

                DCD     DebugMon_Handler       ; Debug Monitor Handler

                DCD     0                         ; Reserved

                DCD     PendSV_Handler          ; PendSV Handler

                DCD     SysTick_Handler          ; SysTick Handler

 

                ; External Interrupts

                DCD     WWDG_IRQHandler        ; Window Watchdog

                DCD     PVD_IRQHandler           ; PVD through EXTI Line detect

                DCD     TAMPER_IRQHandler       ; Tamper

                DCD     RTC_IRQHandler           ; RTC

                DCD     FLASH_IRQHandler         ; Flash

                DCD     RCC_IRQHandler           ; RCC

                DCD     EXTI0_IRQHandler      ; EXTI Line 0 中断发生时跳转至EXT0_IRQHandler地址处。@@@记住这条代码,下面以此处为例@@@

                       ….

 

Default_Handler PROC

                EXPORT  WWDG_IRQHandler           [WEAK]

                EXPORT  PVD_IRQHandler            [WEAK]

                EXPORT  TAMPER_IRQHandler         [WEAK]

                EXPORT  RTC_IRQHandler            [WEAK]

                EXPORT  FLASH_IRQHandler          [WEAK]

                EXPORT  RCC_IRQHandler            [WEAK]

                EXPORT  EXTI0_IRQHandler          [WEAK]

                       …..

WWDG_IRQHandler

PVD_IRQHandler

TAMPER_IRQHandler

RTC_IRQHandler

FLASH_IRQHandler

RCC_IRQHandler

EXTI0_IRQHandler

EXTI1_IRQHandler

….

       B   .

                ENDP

 

这段是啥意思呢?这里是定义各个中断向量的处理函数处,所有列出来的中断向量处理函数地址一致,功能也是一致:原地跳转。

既然所有的中断处理函数功能一致,那它是如何跳转至用户定义在C语言中的中断处理函数的呢?答案是,如果用户没有在用户代码(C语言)中定义对应向量的中断处理函数,则实际起作用的真正的中断处理函数即为上面列出的原地跳转功能处。

它是如何实现的? 注意到在声明导出处理函数后面的[WEAK]了吗?它的功能由链接器实现:如果在别处也定义该标号(函数),在链接时用别处的地址。如果没有其它定方定义,则以此处地址进行链接。

可能不太好理解,实际上是启动代码已经预定义了中断处理函数,它的功能很简单,就是原地跳转。只不过这块预定义的中断处理函数是否真正起作用,要看你是否在别处重定义了相同标号的中断处理函数。如果你已经重定义了,则以你重定义的中断处理函数为准。

以EXTI0中断为列,假设用户在自已的代码中配置好了EXTI0的中断,并且重定义了下面的EXTI0_IRQHandler函数,则链接器会以此函数地址进行链接。

void EXTI0_IRQHandler()

{

}

 

也就是在上面启动代码的@@@标注处(DCD  EXTI0_IRQHandler),会以用户重定义的EXTI0_IRQHandler()函数地址填入。

 

2011-10-20

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值