STM32F103X启动代码详细分析

2012/9/2

1.      在分析启动代码之前,先把STM32的存储结构说一下:

上面这张图来自CORTEX M3权威指南

STM32F103RTB6 有20k的SRAM,起始地址为0x20000000,128k的闪存flash,起始地址为0x08000000(处于code区域).

         从主闪存存储器启动时,主闪存存储器被映射到启动空间(0x00000000),但仍然能够在它原有的地址(0x08000000)访问它,即闪存存储器的内容可以在两个地址区域访问,0x00000000或0x0800 0000。

         通过boot0和boot1的配置可以选着三种启动方式:


当我们下载程序时,选着的是系统存储器启动,当我们一上电开始跑程序的时候,应选择闪存flash启动.

1.      再明确一下一些代码对齐的规则:

1.1   字对齐: 4字节对齐,ARM指令时32位一跳的; 半字对齐: 2字节对齐.thumb指令是16位一跳的。而CORTEX-M3  是thumb-2指令集,16位32位都有

1.2   注意align的不同:

AREA    STACK, NOINIT, READWRITE, ALIGN=3

此处的align表示接下来的堆栈段是2^3=8字节对齐的

单纯.align或ALIGN表示字对齐(32位)

3.我想我们还要明确比较重要的一点,既然我们的程序是从flash闪存上开始执行的,在STM32中文手册上由这么一句话:,CPU从地址0x0000 0000获取堆栈顶的地址,并从启动存储器的0x00000004指示的地址开始执行代码。而0x00000004开始的地址放的是什么呢?我可以告诉你从该处开始放的是cortex-m3规定的异常向量表。而且我们还可以确定,0x0000 0004出放的必然是复位异常向量。

4.下面好好来分析启动代码,我从keil得到的文件是STM32F10X.s,跟着我的注释走吧

//栈大小

Stack_Size      EQU    0x00000200                

//定义堆栈段,8字节对齐,注意,是可读写!!而我们的闪存flash是要擦除后才能写的,这就有问题了,说明我们的堆栈段不可能是安排在Flash闪存上的,那安排在哪呢?当然是内部20k的SRAM上啦!

                AREA    STACK, NOINIT, READWRITE, ALIGN=3

//stack_Mem为堆栈的底部,SPACE表示存储Stack_size个 分配单元

Stack_Mem       SPACE  Stack_Size

//__initial_sp很显然表示的是栈顶地址

__initial_sp

//下面是在SRAM上分配堆空间,大小为0

Heap_Size       EQU    0x00000000

 

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3

//__heap_base和Heap_Mem为堆起始地址

__heap_base

Heap_Mem        SPACE  Heap_Size

//__heap_limit为堆结束的地址

__heap_limit

//8字节对齐,在keil中必须要这一条

                PRESERVE8

//使用的是thumb指令集,但是cortex-m3是thumb-2版本,16位和32位的指令都有

       THUMB

//只读代码段

                AREA    RESET, DATA, READONLY

//导出__Vectors中断向量表起始地址,相当于在此声明__Vectors为一个全局变量,别的文件时可以访问到的   

                            EXPORT __Vectors

//前面说过0x0地址必须放堆栈顶地址

__Vectors       DCD    __initial_sp              ; Top ofStack

