stm32启动代码分析

转载:http://blog.csdn.net/chehlcy/article/details/5164472

学习STM32,看了一堆乱七八糟的文档,准备写程序了,先分析了下STM32的启动代码,看着这堆鬼鬼的汇编代码,挺吓人的,看看帮助,查查网路,还是不那么难懂。


;// <h> Stack Configuration
;//   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;// </h>
Stack_Size      EQU     0x00000200                           
		;//定义堆栈大小
                AREA    STACK, NOINIT, READWRITE, ALIGN=3    
		;//定义一个数据段 按8字节对齐
Stack_Mem       SPACE   Stack_Size                           
		;//保留Stack_Size大小的堆栈空间
__initial_sp                                                 
		;//标号,代表堆栈顶部地址,后面有用

;// <h> Heap Configuration
;//   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;// </h>
Heap_Size       EQU     0x00000020                            
		;//定义堆空间大小
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3      
		;//定义一个数据段,8字节对齐
__heap_base
Heap_Mem        SPACE   Heap_Size                             
		;//保留Heap_Size的堆空间
__heap_limit                                                  
		;//标号,代表堆末尾地址,后面有用

                PRESERVE8                                     
		;//指示编译器8字节对齐
                THUMB                                         
		;//指示编译器为THUMB指令

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY                  
		;//定义只读数据段,其实放在CODE区,位于0地址
                
                EXTERN  NMIException
                EXTERN  HardFaultException
                EXTERN  MemManageException
                EXTERN  BusFaultException
                EXTERN  UsageFaultException
                EXTERN  SVCHandler
                EXTERN  DebugMonitor
                EXTERN  PendSVC
                EXTERN  SysTickHandler                         
		;//声明这些符号在外部定义,同C				                                               
		;//在××it.c中实现这些函数 ,中断就能自动调用了
                
		EXPORT  __Vectors
__Vectors       DCD     __initial_sp              ; Top of Stack //Cotex-M  要求此处为堆栈顶部地址
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMIException              ; NMI Handler
                DCD     HardFaultException        ; Hard Fault Handler
                DCD     MemManageException        ; MPU Fault Handler
                DCD     BusFaultException         ; Bus Fault Handler
                DCD     UsageFaultException       ; Usage Fault Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVCHandler                ; SVCall Handler
                DCD     DebugMonitor              ; Debug Monitor Handler
                DCD     0                         ; Reserved
                DCD     PendSVC                   ; PendSV Handler
                DCD     SysTickHandler            ; SysTick Handler      
		//一大堆的异常处理函数地址
                
		; External Interrupts
                EXTERN  WWDG_IRQHandler
                EXTERN  PVD_IRQHandler
                EXTERN  TAMPER_IRQHandler
                EXTERN  RTC_IRQHandler
                EXTERN  FLASH_IRQHandler
                EXTERN  RCC_IRQHandler
                EXTERN  EXTI0_IRQHandler
                EXTERN  EXTI1_IRQHandler
                EXTERN  EXTI2_IRQHandler
                EXTERN  EXTI3_IRQHandler
                EXTERN  EXTI4_IRQHandler
                EXTERN  DMAChannel1_IRQHandler
                EXTERN  DMAChannel2_IRQHandler
                EXTERN  DMAChannel3_IRQHandler
                EXTERN  DMAChannel4_IRQHandler
                EXTERN  DMAChannel5_IRQHandler
                EXTERN  DMAChannel6_IRQHandler
                EXTERN  DMAChannel7_IRQHandler
                EXTERN  ADC_IRQHandler
                EXTERN  USB_HP_CAN_TX_IRQHandler
                EXTERN  USB_LP_CAN_RX0_IRQHandler
                EXTERN  CAN_RX1_IRQHandler
                EXTERN  CAN_SCE_IRQHandler
                EXTERN  EXTI9_5_IRQHandler
                EXTERN  TIM1_BRK_IRQHandler
                EXTERN  TIM1_UP_IRQHandler
                EXTERN  TIM1_TRG_COM_IRQHandler
                EXTERN  TIM1_CC_IRQHandler
                EXTERN  TIM2_IRQHandler
                EXTERN  TIM3_IRQHandler
                EXTERN  TIM4_IRQHandler
                EXTERN  I2C1_EV_IRQHandler
                EXTERN  I2C1_ER_IRQHandler
                EXTERN  I2C2_EV_IRQHandler
                EXTERN  I2C2_ER_IRQHandler
                EXTERN  SPI1_IRQHandler
                EXTERN  SPI2_IRQHandler
                EXTERN  USART1_IRQHandler
                EXTERN  USART2_IRQHandler
                EXTERN  USART3_IRQHandler
                EXTERN  EXTI15_10_IRQHandler
                EXTERN  RTCAlarm_IRQHandler
                EXTERN  USBWakeUp_IRQHandler                    
		;//同上,
                
                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   ;//同上

                AREA    |.text|, CODE, READONLY        
		;//定义代码段

