[应用相关] 解析 STM32 的启动过程

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

 楼主| 欢乐家园 发表于 2021-7-21 23:27 | 显示全部楼层
无论性能高下,结构简繁,价格贵贱,每一种微控制器(处理器)都必须有启动文件,启动文件的作用便是负责执行微控制器从“复位”到“开始执行main函数”中间这段时间(称为启动过程)所必须进行的工作。最为常见的51,AVR或MSP430等微控制器当然也有对应启动文件,但开发环境往往自动完整地提供了这个启动文件,不需要开发人员再行干预启动过程,只需要从main函数开始进行应用程序的设计即可。
 楼主| 欢乐家园 发表于 2021-7-21 23:28 | 显示全部楼层
话题转到STM32微控制器,无论是keil
uvision4还是IAR EWARM开发环境,ST公司都提供了现成的直接可用的启动文件,程序开发人员可以直接引用启动文件后直接进行C应用程序的开发。这样能大大减小开发人员从其它微控制器平台跳转至STM32平台,也降低了适应STM32微控制器的难度(对于上一代ARM的当家花旦ARM9,启动文件往往是第一道难啃却又无法逾越的坎)。
 楼主| 欢乐家园 发表于 2021-7-21 23:29 | 显示全部楼层
相对于ARM上一代的主流ARM7/ARM9内核架构,新一代Cortex内核架构的启动方式有了比较大的变化。ARM7/ARM9内核的控制器在复位后,CPU会从存储空间的绝对地址0x000000取出第一条指令执行复位中断服务程序的方式启动,即固定了复位后的起始地址为0x000000(PC = 0x000000)同时中断向量表的位置并不是固定的。
 楼主| 欢乐家园 发表于 2021-7-21 23:30 | 显示全部楼层
而Cortex-M3内核则正好相反,有3种情况:
 楼主| 欢乐家园 发表于 2021-7-21 23:31 | 显示全部楼层
1、 通过boot引脚设置可以将中断向量表定位于SRAM区,即起始地址为0x2000000,同时复位后PC指针位于0x2000000处;
 楼主| 欢乐家园 发表于 2021-7-21 23:32 | 显示全部楼层
2、 通过boot引脚设置可以将中断向量表定位于FLASH区,即起始地址为0x8000000,同时复位后PC指针位于0x8000000处;
 楼主| 欢乐家园 发表于 2021-7-21 23:33 | 显示全部楼层
3、 通过boot引脚设置可以将中断向量表定位于内置Bootloader区,本文不对这种情况做论述;
 楼主| 欢乐家园 发表于 2021-7-21 23:34 | 显示全部楼层
而Cortex-M3内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。
 楼主| 欢乐家园 发表于 2021-7-21 23:35 | 显示全部楼层
有了上述准备只是后,下面以STM32的2.02固件库提供的启动文件“stm32f10x_vector.s”为模板,对STM32的启动过程做一个简要而全面的解析。
 楼主| 欢乐家园 发表于 2021-7-21 23:36 | 显示全部楼层