//接下来是一些异常向量表,当发生该异常时,PC将会跳到这里执行

                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

                DCD     EXTI1_IRQHandler          ; EXTI Line 1

                DCD     EXTI2_IRQHandler          ; EXTI Line 2

                DCD     EXTI3_IRQHandler          ; EXTI Line 3

                DCD     EXTI4_IRQHandler          ; EXTI Line 4

                DCD     DMAChannel1_IRQHandler    ; DMA Channel 1

                DCD     DMAChannel2_IRQHandler    ; DMA Channel 2

                DCD     DMAChannel3_IRQHandler    ; DMA Channel 3

                DCD     DMAChannel4_IRQHandler    ; DMA Channel 4

                DCD     DMAChannel5_IRQHandler    ; DMA Channel 5

                DCD     DMAChannel6_IRQHandler    ; DMA Channel 6

                DCD     DMAChannel7_IRQHandler    ; DMA Channel 7

                DCD     ADC_IRQHandler            ; ADC

                DCD     USB_HP_CAN_TX_IRQHandler  ; USB High Priority or CAN TX

                DCD     USB_LP_CAN_RX0_IRQHandler ; USB Low  Priority or CAN RX0

                DCD     CAN_RX1_IRQHandler        ; CAN RX1

                DCD     CAN_SCE_IRQHandler        ; CAN SCE

                DCD     EXTI9_5_IRQHandler        ; EXTI Line 9..5

                DCD     TIM1_BRK_IRQHandler       ; TIM1 Break

                DCD     TIM1_UP_IRQHandler        ; TIM1 Update

                DCD     TIM1_TRG_COM_IRQHandler   ; TIM1 Trigger and Commutation

                DCD     TIM1_CC_IRQHandler        ; TIM1 Capture Compare

                DCD     TIM2_IRQHandler           ; TIM2

               DCD     TIM3_IRQHandler           ; TIM3

                DCD     TIM4_IRQHandler           ; TIM4

                DCD     I2C1_EV_IRQHandler        ; I2C1 Event

                DCD     I2C1_ER_IRQHandler        ; I2C1 Error

                DCD     I2C2_EV_IRQHandler        ; I2C2 Event

                DCD     I2C2_ER_IRQHandler        ; I2C2 Error

                DCD     SPI1_IRQHandler           ; SPI1

                DCD     SPI2_IRQHandler           ; SPI2

                DCD     USART1_IRQHandler         ; USART1

                DCD     USART2_IRQHandler         ; USART2

                DCD     USART3_IRQHandler         ; USART3

                DCD     EXTI15_10_IRQHandler      ; EXTI Line 15..10

                DCD     RTCAlarm_IRQHandler       ; RTC Alarm through EXTI Line

                DCD     USBWakeUp_IRQHandler      ; USB Wakeup from suspend

//声明代码段|.text|是约定的代码段名称

AREA    |.text|, CODE,READONLY

//中断异常向量的函数指针

Reset_Handler   PROC

//到处该符号,[WEAK]表示如果外部有同名符号,外部该同名符号是优先使用的

                EXPORT  Reset_Handler             [WEAK]

//__main标号起始不是我们c语言中的main函数,而是C/C++标准实时库函数里的一个初始化子程序__main的入口地址,该程序的一个主要作用是初始化堆栈(对于我们的程序来说是跳转到后面的_user_initial_stackheap标号出进行初始化堆栈),并初始化映象文件,最后跳转到C程序的main函数。我们就理解为__main最后就跳到了main吧

                IMPORT  __main

                LDR     R0, =__main

                BX      R0

                ENDP

//下面就是其他向量的函数地址了,这里只是简单的死循环,不做任何处理,然而很有意思的是,他们都EXPORT…[WEAK]了,所以,当我们要设置该异常的中断向量函数时,以我们设置的同名标号为准,这就是我们经常在keil中写的各个外部中断的handler了,然而,当没有设置这个异常的中断函数就引发了该中断,程序就会死在中断函数入口了。

; Dummy Exception Handlers (infinite loopswhich can be modified)               

 

NMI_Handler     PROC

                EXPORT  NMI_Handler               [WEAK]

                B       .

                ENDP

HardFault_Handler\

                PROC

                EXPORT  HardFault_Handler         [WEAK]

                B       .

                ENDP

MemManage_Handler\

                PROC

                EXPORT  MemManage_Handler         [WEAK]

                B       .

                ENDP

BusFault_Handler\

                PROC

                EXPORT  BusFault_Handler          [WEAK]

                B       .

                ENDP

UsageFault_Handler\

                PROC

                EXPORT  UsageFault_Handler        [WEAK]

                B       .

                ENDP

SVC_Handler     PROC

                EXPORT  SVC_Handler               [WEAK]

                B       .

                ENDP

DebugMon_Handler\

                PROC

                EXPORT  DebugMon_Handler          [WEAK]

                B       .

                ENDP

PendSV_Handler  PROC

                EXPORT  PendSV_Handler            [WEAK]

                B       .

                ENDP

