您的位置:首页 > 其它

stm32 M3启动文件解析

2015-06-27 10:56 543 查看
本文转载自:http://blog.sina.com.cn/s/blog_69bcf45201019djx.html

DATA_IN_ExtSRAM EQU 0 ;;1定义是否使用外部SRAM,为1则使用,为0则表示不使用

Stack_Size EQU 0x00000400 ;;2定义栈空间大小为0x00000400个字

AREA STACK, NOINIT, READWRITE, ALIGN = 3 ;;3伪指令AREA,定义一个段

Stack_Mem SPACE Stack_Size ;;4开辟一段大小为Stack_Size的内存空间作为栈。

__initial_sp ;;5标号__initial_sp,表示栈空间顶地址。

Heap_Size EQU 0x00000400 ;;6定义堆空间大小为0x00000400个字节,也为1Kbyte。

AREA HEAP, NOINIT, READWRITE, ALIGN = 3 ;;7

__heap_base ;;8标号__heap_base,表示堆空间起始地址。

Heap_Mem SPACE Heap_Size ;;9开辟一段大小为Heap_Size的内存空间作为堆。

__heap_limit ;;10标号__heap_limit,表示堆空间结束地址。

THUMB ;;11告诉编译器使用THUMB指令集。

PRESERVE8 ;;12告诉编译器以8字节对齐。

IMPORT NMIException ;;13IMPORT指令,指示后续符号是在外部文件定义的(类似C语言中的全局变量声明),而下文可能会使用到这些符号。

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定义只读数据段,实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000000)

EXPORT __Vectors ;;83将标号__Vectors声明为全局标号,这样外部文件就可以使用这个标号。

__Vectors ;;84标号__Vectors,表示中断向量表入口地址。

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复位中断服务程序,PROC…ENDP结构表示程序的开始和结束。

EXPORT Reset_Handler ;;163声明复位中断向量Reset_Handler为全局属性,这样外部文件就可以调用此复位中断服务。

IF DATA_IN_ExtSRAM == 1 ;;164IF…ENDIF为预编译结构,判断是否使用外部SRAM,在第1行中已定义为“不使用”。

LDR R0,= 0x00000114 ;;165 此部分代码的作用是设置FSMC总线以支持SRAM,因不使用外部SRAM因此此部分代码不会被编译。

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

ENDP ;;205

ALIGN ;;206

IF :DEF:__MICROLIB ;;207 IF…ELSE…ENDIF结构,判断是否使用DEF:__MICROLIB(此处为不使用)。

EXPORT __initial_sp ;;208若使用DEF:__MICROLIB,则将__initial_sp,__heap_base,__heap_limit亦即栈顶地址,堆始末地址赋予全局属性,使外部程序可以使用。

EXPORT __heap_base ;;209

EXPORT __heap_limit ;;210

ELSE ;;211

IMPORT __use_two_region_memory ;;212定义全局标号__use_two_region_memory

EXPORT __user_initial_stackheap ;;213声明全局标号__user_initial_stackheap,这样外程序也可调用此标号。

__user_initial_stackheap ;;214标号__user_initial_stackheap,表示用户堆栈初始化程序入口。

LDR R0, = Heap_Mem ;;215分别保存栈顶指针和栈大小,堆始地址和堆大小至R0,R1,R2,R3寄存器。

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的启动代码的完整解析,接下来对几个小地方做解释:

1、 AREA指令:伪指令,用于定义代码段或数据段,后跟属性标号。其中比较重要的一个标号为“READONLY”或者“READWRITE”,其中“READONLY”表示该段为只读属性,联系到STM32的内部存储介质,可知具有只读属性的段保存于FLASH区,即0x8000000地址后。而“READONLY”表示该段为“可读写”属性,可知“可读写”段保存于SRAM区,即0x2000000地址后。由此可以从第3、7行代码知道,堆栈段位于SRAM空间。从第82行可知,中断向量表放置与FLASH区,而这也是整片启动代码中最先被放进FLASH区的数据。因此可以得到一条重要的信息:0x8000000地址存放的是栈顶地址__initial_sp,0x8000004地址存放的是复位中断向量Reset_Handler(STM32使用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的世界。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: