解析STM32的启动过程(转载)

转载自:http://9mcu.com/9mcubbs/forum.php?mod=viewthread&tid=1051037

当前的嵌入式应用程序开发过程里,并且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
__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
EXPORT  __Vectors                                                        
83
__Vectors                                                                          
84
DCD  __initial_sp                                                       
85
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
LDR     R0, =__main                                                        
203
BX      R0                                                                        
204
ENDP                                                                                
205
ALIGN                                                                                
206
IF      EF:__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行,使用了汇编语言编写,这其中的主要原因下文将会给出交代。现在从第一行开始分析:
    l    1行:定义是否使用外部SRAM,为1则使用,为0则表示不使用。此语行若用C语言表达则等价于:
#define        DATA_IN_ExtSRAM         0
    
l    2行:定义栈空间大小为0x00000400个字节,即1Kbyte。此语行亦等价于:
#define        Stack_Size                        0x00000400
        
3行:伪指令AREA,表示l
    l    4行:开辟一段大小为Stack_Size的内存空间作为栈。
        5行:标号__initial_sp,表示栈空间顶地址。l
l       6行:定义堆空间大小为0x00000400个字节,也为1Kbyte
        7行:伪指令AREA,表示l
    l    8行:标号__heap_base,表示堆空间起始地址。
        9行:开辟一段大小为Heap_Size的内存空间作为堆。l
l       10行:标号__heap_limit,表示堆空间结束地址。
        11行:告诉编译器使用THUMB指令集。l
    l    12行:告诉编译器以8字节对齐。
    l    13—81行:IMPORT指令,指示后续符号是在外部文件定义的(类似C语言中的全局变量声明),而下文可能会使用到这些符号。
    l    82行:定义只读数据段,实际上是在CODE区(假设STM32FLASH启动,则此中断向量表起始地址即为0x8000000
    l    83行:将标号__Vectors声明为全局标号,这样外部文件就可以使用这个标号。
    l    84行:标号__Vectors,表示中断向量表入口地址。
        85—160行:建立中断向量表。l
    l    161行:
        162行:复位中断服务程序,PROC…ENDP结构表示程序的开始和结束。l
    l    163行:声明复位中断向量Reset_Handler为全局属性,这样外部文件就可以调用此复位中断服务。
    l    164行:IF…ENDIF为预编译结构,判断是否使用外部SRAM,在第1行中已定义为不使用
    l    165—201行:此部分代码的作用是设置FSMC总线以支持SRAM,因不使用外部SRAM因此此部分代码不会被编译。
    l    202行:声明__main标号。
        203—204行:跳转__main地址执行。l
    l    207行:IF…ELSE…ENDIF结构,判断是否使用DEF:__MICROLIB(此处为不使用)。
    l    208—210行:若使用DEF:__MICROLIB,则将__initial_sp__heap_base__heap_limit亦即栈顶地址,堆始末地址赋予全局属性,使外部程序可以使用。
l       212行:定义全局标号__use_two_region_memory
    l    213行:声明全局标号__user_initial_stackheap,这样外程序也可调用此标号。
    l    214行:标号__user_initial_stackheap,表示用户堆栈初始化程序入口。
    l    215—218行:分别保存栈顶指针和栈大小,堆始地址和堆大小至R0R1R2R3寄存器。
    l    224行:程序完毕。
以上便是STM32的启动代码的完整解析,接下来对几个小地方做解释:
1        AREA指令:伪指令,用于定义代码段或数据段,后跟属性标号。其中比较重要的一个标号为“READONLY”或者“READWRITE”,其中“READONLY”表示该段为只读属性,联系到STM32的内部存储介质,可知具有只读属性的段保存于FLASH区,即0x8000000地址后。而“READONLY”表示该段为可读写属性,可知可读写段保存于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的世界。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值