SysTick_Handler PROC

                EXPORT  SysTick_Handler           [WEAK]

                B       .

                ENDP

 

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]

                EXPORT  EXTI1_IRQHandler          [WEAK]

                EXPORT  EXTI2_IRQHandler          [WEAK]

                EXPORT  EXTI3_IRQHandler          [WEAK]

                EXPORT  EXTI4_IRQHandler          [WEAK]

                EXPORT  DMAChannel1_IRQHandler    [WEAK]

                EXPORT  DMAChannel2_IRQHandler    [WEAK]

                EXPORT  DMAChannel3_IRQHandler    [WEAK]

                EXPORT  DMAChannel4_IRQHandler    [WEAK]

                EXPORT  DMAChannel5_IRQHandler    [WEAK]

                EXPORT  DMAChannel6_IRQHandler    [WEAK]

                EXPORT  DMAChannel7_IRQHandler    [WEAK]

                EXPORT  ADC_IRQHandler            [WEAK]

                EXPORT  USB_HP_CAN_TX_IRQHandler  [WEAK]

                EXPORT  USB_LP_CAN_RX0_IRQHandler [WEAK]

                EXPORT  CAN_RX1_IRQHandler        [WEAK]

                EXPORT  CAN_SCE_IRQHandler        [WEAK]

                EXPORT  EXTI9_5_IRQHandler        [WEAK]

                EXPORT  TIM1_BRK_IRQHandler       [WEAK]

                EXPORT  TIM1_UP_IRQHandler        [WEAK]

                EXPORT  TIM1_TRG_COM_IRQHandler   [WEAK]

                EXPORT  TIM1_CC_IRQHandler        [WEAK]

                EXPORT  TIM2_IRQHandler           [WEAK]

                EXPORT  TIM3_IRQHandler           [WEAK]

                EXPORT  TIM4_IRQHandler           [WEAK]

                EXPORT  I2C1_EV_IRQHandler        [WEAK]

                EXPORT  I2C1_ER_IRQHandler        [WEAK]

                EXPORT  I2C2_EV_IRQHandler        [WEAK]

                EXPORT  I2C2_ER_IRQHandler        [WEAK]

                EXPORT  SPI1_IRQHandler           [WEAK]

                EXPORT  SPI2_IRQHandler           [WEAK]

                EXPORT  USART1_IRQHandler         [WEAK]

                EXPORT  USART2_IRQHandler         [WEAK]

                EXPORT  USART3_IRQHandler         [WEAK]

                EXPORT  EXTI15_10_IRQHandler      [WEAK]

                EXPORT  RTCAlarm_IRQHandler       [WEAK]

                EXPORT  USBWakeUp_IRQHandler      [WEAK]

 

WWDG_IRQHandler

PVD_IRQHandler

TAMPER_IRQHandler

RTC_IRQHandler

FLASH_IRQHandler

RCC_IRQHandler

EXTI0_IRQHandler

EXTI1_IRQHandler

EXTI2_IRQHandler

EXTI3_IRQHandler

EXTI4_IRQHandler

DMAChannel1_IRQHandler

DMAChannel2_IRQHandler

DMAChannel3_IRQHandler

DMAChannel4_IRQHandler

DMAChannel5_IRQHandler

DMAChannel6_IRQHandler

DMAChannel7_IRQHandler

ADC_IRQHandler

USB_HP_CAN_TX_IRQHandler

USB_LP_CAN_RX0_IRQHandler

CAN_RX1_IRQHandler

CAN_SCE_IRQHandler

EXTI9_5_IRQHandler

TIM1_BRK_IRQHandler

TIM1_UP_IRQHandler

TIM1_TRG_COM_IRQHandler

TIM1_CC_IRQHandler

TIM2_IRQHandler

TIM3_IRQHandler

TIM4_IRQHandler

I2C1_EV_IRQHandler

I2C1_ER_IRQHandler

I2C2_EV_IRQHandler

I2C2_ER_IRQHandler

SPI1_IRQHandler

SPI2_IRQHandler

USART1_IRQHandler

USART2_IRQHandler

USART3_IRQHandler

EXTI15_10_IRQHandler

RTCAlarm_IRQHandler

USBWakeUp_IRQHandler

 

                B       .

 

                ENDP

// 字对齐(32位)

ALIGN

; User Initial Stack & Heap

//这里我们没有定义__MICROLIB,走下面分支

                IF      :DEF:__MICROLIB

                //导出栈顶,堆头和堆尾地址

                EXPORT  __initial_sp

                EXPORT  __heap_base

                EXPORT  __heap_limit

               

                ELSE

               

               

IMPORT __use_two_region_memory

//一个小函数,我们前面提到在__main中会调用他来初始化堆栈

                EXPORT  __user_initial_stackheap

__user_initial_stackheap

                                     //传入这些关于堆栈的地址,作为参数

                LDR     R0, = Heap_Mem

                LDR     R1, =(Stack_Mem + Stack_Size)

                LDR     R2, = (Heap_Mem +  Heap_Size)

                LDR     R3, = Stack_Mem

                                     //调回__mian中调用__user_initial_stackheap的地方去

                BX      LR

 

               ALIGN

 

                ENDIF

//汇编结束

END


你可能感兴趣的:(嵌入式软件)