; Reset Handler
Reset_Handler   PROC                                        
		;//Rset_Handler的实现
                
		EXPORT  Reset_Handler             [WEAK]    
		;//在外部没有定义该符号时导出该符号,见HELP中[WEAK]
                
		IMPORT  __main                              
		;//导入符号,__main为 运行时库提供的函数;完成堆栈,堆的初始话
                
		LDR     R0, =__main                         
		;//等工作,会调用下面定义的__user_initial_stackheap;
                
		BX      R0                                  
		;//跳到__main,进入C的世界
                
		ENDP

                ALIGN

; User Initial Stack & Heap
                IF      :DEF:__MICROLIB                     
		;//如果使用micro lib,micro lib 描述见armlib.chm
                
                EXPORT  __initial_sp
                EXPORT  __heap_base
                EXPORT  __heap_limit                        
		;//只导出几个定义
                
                ELSE                                        
		;//如果使用默认C运行时库
                
                IMPORT  __use_two_region_memory
                EXPORT  __user_initial_stackheap
__user_initial_stackheap                                    
		;//则进行堆栈和堆的赋值,在__main函数执行过程中调用。
                
		LDR     R0, =  Heap_Mem
                LDR     R1, =(Stack_Mem + Stack_Size)
                LDR     R2, = (Heap_Mem +  Heap_Size)
                LDR     R3, = Stack_Mem
                BX      LR
                ALIGN
                ENDIF

                END                                         ;//OK ,完了

版本二

当前的嵌入式应用程序开发过程里,并且C语言成为了绝大部分场合的最佳选择。如此一来main函数似乎成为了理所当然的起点——因为C程序往往从main函数开始执行。但一个经常会被忽略的问题是:微控制器(单片机)上电后,是如何寻找到并执行main函数的呢?很显然微控制器无法从硬件上定位main函数的入口地址,因为使用C语言作为开发语言后,变量/函数的地址便由编译器在编译时自行分配,这样一来main函数的入口地址在微控制器的内部存储空间中不再是绝对不变的。相信读者都可以回答这个问题,答案也许大同小异,但肯定都有个关键词,叫启动文件,用英文单词来描述是Bootloader

无论性能高下,结构简繁,价格贵贱,每一种微控制器(处理器)都必须有启动文件,启动文件的作用便是负责执行微控制器从复位开始执行main函数中间这段时间(称为启动过程)所必须进行的工作。最为常见的51AVRMSP430等微控制器当然也有对应启动文件,但开发环境往往自动完整地提供了这个启动文件,不需要开发人员再行干预启动过程,只需要从main函数开始进行应用程序的设计即可。

话题转到STM32微控制器,无论是keil
uvision4
还是IAR EWARM开发环境,ST公司都提供了现成的直接可用的启动文件,程序开发人员可以直接引用启动文件后直接进行C应用程序的开发。这样能大大减小开发人员从其它微控制器平台跳转至STM32平台,也降低了适应STM32微控制器的难度(对于上一代ARM的当家花旦ARM9,启动文件往往是第一道难啃却又无法逾越的坎)。

