文章目录
- 序言
- 启动文件概述
- 开辟堆栈区
- 定义中断向量表
- 编写启动函数
- 定义默认中断函数
- 堆栈初始化
序言 上篇文章MDK链接脚本解析中我介绍了程序在汇编完成后是如何最终形成镜像文件的,以及镜像文件在FLASH中的存储状态、加载状态、运行状态。今天我们就要进入更深入,更细节,更具体的源码分析阶段,首先从启动文件开始。
注:手边最好有一本ARM汇编手册,查指令方便点,这是我用的汇编手册ARM汇编手册
百度盘密码:
gzo7
启动文件概述 我大概总结了一下,STM32F103的启动文件分成如下几个部分
- 开辟堆栈区
- 设置中断向量表
- 编写启动函数
- 定义默认中断函数
- 初始化堆栈
开辟堆栈区 【STM32F103启动文件解析】上源码,具体的解释都在代码注释里了
;
Amount of memory (in bytes) allocated for Stack
;
Tailor this value to your application needs
;
Stack Configuration
;
Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
;
EQU指令的作用就是把0x00000400这个值定义一个标签Stack_Size,类似于C语言中的宏定义#define
Stack_SizeEQU0x00000400
;
AREA指令指示汇编器汇编新的代码节或数据节。节是不可分的已命名独立代码或数据块,由链接器处理。
AREASTACK, NOINIT, READWRITE, ALIGN=3;
SPACE 指令保留一个用零填充的内存块。
Stack_MemSPACEStack_Size
__initial_sp;
Heap Configuration
;
Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
Heap_SizeEQU0x00000200AREAHEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_MemSPACEHeap_Size
__heap_limit;
PRESERVE8 指令指定当前文件保持堆栈八字节对齐
PRESERVE8;
为了最有力地支持 Thumb‐2,引了一个“统一汇编语言(UAL)”语法机制。对于 16 位
;
指令和 32 位指令均能实现的一些操作(常见于数据处理操作),有时虽然指令的实际操作数
;
不同,或者对立即数的长度有不同的限制,但是汇编器允许开发者以相同的语法格式书写,
;
并且由汇编器来决定是使用 16 位指令,还是使用 32 位指令。以前,Thumb 的语法和 ARM
;
的语法不同,在有了 UAL 之后,两者的书写格式就统一了。
;
THUMB 指令使用 UAL 语法,指示汇编器将后续指令解释为 Thumb 指令。
THUMB
定义中断向量表
;
Vector Table Mapped to Address 0 at Reset
;
AREA指令指示汇编器汇编一个叫做RESET的DATA段,段是READONLY的
AREARESET, DATA, READONLY
;
使用 EXPORT 可使其他文件中的代码能够访问当前文件中的符号。
;
使用 [WEAK] 属性可通知链接器,如果可以使用其他源中的不同 symbol 实例,则
;
不同实例将优先于此实例。[WEAK] 属性可与任何符号可见性属性一起使用。
EXPORT__Vectors
EXPORT__Vectors_End
EXPORT__Vectors_Size;
下面是中断向量表,放在在STM32中代码段的最开头,当对应的中断发生的时候就会寻找这个表里面的内容,也就是对应的函数指针
;
这里的地址在M3中应该是0x00000000,但是ST对它进行了地址重映射,所以这里是0x08000000
__VectorsDCD__initial_sp;
Top of Stack
DCDReset_Handler;
Reset Handler
DCDNMI_Handler;
NMI Handler
DCDHardFault_Handler;
Hard Fault Handler
DCDMemManage_Handler;
MPU Fault Handler
DCDBusFault_Handler;
Bus Fault Handler
DCDUsageFault_Handler;
Usage Fault Handler
DCD0;
Reserved
DCD0;
Reserved
DCD0;
Reserved
DCD0;
Reserved
DCDSVC_Handler;
SVCall Handler
DCDDebugMon_Handler;
Debug Monitor Handler
DCD0;
Reserved
DCDPendSV_Handler;
PendSV Handler
DCDSysTick_Handler;
SysTick Handler;
External Interrupts
DCDWWDG_IRQHandler;
Window Watchdog
DCDPVD_IRQHandler;
PVD through EXTI Line detect
DCDTAMPER_IRQHandler;
Tamper
DCDRTC_IRQHandler;
RTC
DCDFLASH_IRQHandler;
Flash
DCDRCC_IRQHandler;
RCC
DCDEXTI0_IRQHandler;
EXTI Line 0
DCDEXTI1_IRQHandler;
EXTI Line 1
DCDEXTI2_IRQHandler;
EXTI Line 2
DCDEXTI3_IRQHandler;
EXTI Line 3
DCDEXTI4_IRQHandler;
EXTI Line 4
DCDDMA1_Channel1_IRQHandler;
DMA1 Channel 1
DCDDMA1_Channel2_IRQHandler;
DMA1 Channel 2
DCDDMA1_Channel3_IRQHandler;
DMA1 Channel 3
DCDDMA1_Channel4_IRQHandler;
DMA1 Channel 4
DCDDMA1_Channel5_IRQHandler;
DMA1 Channel 5
DCDDMA1_Channel6_IRQHandler;
DMA1 Channel 6
DCDDMA1_Channel7_IRQHandler;
DMA1 Channel 7
DCDADC1_2_IRQHandler;
ADC1 & ADC2
DCDUSB_HP_CAN1_TX_IRQHandler;
USB High Priority or CAN1 TX
DCDUSB_LP_CAN1_RX0_IRQHandler ;
USB LowPriority or CAN1 RX0
DCDCAN1_RX1_IRQHandler;
CAN1 RX1
DCDCAN1_SCE_IRQHandler;
CAN1 SCE
DCDEXTI9_5_IRQHandler;
EXTI Line 9..5
DCDTIM1_BRK_IRQHandler;
TIM1 Break
DCDTIM1_UP_IRQHandler;
TIM1 Update
DCDTIM1_TRG_COM_IRQHandler;
TIM1 Trigger and Commutation
DCDTIM1_CC_IRQHandler;
TIM1 Capture Compare
DCDTIM2_IRQHandler;
TIM2
DCDTIM3_IRQHandler;
TIM3
DCDTIM4_IRQHandler;
TIM4
DCDI2C1_EV_IRQHandler;
I2C1 Event
DCDI2C1_ER_IRQHandler;
I2C1 Error
DCDI2C2_EV_IRQHandler;
I2C2 Event
DCDI2C2_ER_IRQHandler;
I2C2 Error
DCDSPI1_IRQHandler;
SPI1
DCDSPI2_IRQHandler;
SPI2
DCDUSART1_IRQHandler;
USART1
DCDUSART2_IRQHandler;
USART2
DCDUSART3_IRQHandler;
USART3
DCDEXTI15_10_IRQHandler;
EXTI Line 15..10
DCDRTCAlarm_IRQHandler;
RTC Alarm through EXTI Line
DCDUSBWakeUp_IRQHandler;
USB Wakeup from suspend
DCDTIM8_BRK_IRQHandler;
TIM8 Break
DCDTIM8_UP_IRQHandler;
TIM8 Update
DCDTIM8_TRG_COM_IRQHandler;
TIM8 Trigger and Commutation
DCDTIM8_CC_IRQHandler;
TIM8 Capture Compare
DCDADC3_IRQHandler;
ADC3
DCDFSMC_IRQHandler;
FSMC
DCDSDIO_IRQHandler;
SDIO
DCDTIM5_IRQHandler;
TIM5
DCDSPI3_IRQHandler;
SPI3
DCDUART4_IRQHandler;
UART4
DCDUART5_IRQHandler;
UART5
DCDTIM6_IRQHandler;
TIM6
DCDTIM7_IRQHandler;
TIM7
DCDDMA2_Channel1_IRQHandler;
DMA2 Channel1
DCDDMA2_Channel2_IRQHandler;
DMA2 Channel2
DCDDMA2_Channel3_IRQHandler;
DMA2 Channel3
DCDDMA2_Channel4_5_IRQHandler ;
DMA2 Channel4 & Channel5
__Vectors_End__Vectors_SizeEQU__Vectors_End - __Vectors
编写启动函数
;
定义代码段,READONLY
AREA|.text|, CODE, READONLY;
Reset handler
;
PROC标记函数的开始,与FUNCTION功能相同,下面的EXPORT和IMPORT的用法见手册
Reset_HandlerPROC
EXPORTReset_Handler[WEAK]
IMPORT__main
IMPORTSystemInit
LDRR0, =SystemInit
BLXR0;
进行系统初始化
LDRR0, =__main
BXR0;
跳转到__main,这个__main是C库里面的函数,它完成一些工作后,最终会跳到我们的main函数
ENDP
定义默认中断函数
;
下面定义了一堆的中断函数,函数的实体是一个死循环
NMI_HandlerPROC
EXPORTNMI_Handler[WEAK]
B.
ENDP
HardFault_Handler\
PROC
EXPORTHardFault_Handler[WEAK]
B.
ENDP
MemManage_Handler\
PROC
EXPORTMemManage_Handler[WEAK]
B.
ENDP
BusFault_Handler\
PROC
EXPORTBusFault_Handler[WEAK]
B.
ENDP
UsageFault_Handler\
PROC
EXPORTUsageFault_Handler[WEAK]
B.
ENDP
SVC_HandlerPROC
EXPORTSVC_Handler[WEAK]
B.
ENDP
DebugMon_Handler\
PROC
EXPORTDebugMon_Handler[WEAK]
B.
ENDP
PendSV_HandlerPROC
EXPORTPendSV_Handler[WEAK]
B.
ENDP
SysTick_Handler PROC
EXPORTSysTick_Handler[WEAK]
B.
ENDP;
下面这个函数我看了半天没看懂,后来才明白,我们把多个函数映射到了一个函数实体,如果这些函数没有被重写,它就是一个死循环,这些函数被用到的时候,一般都是要被我们重写的
Default_Handler PROCEXPORTWWDG_IRQHandler[WEAK]
EXPORTPVD_IRQHandler[WEAK]
EXPORTTAMPER_IRQHandler[WEAK]
EXPORTRTC_IRQHandler[WEAK]
EXPORTFLASH_IRQHandler[WEAK]
EXPORTRCC_IRQHandler[WEAK]
EXPORTEXTI0_IRQHandler[WEAK]
EXPORTEXTI1_IRQHandler[WEAK]
EXPORTEXTI2_IRQHandler[WEAK]
EXPORTEXTI3_IRQHandler[WEAK]
EXPORTEXTI4_IRQHandler[WEAK]
EXPORTDMA1_Channel1_IRQHandler[WEAK]
EXPORTDMA1_Channel2_IRQHandler[WEAK]
EXPORTDMA1_Channel3_IRQHandler[WEAK]
EXPORTDMA1_Channel4_IRQHandler[WEAK]
EXPORTDMA1_Channel5_IRQHandler[WEAK]
EXPORTDMA1_Channel6_IRQHandler[WEAK]
EXPORTDMA1_Channel7_IRQHandler[WEAK]
EXPORTADC1_2_IRQHandler[WEAK]
EXPORTUSB_HP_CAN1_TX_IRQHandler[WEAK]
EXPORTUSB_LP_CAN1_RX0_IRQHandler [WEAK]
EXPORTCAN1_RX1_IRQHandler[WEAK]
EXPORTCAN1_SCE_IRQHandler[WEAK]
EXPORTEXTI9_5_IRQHandler[WEAK]
EXPORTTIM1_BRK_IRQHandler[WEAK]
EXPORTTIM1_UP_IRQHandler[WEAK]
EXPORTTIM1_TRG_COM_IRQHandler[WEAK]
EXPORTTIM1_CC_IRQHandler[WEAK]
EXPORTTIM2_IRQHandler[WEAK]
EXPORTTIM3_IRQHandler[WEAK]
EXPORTTIM4_IRQHandler[WEAK]
EXPORTI2C1_EV_IRQHandler[WEAK]
EXPORTI2C1_ER_IRQHandler[WEAK]
EXPORTI2C2_EV_IRQHandler[WEAK]
EXPORTI2C2_ER_IRQHandler[WEAK]
EXPORTSPI1_IRQHandler[WEAK]
EXPORTSPI2_IRQHandler[WEAK]
EXPORTUSART1_IRQHandler[WEAK]
EXPORTUSART2_IRQHandler[WEAK]
EXPORTUSART3_IRQHandler[WEAK]
EXPORTEXTI15_10_IRQHandler[WEAK]
EXPORTRTCAlarm_IRQHandler[WEAK]
EXPORTUSBWakeUp_IRQHandler[WEAK]
EXPORTTIM8_BRK_IRQHandler[WEAK]
EXPORTTIM8_UP_IRQHandler[WEAK]
EXPORTTIM8_TRG_COM_IRQHandler[WEAK]
EXPORTTIM8_CC_IRQHandler[WEAK]
EXPORTADC3_IRQHandler[WEAK]
EXPORTFSMC_IRQHandler[WEAK]
EXPORTSDIO_IRQHandler[WEAK]
EXPORTTIM5_IRQHandler[WEAK]
EXPORTSPI3_IRQHandler[WEAK]
EXPORTUART4_IRQHandler[WEAK]
EXPORTUART5_IRQHandler[WEAK]
EXPORTTIM6_IRQHandler[WEAK]
EXPORTTIM7_IRQHandler[WEAK]
EXPORTDMA2_Channel1_IRQHandler[WEAK]
EXPORTDMA2_Channel2_IRQHandler[WEAK]
EXPORTDMA2_Channel3_IRQHandler[WEAK]
EXPORTDMA2_Channel4_5_IRQHandler [WEAK]WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
DMA1_Channel5_IRQHandler
DMA1_Channel6_IRQHandler
DMA1_Channel7_IRQHandler
ADC1_2_IRQHandler
USB_HP_CAN1_TX_IRQHandler
USB_LP_CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_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
TIM8_BRK_IRQHandler
TIM8_UP_IRQHandler
TIM8_TRG_COM_IRQHandler
TIM8_CC_IRQHandler
ADC3_IRQHandler
FSMC_IRQHandler
SDIO_IRQHandler
TIM5_IRQHandler
SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_IRQHandler
TIM7_IRQHandler
DMA2_Channel1_IRQHandler
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
B.ENDP;
四字节对齐
ALIGN
堆栈初始化
;
*******************************************************************************
;
User Stack and Heap initialization
;
*******************************************************************************
;
用户栈和堆的初始化
IF:DEF:__MICROLIBEXPORT__initial_sp
EXPORT__heap_base
EXPORT__heap_limitELSEIMPORT__use_two_region_memory
EXPORT__user_initial_stackheap__user_initial_stackheapLDRR0, =Heap_Mem
LDRR1, =(Stack_Mem + Stack_Size)
LDRR2, = (Heap_Mem +Heap_Size)
LDRR3, = Stack_Mem
BXLRALIGNENDIFEND
;
******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****
推荐阅读
- 课程笔记|uCos中的邮箱和消息队列
- ucos ii学习笔记1——任务中断和调度
- UCOS环境下的中断程序
- uCOS|8.uCOS3在STM32F4开发板上的移植
- STM32|在串口数据轰炸后,程序HardFault_Handler()了
- ucos|ucos ii移植到STM32 (HardFault_Handler)