程序清单一:
;文件“stm32f10x_vector.s”,其中注释为行号
  1. DATA_IN_ExtSRAM EQU 0 ;1
  2. Stack_Size EQU 0x00000400 ;2
  3. AREA STACK, NOINIT, READWRITE, ALIGN = 3 ;3
  4. Stack_Mem SPACE Stack_Size ;4
  5. __initial_sp ;5
  6. Heap_Size EQU 0x00000400 ;6
  7. AREA HEAP, NOINIT, READWRITE, ALIGN = 3 ;7
  8. __heap_base ;8
  9. Heap_Mem SPACE Heap_Size ;9
  10. __heap_limit ;10
  11. THUMB ;11
  12. PRESERVE8 ;12
  13. IMPORT NMIException ;13
  14. IMPORT HardFaultException ;14
  15. IMPORT MemManageException ;15
  16. IMPORT BusFaultException ;16
  17. IMPORT UsageFaultException ;17
  18. IMPORT SVCHandler ;18
  19. IMPORT DebugMonitor ;19
  20. IMPORT PendSVC ;20
  21. IMPORT SysTickHandler ;21
  22. IMPORT WWDG_IRQHandler ;22
  23. IMPORT PVD_IRQHandler ;23
  24. IMPORT TAMPER_IRQHandler ;24
  25. IMPORT RTC_IRQHandler ;25
  26. IMPORT FLASH_IRQHandler ;26
  27. IMPORT RCC_IRQHandler ;27
  28. IMPORT EXTI0_IRQHandler ;28
  29. IMPORT EXTI1_IRQHandler ;29
  30. IMPORT EXTI2_IRQHandler ;30
  31. IMPORT EXTI3_IRQHandler ;31
  32. IMPORT EXTI4_IRQHandler ;32
  33. IMPORT DMA1_Channel1_IRQHandler ;33
  34. IMPORT DMA1_Channel2_IRQHandler ;34
  35. IMPORT DMA1_Channel3_IRQHandler ;35
  36. IMPORT DMA1_Channel4_IRQHandler ;36
  37. IMPORT DMA1_Channel5_IRQHandler ;37
  38. IMPORT DMA1_Channel6_IRQHandler ;38
  39. IMPORT DMA1_Channel7_IRQHandler ;39
  40. IMPORT ADC1_2_IRQHandler ;40
  41. IMPORT USB_HP_CAN_TX_IRQHandler ;41
  42. IMPORT USB_LP_CAN_RX0_IRQHandler ;42
  43. IMPORT CAN_RX1_IRQHandler ;43
  44. IMPORT CAN_SCE_IRQHandler ;44
  45. IMPORT EXTI9_5_IRQHandler ;45
  46. IMPORT TIM1_BRK_IRQHandler ;46
  47. IMPORT TIM1_UP_IRQHandler ;47
  48. IMPORT TIM1_TRG_COM_IRQHandler ;48
  49. IMPORT TIM1_CC_IRQHandler ;49
  50. IMPORT TIM2_IRQHandler ;50
  51. IMPORT TIM3_IRQHandler ;51
  52. IMPORT TIM4_IRQHandler ;52
  53. IMPORT I2C1_EV_IRQHandler ;53
  54. IMPORT I2C1_ER_IRQHandler ;54
  55. IMPORT I2C2_EV_IRQHandler ;55
  56. IMPORT I2C2_ER_IRQHandler ;56
  57. IMPORT SPI1_IRQHandler ;57
  58. IMPORT SPI2_IRQHandler ;58
  59. IMPORT USART1_IRQHandler ;59
  60. IMPORT USART2_IRQHandler ;60
  61. IMPORT USART3_IRQHandler ;61
  62. IMPORT EXTI15_10_IRQHandler ;62
  63. IMPORT RTCAlarm_IRQHandler ;63
  64. IMPORT USBWakeUp_IRQHandler ;64
  65. IMPORT TIM8_BRK_IRQHandler ;65
  66. IMPORT TIM8_UP_IRQHandler ;66
  67. IMPORT TIM8_TRG_COM_IRQHandler ;67
  68. IMPORT TIM8_CC_IRQHandler ;68
  69. IMPORT ADC3_IRQHandler ;69
  70. IMPORT FSMC_IRQHandler ;70
  71. IMPORT SDIO_IRQHandler ;71
  72. IMPORT TIM5_IRQHandler ;72
  73. IMPORT SPI3_IRQHandler ;73
  74. IMPORT UART4_IRQHandler ;74
  75. IMPORT UART5_IRQHandler ;75
  76. IMPORT TIM6_IRQHandler ;76
  77. IMPORT TIM7_IRQHandler ;77
  78. IMPORT DMA2_Channel1_IRQHandler ;78
  79. IMPORT DMA2_Channel2_IRQHandler ;79
  80. IMPORT DMA2_Channel3_IRQHandler ;80
  81. IMPORT DMA2_Channel4_5_IRQHandler ;81
  82. AREA RESET, DATA, READONLY ;82
  83. EXPORT __Vectors ;83
  84. __Vectors ;84
  85. DCD __initial_sp ;85
  86. DCD Reset_Handler ;86
  87. DCD NMIException ;87
  88. DCD HardFaultException ;88
  89. DCD MemManageException ;89
  90. DCD BusFaultException ;90
  91. DCD UsageFaultException ;91
  92. DCD 0 ;92
  93. DCD 0 ;93
  94. DCD 0 ;94
  95. DCD 0 ;95
  96. DCD SVCHandler ;96
  97. DCD DebugMonitor ;97
  98. DCD 0 ;98
  99. DCD PendSVC ;99
  100. DCD SysTickHandler ;100
  101. DCD WWDG_IRQHandler ;101
  102. DCD PVD_IRQHandler ;102
  103. DCD TAMPER_IRQHandler ;103
  104. DCD RTC_IRQHandler ;104
  105. DCD FLASH_IRQHandler ;105
  106. DCD RCC_IRQHandler ;106
  107. DCD EXTI0_IRQHandler ;107
  108. DCD EXTI1_IRQHandler ;108
  109. DCD EXTI2_IRQHandler ;109
  110. DCD EXTI3_IRQHandler ;110
  111. DCD EXTI4_IRQHandler ;111
  112. DCD DMA1_Channel1_IRQHandler ;112
  113. DCD DMA1_Channel2_IRQHandler ;113
  114. DCD DMA1_Channel3_IRQHandler ;114
  115. DCD DMA1_Channel4_IRQHandler ;115
  116. DCD DMA1_Channel5_IRQHandler ;116
  117. DCD DMA1_Channel6_IRQHandler ;117
  118. DCD DMA1_Channel7_IRQHandler ;118
  119. DCD ADC1_2_IRQHandler ;119
  120. DCD USB_HP_CAN_TX_IRQHandler ;120
  121. DCD USB_LP_CAN_RX0_IRQHandler ;121
  122. DCD CAN_RX1_IRQHandler ;122
  123. DCD CAN_SCE_IRQHandler ;123
  124. DCD EXTI9_5_IRQHandler ;124
  125. DCD TIM1_BRK_IRQHandler ;125
  126. DCD TIM1_UP_IRQHandler ;126
  127. DCD TIM1_TRG_COM_IRQHandler ;127
  128. DCD TIM1_CC_IRQHandler ;128
  129. DCD TIM2_IRQHandler ;129
  130. DCD TIM3_IRQHandler ;130
  131. DCD TIM4_IRQHandler ;131
  132. DCD I2C1_EV_IRQHandler ;132
  133. DCD I2C1_ER_IRQHandler ;133
  134. DCD I2C2_EV_IRQHandler ;134
  135. DCD I2C2_ER_IRQHandler ;135
  136. DCD SPI1_IRQHandler ;136
  137. DCD SPI2_IRQHandler ;137
  138. DCD USART1_IRQHandler ;138
  139. DCD USART2_IRQHandler ;139
  140. DCD USART3_IRQHandler ;140
  141. DCD EXTI15_10_IRQHandler ;141
  142. DCD RTCAlarm_IRQHandler ;142
  143. DCD USBWakeUp_IRQHandler ;143
  144. DCD TIM8_BRK_IRQHandler ;144
  145. DCD TIM8_UP_IRQHandler ;145
  146. DCD TIM8_TRG_COM_IRQHandler ;146
  147. DCD TIM8_CC_IRQHandler ;147
  148. DCD ADC3_IRQHandler ;148
  149. DCD FSMC_IRQHandler ;149
  150. DCD SDIO_IRQHandler ;150
  151. DCD TIM5_IRQHandler ;151
  152. DCD SPI3_IRQHandler ;152
  153. DCD UART4_IRQHandler ;153
  154. DCD UART5_IRQHandler ;154
  155. DCD TIM6_IRQHandler ;155
  156. DCD TIM7_IRQHandler ;156
  157. DCD DMA2_Channel1_IRQHandler ;157
  158. DCD DMA2_Channel2_IRQHandler ;158
  159. DCD DMA2_Channel3_IRQHandler ;159
  160. DCD DMA2_Channel4_5_IRQHandler ;160
  161. AREA |.text|, CODE, READONLY ;161
  162. Reset_Handler PROC ;162
  163. EXPORT Reset_Handler ;163
  164. IF DATA_IN_ExtSRAM == 1 ;164
  165. LDR R0,= 0x00000114 ;165
  166. LDR R1,= 0x40021014 ;166
  167. STR R0,[R1] ;167
  168. LDR R0,= 0x000001E0 ;168
  169. LDR R1,= 0x40021018 ;169
  170. STR R0,[R1] ;170
  171. LDR R0,= 0x44BB44BB ;171
  172. LDR R1,= 0x40011400 ;172
  173. STR R0,[R1] ;173
  174. LDR R0,= 0xBBBBBBBB ;174
  175. LDR R1,= 0x40011404 ;175
  176. STR R0,[R1] ;176
  177. LDR R0,= 0xB44444BB ;177
  178. LDR R1,= 0x40011800 ;178
  179. STR R0,[R1] ;179
  180. LDR R0,= 0xBBBBBBBB ;180
  181. LDR R1,= 0x40011804 ;181
  182. STR R0,[R1] ;182
  183. LDR R0,= 0x44BBBBBB ;183
  184. LDR R1,= 0x40011C00 ;184
  185. STR R0,[R1] ;185
  186. LDR R0,= 0xBBBB4444 ;186
  187. LDR R1,= 0x40011C04 ;187
  188. STR R0,[R1] ;188
  189. LDR R0,= 0x44BBBBBB ;189
  190. LDR R1,= 0x40012000 ;190
  191. STR R0,[R1] ;191
  192. LDR R0,= 0x44444B44 ;192
  193. LDR R1,= 0x40012004 ;193
  194. STR R0,[R1] ;194
  195. LDR R0,= 0x00001011 ;195
  196. LDR R1,= 0xA0000010 ;196
  197. STR R0,[R1] ;197
  198. LDR R0,= 0x00000200 ;198
  199. LDR R1,= 0xA0000014 ;199
  200. STR R0,[R1] ;200
  201. ENDIF ;201
  202. IMPORT __main ;202
  203. LDR R0, =__main ;203
  204. BX R0 ;204
  205. ENDP ;205
  206. ALIGN ;206
  207. IF :DEF:__MICROLIB ;207
  208. EXPORT __initial_sp ;208
  209. EXPORT __heap_base ;209
  210. EXPORT __heap_limit ;210
  211. ELSE ;211
  212. IMPORT __use_two_region_memory ;212
  213. EXPORT __user_initial_stackheap ;213
  214. __user_initial_stackheap ;214
  215. LDR R0, = Heap_Mem ;215
  216. LDR R1, = (Stack_Mem + Stack_Size) ;216
  217. LDR R2, = (Heap_Mem + Heap_Size) ;217
  218. LDR R3, = Stack_Mem ;218
  219. BX LR ;219
  220. ALIGN ;220
  221. ENDIF ;221
  222. END ;222
  223. ENDIF ;223
  224. END ;224
 楼主| 欢乐家园 发表于 2021-7-21 23:37 | 显示全部楼层