相对于ARM上一代的主流ARM7/ARM9内核架构,新一代Cortex内核架构的启动方式有了比较大的变化ARM7/ARM9内核的控制器在复位后,CPU会从存储空间的绝对地址0x000000取出第一条指令执行复位中断服务程序的方式启动,即固定了复位后的起始地址为0x000000PC = 0x000000)同时中断向量表的位置并不是固定的。而Cortex-M3内核则正好相反,有3种情况:
1
 通过boot引脚设置可以将中断向量表定位于SRAM区,即起始地址为0x2000000,同时复位后PC指针位于0x2000000处;
2
 通过boot引脚设置可以将中断向量表定位于FLASH区,即起始地址为0x8000000,同时复位后PC指针位于0x8000000处;
3
 通过boot引脚设置可以将中断向量表定位于内置Bootloader区,本文不对这种情况做论述;
Cortex-M3内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。
有了上述准备只是后,下面以STM322.02固件库提供的启动文件stm32f10x_vector.s为模板,对STM32的启动过程做一个简要而全面的解析。
程序清单一:
;文件stm32f10x_vector.s,其中注释为行号
DATA_IN_ExtSRAM EQU 0 1
Stack_Size EQU 0x00000400
 2
AREA STACK, NOINIT, READWRITE, ALIGN = 3 3
Stack_Mem SPACE Stack_Size
 4
__initial_sp
 5
Heap_Size EQU 0x00000400
 6
AREA HEAP, NOINIT, READWRITE, ALIGN = 3 7  可读写段保存于SRAM区,即0x2000000地址后
__heap_base
 8
Heap_Mem SPACE Heap_Size
 9
__heap_limit
 10
THUMB
 11
PRESERVE8
 12
IMPORT NMIException
 13
IMPORT HardFaultException
 14
IMPORT MemManageException
 15
IMPORT BusFaultException
 16
IMPORT UsageFaultException
 17
IMPORT SVCHandler
 18
IMPORT DebugMonitor
 19
IMPORT PendSVC
 20
IMPORT SysTickHandler
 21
IMPORT WWDG_IRQHandler
 22
IMPORT PVD_IRQHandler
 23
IMPORT TAMPER_IRQHandler
 24
IMPORT RTC_IRQHandler
 25
IMPORT FLASH_IRQHandler
 26
IMPORT RCC_IRQHandler
 27
IMPORT EXTI0_IRQHandler
 28
IMPORT EXTI1_IRQHandler
 29
IMPORT EXTI2_IRQHandler
 30
IMPORT EXTI3_IRQHandler
 31
IMPORT EXTI4_IRQHandler
 32
IMPORT DMA1_Channel1_IRQHandler
 33
IMPORT DMA1_Channel2_IRQHandler
 34
IMPORT DMA1_Channel3_IRQHandler
 35
IMPORT DMA1_Channel4_IRQHandler
 36
IMPORT DMA1_Channel5_IRQHandler
 37
IMPORT DMA1_Channel6_IRQHandler
 38
IMPORT DMA1_Channel7_IRQHandler
 39
IMPORT ADC1_2_IRQHandler
 40
IMPORT USB_HP_CAN_TX_IRQHandler
 41
IMPORT USB_LP_CAN_RX0_IRQHandler
 42
IMPORT CAN_RX1_IRQHandler
 43
IMPORT CAN_SCE_IRQHandler
 44
IMPORT EXTI9_5_IRQHandler
 45
IMPORT TIM1_BRK_IRQHandler
 46
IMPORT TIM1_UP_IRQHandler
 47
IMPORT TIM1_TRG_COM_IRQHandler
 48
IMPORT TIM1_CC_IRQHandler
 49
IMPORT TIM2_IRQHandler
 50
IMPORT TIM3_IRQHandler
 51
IMPORT TIM4_IRQHandler
 52
IMPORT I2C1_EV_IRQHandler
 53
IMPORT I2C1_ER_IRQHandler
 54
IMPORT I2C2_EV_IRQHandler
 55
IMPORT I2C2_ER_IRQHandler
 56
IMPORT SPI1_IRQHandler
 57
IMPORT SPI2_IRQHandler
 58
IMPORT USART1_IRQHandler
 59
IMPORT USART2_IRQHandler
 60
IMPORT USART3_IRQHandler
 61
IMPORT EXTI15_10_IRQHandler
 62
IMPORT RTCAlarm_IRQHandler
 63
IMPORT USBWakeUp_IRQHandler
 64
IMPORT TIM8_BRK_IRQHandler
 65
IMPORT TIM8_UP_IRQHandler
 66
IMPORT TIM8_TRG_COM_IRQHandler
 67
IMPORT TIM8_CC_IRQHandler
 68
IMPORT ADC3_IRQHandler
 69
IMPORT FSMC_IRQHandler
 70
IMPORT SDIO_IRQHandler
 71
IMPORT TIM5_IRQHandler
 72
IMPORT SPI3_IRQHandler
 73
IMPORT UART4_IRQHandler
 74
IMPORT UART5_IRQHandler
 75
IMPORT TIM6_IRQHandler
 76
IMPORT TIM7_IRQHandler
 77
IMPORT DMA2_Channel1_IRQHandler
 78
IMPORT DMA2_Channel2_IRQHandler
 79
IMPORT DMA2_Channel3_IRQHandler
 80
IMPORT DMA2_Channel4_5_IRQHandler
 81
AREA RESET, DATA, READONLY
 82      具有只读属性的段保存于FLASH区,即0x8000000地址后
EXPORT __Vectors
 83
__Vectors
 84
DCD __initial_sp
 85   其意义等价于C语言中的地址符&。因此从第84行开始建立的中断向量表则类似于使用C语言定义了一个指针数组,其每一个成员都是一个函数指针,分别指向各个中断服务函数。

DCD Reset_Handler
 86
DCD NMIException
 87
DCD HardFaultException
 88
DCD MemManageException
 89
DCD BusFaultException
 90
DCD UsageFaultException
 91
DCD 0
 92
DCD 0
 93
DCD 0
 94
DCD 0
 95
DCD SVCHandler
 96
DCD DebugMonitor
 97
DCD 0
 98
DCD PendSVC
 99
DCD SysTickHandler
 100
DCD WWDG_IRQHandler
 101
DCD PVD_IRQHandler
 102
DCD TAMPER_IRQHandler
 103
DCD RTC_IRQHandler
 104
DCD FLASH_IRQHandler
 105
DCD RCC_IRQHandler
 106
DCD EXTI0_IRQHandler
 107
DCD EXTI1_IRQHandler
 108
DCD EXTI2_IRQHandler
 109
DCD EXTI3_IRQHandler
 110
DCD EXTI4_IRQHandler
 111
DCD DMA1_Channel1_IRQHandler
 112
DCD DMA1_Channel2_IRQHandler
 113
DCD DMA1_Channel3_IRQHandler
 114
DCD DMA1_Channel4_IRQHandler
 115
DCD DMA1_Channel5_IRQHandler
 116
DCD DMA1_Channel6_IRQHandler
 117
DCD DMA1_Channel7_IRQHandler
 118
DCD ADC1_2_IRQHandler
 119
DCD USB_HP_CAN_TX_IRQHandler
 120
DCD USB_LP_CAN_RX0_IRQHandler
 121
DCD CAN_RX1_IRQHandler
 122
DCD CAN_SCE_IRQHandler
 123
DCD EXTI9_5_IRQHandler
 124
DCD TIM1_BRK_IRQHandler
 125
DCD TIM1_UP_IRQHandler
 126
DCD TIM1_TRG_COM_IRQHandler
 127
DCD TIM1_CC_IRQHandler
 128
DCD TIM2_IRQHandler
 129
DCD TIM3_IRQHandler
 130
DCD TIM4_IRQHandler
 131