如程序清单一,STM32的启动代码一共224行,使用了汇编语言编写,这其中的主要原因下文将会给出交代。现在从第一行开始分析:
 楼主| 欢乐家园 发表于 2021-7-21 23:39 | 显示全部楼层
第1行:定义是否使用外部SRAM,为1则使用,为0则表示不使用。此语行若用C语言表达则等价于:
#define DATA_IN_ExtSRAM 0
 楼主| 欢乐家园 发表于 2021-7-21 23:40 | 显示全部楼层
第2行:定义栈空间大小为0x00000400个字节,即1Kbyte。此语行亦等价于:
#define Stack_Size 0x00000400
 楼主| 欢乐家园 发表于 2021-7-21 23:41 | 显示全部楼层
第3行:伪指令AREA,表示
 楼主| 欢乐家园 发表于 2021-7-21 23:42 | 显示全部楼层
第4行:开辟一段大小为Stack_Size的内存空间作为栈。
 楼主| 欢乐家园 发表于 2021-7-21 23:43 | 显示全部楼层
第5行:标号__initial_sp,表示栈空间顶地址。
 楼主| 欢乐家园 发表于 2021-7-21 23:43 | 显示全部楼层
第6行:定义堆空间大小为0x00000400个字节,也为1Kbyte。
 楼主| 欢乐家园 发表于 2021-7-21 23:45 | 显示全部楼层
第7行:伪指令AREA,表示
 楼主| 欢乐家园 发表于 2021-7-21 23:46 | 显示全部楼层
第8行:标号__heap_base,表示堆空间起始地址。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

113

主题

1029

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部

113

主题

1029

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部