DCD I2C1_EV_IRQHandler
 132
DCD I2C1_ER_IRQHandler
 133
DCD I2C2_EV_IRQHandler
 134
DCD I2C2_ER_IRQHandler
 135
DCD SPI1_IRQHandler
 136
DCD SPI2_IRQHandler
 137
DCD USART1_IRQHandler
 138
DCD USART2_IRQHandler
 139
DCD USART3_IRQHandler
 140
DCD EXTI15_10_IRQHandler
 141
DCD RTCAlarm_IRQHandler
 142
DCD USBWakeUp_IRQHandler
 143
DCD TIM8_BRK_IRQHandler
 144
DCD TIM8_UP_IRQHandler
 145
DCD TIM8_TRG_COM_IRQHandler
 146
DCD TIM8_CC_IRQHandler
 147
DCD ADC3_IRQHandler
 148
DCD FSMC_IRQHandler
 149
DCD SDIO_IRQHandler
 150
DCD TIM5_IRQHandler
 151
DCD SPI3_IRQHandler
 152
DCD UART4_IRQHandler
 153
DCD UART5_IRQHandler
 154
DCD TIM6_IRQHandler
 155
DCD TIM7_IRQHandler
 156
DCD DMA2_Channel1_IRQHandler
 157
DCD DMA2_Channel2_IRQHandler
 158
DCD DMA2_Channel3_IRQHandler
 159
DCD DMA2_Channel4_5_IRQHandler
 160
AREA |.text|, CODE, READONLY
 161
Reset_Handler
 PROC 162
EXPORT Reset_Handler
 163
IF DATA_IN_ExtSRAM == 1 164
LDR R0,= 0x00000114
 165
LDR R1,= 0x40021014
 166
STR R0,[R1]
 167
LDR R0,= 0x000001E0
 168
LDR R1,= 0x40021018
 169
STR R0,[R1]
 170
LDR R0,= 0x44BB44BB
 171
LDR R1,= 0x40011400
 172
STR R0,[R1]
 173
LDR R0,= 0xBBBBBBBB
 174
LDR R1,= 0x40011404
 175
STR R0,[R1]
 176
LDR R0,= 0xB44444BB
 177
LDR R1,= 0x40011800
 178
STR R0,[R1]
 179
LDR R0,= 0xBBBBBBBB
 180
LDR R1,= 0x40011804
 181
STR R0,[R1]
 182
LDR R0,= 0x44BBBBBB
 183
LDR R1,= 0x40011C00
 184
STR R0,[R1]
 185
LDR R0,= 0xBBBB4444
 186
LDR R1,= 0x40011C04
 187
STR R0,[R1]
 188
LDR R0,= 0x44BBBBBB
 189
LDR R1,= 0x40012000
 190
STR R0,[R1]
 191
LDR R0,= 0x44444B44
 192
LDR R1,= 0x40012004
 193
STR R0,[R1]
 194
LDR R0,= 0x00001011
 195
LDR R1,= 0xA0000010
 196
STR R0,[R1]
 197
LDR R0,= 0x00000200
 198
LDR R1,= 0xA0000014
 199
STR R0,[R1]
 200
ENDIF 201
IMPORT __main 202   声明__main标号
LDR R0, =__main
 203   跳转__main地址执行
BX R0 204                __main标号表示C/C++标准实时库函数里的一个初始化子程序__main的入口地址。该程序的一个主要作用是初始化堆栈(对于程序清单一来说则是跳转__user_initial_stackheap标号进行初始化堆栈的),并初始化映像文件,最后跳转C程序中的main函数。
ENDP 205
ALIGN
 206
IF :DEF:__MICROLIB
 207
EXPORT __initial_sp
 208
EXPORT __heap_base
 209
EXPORT __heap_limit
 210
ELSE
 211
IMPORT __use_two_region_memory
 212
EXPORT __user_initial_stackheap
 213
__user_initial_stackheap
 214    用户堆栈初始化程序入口
LDR R0, = Heap_Mem
 215        保存栈顶指针和栈大小
LDR R1, = (Stack_Mem + Stack_Size)
 216 
LDR R2, = (Heap_Mem + Heap_Size)
 217  堆始地址和堆大小
LDR R3, = Stack_Mem
 218
BX LR 219
ALIGN
 220
ENDIF
 221
END
 222
ENDIF
 223
END
 224


如程序清单一,STM32的启动代码一共224行,使用了汇编语言编写,这其中的主要原因下文将会给出交代。现在从第一行开始分析:
 1行:定义是否使用外部SRAM,为1则使用,为0则表示不使用。此语行若用C语言表达则等价于:
#define DATA_IN_ExtSRAM 0
 2行:定义栈空间大小为0x00000400个字节,即1Kbyte1024  此语行亦等价于:
#define Stack_Size 0x00000400
 3行:伪指令AREA,表示
 4行:开辟一段大小为Stack_Size的内存空间作为栈。Stack_Mem SPACE Stack_Size
 5行:标号__initial_sp,表示栈空间顶地址。
 6行:定义堆空间大小为0x00000400个字节,也为1Kbyte
 7行:伪指令AREA,表示
 8行:标号__heap_base,表示堆空间起始地址
 9行:开辟一段大小为Heap_Size的内存空间作为堆。
 10行:标号__heap_limit,表示堆空间结束地址
 11行:告诉编译器使用THUMB指令集。
 12行:告诉编译器以8字节对齐。
 1381行:IMPORT指令,指示后续符号是在外部文件定义的(类似C语言中的全局变量声明),而下文可能会使用到这些符号。
 82行:定义只读数据段,实际上是在CODE区(假设STM32FLASH启动,则此中断向量表起始地址即为0x8000000
 83行:将标号__Vectors声明为全局标号,这样外部文件就可以使用这个标号。EXPORT __Vectors 
 84行:标号__Vectors,表示中断向量表入口地址。
 85160行:建立中断向量表。
 161行:
 162行:复位中断服务程序,PROCENDP结构表示程序的开始和结束Reset_Handler PROC
 163行:声明复位中断向量Reset_Handler为全局属性,这样外部文件就可以调用此复位中断服务。
 164行:IFENDIF为预编译结构,判断是否使用外部SRAM,在第1行中已定义为不使用
 165201行:此部分代码的作用是设置FSMC总线以支持SRAM,因不使用外部SRAM因此此部分代码不会被编译。
 202行:声明__main标号。
 203204行:跳转__main地址执行。
 207行:IFELSEENDIF结构,判断是否使用DEF:__MICROLIB(此处为不使用)。
 208210行:若使用DEF:__MICROLIB,则将__initial_sp__heap_base__heap_limit亦即栈顶地址,堆始末地址赋予全局属性,使外部程序可以使用。
 212行:定义全局标号__use_two_region_memory
 213行:声明全局标号__user_initial_stackheap,这样外程序也可调用此标号。
 214行:标号__user_initial_stackheap,表示用户堆栈初始化程序入口。
 215218行:分别保存栈顶指针和栈大小,堆始地址和堆大小至R0R1R2R3寄存器。
 224行:程序完毕。
以上便是STM32的启动代码的完整解析,接下来对几个小地方做解释:
1
 AREA指令:伪指令,用于定义代码段或数据段,后跟属性标号。其中比较重要的一个标号为READONLY或者READWRITE,其中READONLY表示该段为只读属性,联系到STM32的内部存储介质,可知具有只读属性的段保存于FLASH区,即0x8000000地址后。而READWRITE表示该段为可读写属性,可知可读写段保存于SRAM区,即0x2000000地址后。由此可以从第37行代码知道,堆栈段位于SRAM空间。从第82行可知,中断向量表放置与FLASH区,而这也是整片启动代码中最先被放进FLASH区的数据。因此可以得到一条重要的信息:0x8000000地址存放的是栈顶地址__initial_sp0x8000004地址存放的是复位中断向量Reset_HandlerSTM32使用32位总线,因此存储空间为4字节对齐)。
2
 DCD指令:作用是开辟一段空间,其意义等价于C语言中的地址符&。因此从第84行开始建立的中断向量表则类似于使用C语言定义了一个指针数组,其每一个成员都是一个函数指针,分别指向各个中断服务函数。
3
 标号:前文多处使用了标号一词。标号主要用于表示一片内存空间的某个位置,等价于C语言中的地址概念。地址仅仅表示存储空间的一个位置,从C语言的角度来看,变量的地址,数组的地址或是函数的入口地址在本质上并无区别。
4
 202行中的__main标号并不表示C程序中的main函数入口地址,因此第204行也并不是跳转至main函数开始执行C程序。__main标号表示C/C++标准实时库函数里的一个初始化子程序__main的入口地址。该程序的一个主要作用是初始化堆栈(对于程序清单一来说则是跳转__user_initial_stackheap标号进行初始化堆栈的),并初始化映像文件,最后跳转C程序中的main函数。这就解释了为何所有的C程序必须有一个main函数作为程序的起点——因为这是由C/C++标准实时库所规定的——并且不能更改,因为C/C++标准实时库并不对外界开发源代码。因此,实际上在用户可见的前提下,程序在第204行后就跳转至.c文件中的main函数,开始执行C程序了。
至此可以总结一下STM32的启动文件和启动过程。首先对栈和堆的大小进行定义,并在代码区的起始处建立中断向量表,其第一个表项是栈顶地址,第二个表项是复位中断服务入口地址。然后在复位中断服务程序中跳转¬¬C/C++标准实时库的__main函数,完成用户堆栈等的初始化后,跳转.c文件中的main函数开始执行C程序。假设STM32被设置为从内部FLASH启动(这也是最常见的一种情况),中断向量表起始地位为0x8000000,则栈顶地址存放于0x8000000处,而复位中断服务入口地址存放于0x8000004处。当STM32遇到复位信号后,则从0x80000004处取出复位中断服务入口地址,继而执行复位中断服务程序,然后跳转__main函数,最后进入mian函数,来到C的世界。


STM32启动代码问题

能否讲解一下startup_stm32f10x_cl.s启动代码含义,谢谢!

我现在看反汇编如下
0x08000000 0678      LSLS     r0,r7,#25            (查看Memory窗口0x08000000  :  78 06 00 20 ---STM32小端缘故)

0x08000002 2000      MOVS     r0,#0x00
0x08000004 1105      ASRS     r5,r0,#408
0x08000006 0800      LSRS     r0,r0,#00A
。。。。。。。。。。。。。。。。。。。。。。

上面应该对应
__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



0x08001104 4808      LDR      r0,[pc,#32]  ;  程序一运行跳到这里,why?
0x08001106 4700      BX       r0,r0,#0

上面对应
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  __main
                 LDR     R0, =__main
                 BX      R0
                 ENDP

那位能说一下为什么跳到0x08001104,即PC =0x08001104, 我想应该PC应该先跳到0x08000000?

 

解答

cortex-M3和ARM9的架构有很大区别,ARM7、ARM9在复位后是从地址0处开始执行指令,也就是说地址0x00000000的内容是指令。而cortex-M3的异常向量表中的内容并不是指令,0x00000000处(当然也可能映射到别的范围)是主堆栈指针的数值,0x00000004的内容是复位后需要跳转到的地址,是一个地址而不是一条指令。

 

stm32选择flash启动方式,中断向量表映射到0x08000000,由楼主给出的反汇编可知,复位后主堆栈指针的位置是0x20000678,0x08000004位置的数值是0x08001105,由于cortex-M3只能运行在thumb2状态,所以要保证向PC(R15)写入的数值的bit0必须是1(如果向PC写入的数值的bit0是0,则处理器认为试图切入ARM状态,会产生fault),而实际上stm32的指令是半字对齐的,所以复位后会跳转到0x08001104.


  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值