STM32启动文件详解

一、简介

      在STM32微处理器(包括其他类型微处理器或CPU)上电后,运行的第一行代码并不是C代码,而是一段汇编代码,因为此时的环境还无法运行C代码,比如堆栈此时还未设置,RW段、ZI段等还未拷贝、就绪等。针对STM32这类微控制器而言,启动文件就是用来完成这一工作的。对于一些高端的微控制器,也会有专门的Bootloader(如U-Boot)来完成此类工作。

      启动文件其实还有一个隐含的功能。我们都知道, STM32系列微处理器都是内置FLASH和RAM的,程序被编译、链接成bin或者hex文件,然后被烧写到FLASH中。在嵌入式系统中,代码通常有链接地址(也叫运行地址,在链接脚本中指定)和加载地址(也叫存储地址,代码被实际存放的存储器地址)之分,正常情况下,链接地址和存储地址应该是一样的,这样程序才能正常工作(除非使用位置无关码技术)。对于STM32而言,代码(TEXT段)的链接地址和加载地址都位于FLASH中,但是RW和ZI等数据段的链接地址在RAM中(为了加速访问,理论上位于FLASH中也是可以的)。那么这些位于FLASH中的RW、ZI是怎么被放入RAM中的呢?是谁负责完成对ZI段清零的?这其实也是启动文件中做的,下文会做详细介绍。

二、启动文件

     下面是stm32f429系列微控制器使用的启动文件:

;******************** (C) COPYRIGHT 2015 STMicroelectronics ********************
;* File Name          : startup_stm32f429_439xx.s
;* Author             : MCD Application Team
;* @version           : V1.5.0
;* @date              : 06-March-2015
;* Description        : STM32F429xx/439xx devices vector table for MDK-ARM toolchain. 
;*                      This module performs:
;*                      - Set the initial SP
;*                      - 初始化栈指针SP(ARM R13)
;*                      - Set the initial PC == Reset_Handler
;*                      - 初始化程序计数器PC == 复位异常(ARM USER模式下的R15)
;*                      - Set the vector table entries with the exceptions ISR address
;*                      - 把异常中断服务程序入口地址设置到中断向量表中
;*                      - Configure the system clock and the external SRAM/SDRAM mounted
;*                        on STM324x9I-EVAL boards to be used as data memory
;*                        (optional, to be enabled by user)
;*                      - 配置系统时钟和用作数据存储的外部挂载的SRAM/SDRAM(可选,由用户使能)
;*                      - Branches to __main in the C library (which eventually
;*                        calls main()).
;*                      - 设置分支到C库中的__main(用来最后调用main()函数)
;*                      After Reset the CortexM4 processor is in Thread mode,
;*                      priority is Privileged, and the Stack is set to Main.
;* <<< Use Configuration Wizard in Context Menu >>>   
;*******************************************************************************
; 
; Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
; You may not use this file except in compliance with the License.
; You may obtain a copy of the License at:
; 
;        http://www.st.com/software_license_agreement_liberty_v2
; 
; Unless required by applicable law or agreed to in writing, software 
; distributed under the License is distributed on an "AS IS" BASIS, 
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
; 
;*******************************************************************************

; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size      EQU     0x00000400
;栈大小Stack_Size为0x00000400,即1KB。 

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
;AREA伪指令新建代码段或数据段,STACK表示可变的段名,未初始化,可读可写,2^3=8字节(双字)边界对齐。
Stack_Mem       SPACE   Stack_Size
;Stack_Mem为标号,SPACE伪指令分配了一片连续的大小为Stack_Size字节的存储区域并初始化为0。
__initial_sp
;__initial_sp是个标号,代表当前指令的地址,即栈顶地址。


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200
;堆大小Heap_Size为0x00000200,即512B。 
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
;新建堆段,未初始化,可读可写,8字节对齐。
__heap_base
;标号,堆的起始地址。
Heap_Mem        SPACE   Heap_Size
;分配并初始化一片连续的存储空间。
__heap_limit
;标号,堆的结束地址。堆是由低向高生长的,跟栈相反。


                PRESERVE8
;等于PRESERVE8 {TRUE},设置文件的PRSE8编译属性,使代码保持堆栈8字节对齐。
                THUMB
;THUMB必须位于使用新语法的任何Thumb代码之前,后面指令兼容THUMB指令。

; Vector Table Mapped to Address 0 at Reset
;向量表在复位时映射到地址0
                AREA    RESET, DATA, READONLY
;定义一个数据段RESET,只读。
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size
;声明三个全局标号,该标号可在其他的文件中被引用。
__Vectors       DCD     __initial_sp               ; Top of Stack    栈顶
;中断向量表起始地址,DCD伪指令用于分配一篇连续的字存储单元并用伪指令中制定的表达式初始化。
;用DCD分配的字存储单元是字(4字节)对齐的。
                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    总线错误中断
                                                   ;一般发生在数据访问异常,比如fsmc访问不当
                DCD     UsageFault_Handler         ; Usage Fault Handler    用法错误中断
                                                   ;一般是预取值、位置指令或者数据处理错误
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler    系统调用异常
                                                   ;SVC是用户模式代码中的主进程
                                                   ;用于创造对特权操作系统代码的调用
                DCD     DebugMon_Handler           ; Debug Monitor Handler    ???    
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler    挂起异常
                                                   ;用作上下文切换异常。
                DCD     SysTick_Handler            ; SysTick Handler    系统滴答定时器
                                                   ;操作系统内核时钟

                ; External Interrupts    以上都是Coretex M3内核自带的,以下为外部中断向量表
                DCD     WWDG_IRQHandler                   ; Window WatchDog
                DCD     PVD_IRQHandler                    ; PVD through EXTI Line detection    
                                                          ;PVD = Programmable Voltage Detector 
                                                          ;可编程电压监测器(Vdd和Vdda都要参与比较)                           
                DCD     TAMP_STAMP_IRQHandler             ; Tamper and TimeStamps through the EXTI line    ???            
                DCD     RTC_WKUP_IRQHandler               ; RTC Wakeup through the EXTI line
                DCD     FLASH_IRQHandler                  ; FLASH                                           
                DCD     RCC_IRQHandler                    ; RCC                                             
                DCD     EXTI0_IRQHandler                  ; EXTI Line0                                             
                DCD     EXTI1_IRQHandler                  ; EXTI Line1                                             
                DCD     EXTI2_IRQHandler                  ; EXTI Line2                                             
                DCD     EXTI3_IRQHandler                  ; EXTI Line3                                             
                DCD     EXTI4_IRQHandler                  ; EXTI Line4                                             
                DCD     DMA1_Stream0_IRQHandler           ; DMA1 Stream 0                                   
                DCD     DMA1_Stream1_IRQHandler           ; DMA1 Stream 1                                   
                DCD     DMA1_Stream2_IRQHandler           ; DMA1 Stream 2                                   
                DCD     DMA1_Stream3_IRQHandler           ; DMA1 Stream 3                                   
                DCD     DMA1_Stream4_IRQHandler           ; DMA1 Stream 4                                   
                DCD     DMA1_Stream5_IRQHandler           ; DMA1 Stream 5                                   
                DCD     DMA1_Stream6_IRQHandler           ; DMA1 Stream 6                                   
                DCD     ADC_IRQHandler                    ; ADC1, ADC2 and ADC3s                            
                DCD     CAN1_TX_IRQHandler                ; CAN1 TX                                                
                DCD     CAN1_RX0_IRQHandler               ; CAN1 RX0                                               
                DCD     CAN1_RX1_IRQHandler               ; CAN1 RX1                                               
                DCD     CAN1_SCE_IRQHandler               ; CAN1 SCE                                               
                DCD     EXTI9_5_IRQHandler                ; External Line[9:5]s                                    
                DCD     TIM1_BRK_TIM9_IRQHandler          ; TIM1 Break and TIM9                   
                DCD     TIM1_UP_TIM10_IRQHandler          ; TIM1 Update and TIM10                 
                DCD     TIM1_TRG_COM_TIM11_IRQHandler     ; TIM1 Trigger and Commutation and TIM11
                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              ; External Line[15:10]s                                  
                DCD     RTC_Alarm_IRQHandler              ; RTC Alarm (A and B) through EXTI Line                  
                DCD     OTG_FS_WKUP_IRQHandler            ; USB OTG FS Wakeup through EXTI line    
                                                          ;OTG = On-The-Go
                                                          ;主要应用于各种不同的设备或移动设备间的联接和数据交换
                DCD     TIM8_BRK_TIM12_IRQHandler         ; TIM8 Break and TIM12                  
                DCD     TIM8_UP_TIM13_IRQHandler          ; TIM8 Update and TIM13                 
                DCD     TIM8_TRG_COM_TIM14_IRQHandler     ; TIM8 Trigger and Commutation and TIM14
                DCD     TIM8_CC_IRQHandler                ; TIM8 Capture Compare                                   
                DCD     DMA1_Stream7_IRQHandler           ; DMA1 Stream7                                           
                DCD     FMC_IRQHandler                    ; FMC    ???                                             
                DCD     SDIO_IRQHandler                   ; SDIO    
                                                          ;SDIO = Secure Digital Input and Output
                DCD     TIM5_IRQHandler                   ; TIM5                                            
                DCD     SPI3_IRQHandler                   ; SPI3                                            
                DCD     UART4_IRQHandler                  ; UART4                                           
                DCD     UART5_IRQHandler                  ; UART5                                           
                DCD     TIM6_DAC_IRQHandler               ; TIM6 and DAC1&2 underrun errors                   
                DCD     TIM7_IRQHandler                   ; TIM7                   
                DCD     DMA2_Stream0_IRQHandler           ; DMA2 Stream 0                                   
                DCD     DMA2_Stream1_IRQHandler           ; DMA2 Stream 1                                   
                DCD     DMA2_Stream2_IRQHandler           ; DMA2 Stream 2                                   
                DCD     DMA2_Stream3_IRQHandler           ; DMA2 Stream 3                                   
                DCD     DMA2_Stream4_IRQHandler           ; DMA2 Stream 4                                   
                DCD     ETH_IRQHandler                    ; Ethernet                                        
                DCD     ETH_WKUP_IRQHandler               ; Ethernet Wakeup through EXTI line                      
                DCD     CAN2_TX_IRQHandler                ; CAN2 TX                                                
                DCD     CAN2_RX0_IRQHandler               ; CAN2 RX0                                               
                DCD     CAN2_RX1_IRQHandler               ; CAN2 RX1                                               
                DCD     CAN2_SCE_IRQHandler               ; CAN2 SCE                                               
                DCD     OTG_FS_IRQHandler                 ; USB OTG FS                                      
                DCD     DMA2_Stream5_IRQHandler           ; DMA2 Stream 5                                   
                DCD     DMA2_Stream6_IRQHandler           ; DMA2 Stream 6                                   
                DCD     DMA2_Stream7_IRQHandler           ; DMA2 Stream 7                                   
                DCD     USART6_IRQHandler                 ; USART6                                           
                DCD     I2C3_EV_IRQHandler                ; I2C3 event                                             
                DCD     I2C3_ER_IRQHandler                ; I2C3 error                                             
                DCD     OTG_HS_EP1_OUT_IRQHandler         ; USB OTG HS End Point 1 Out                      
                DCD     OTG_HS_EP1_IN_IRQHandler          ; USB OTG HS End Point 1 In                       
                DCD     OTG_HS_WKUP_IRQHandler            ; USB OTG HS Wakeup through EXTI                         
                DCD     OTG_HS_IRQHandler                 ; USB OTG HS                                      
                DCD     DCMI_IRQHandler                   ; DCMI    
                                                          ;DCMI = Digital Camera Interface  
                                                          ;快速摄像头接口                                      
                DCD     CRYP_IRQHandler                   ; CRYP crypto    
                                                          ;CRYP = Cryptographic Processor  
                                                          ;加密处理器                             
                DCD     HASH_RNG_IRQHandler               ; Hash and Rng    
                                                          ;Hash Processor 哈希处理器 
                                                          ;RNG = Random Number Generator 
                                                          ;随机数发生器
                DCD     FPU_IRQHandler                    ; FPU    
                                                          ;FPU = Float Point Unit 
                                                          ;浮点运算单元 
                DCD     UART7_IRQHandler                  ; UART7
                DCD     UART8_IRQHandler                  ; UART8
                DCD     SPI4_IRQHandler                   ; SPI4
                DCD     SPI5_IRQHandler                   ; SPI5
                DCD     SPI6_IRQHandler                   ; SPI6
                DCD     SAI1_IRQHandler                   ; SAI1    
                                                          ;SAI = Serial Audio Interface 
                                                          ;串行音频接口
                DCD     LTDC_IRQHandler                   ; LTDC    液晶分层显示功能
                DCD     LTDC_ER_IRQHandler                ; LTDC error
                DCD     DMA2D_IRQHandler                  ; DMA2D     2D图形加速器

__Vectors_End
;中断向量表结束地址

__Vectors_Size  EQU  __Vectors_End - __Vectors
;计算中断向量表地址空间大小

                AREA    |.text|, CODE, READONLY
 ;|.text|表示由 C 编译程序产生的代码段,或用于以某种方式与 C 库关联的代码段。

; Reset handler
Reset_Handler    PROC
;PROC、ENDP为过程定义伪指令,一个过程可以被其他程序所调用(用CALL指令)。
                 EXPORT  Reset_Handler             [WEAK]
;EXPORT伪指令声明一个全局标号,[WEAK]声明其他的同名标号优先于该标号被引用。               
        IMPORT  SystemInit
;IMPORT伪指令用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,
;而且无论当前源文件是否引用该标号,该标号均会被加入到当前源文件的符号表中。    
        IMPORT  __main

                 LDR     R0, =SystemInit
;LDR将跳转地址放入寄存器R0,准备调用SystemInit                
                 BLX     R0
;带链接和状态切换的跳转,根据最低位切换指令集,调用完子程序后返回。               
                 LDR     R0, =__main
                 BX      R0
;带状态切换的跳转,根据最低位切换指令集,不返回。              
                 ENDP

; Dummy Exception Handlers (infinite loops which can be modified)
;虚拟的中断处理程序(可被修改的无限循环)
;这些中断服务程序都是死循环,真正的中断服务函数需要我们在外部C文件里重新实现。
;如果开了某个中断但没有重新实现中断服务函数,或者写错函数名,
;则当中断到来时程序将跳转到这里进入死循环。
NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
MemManage_Handler\
                PROC
                EXPORT  MemManage_Handler          [WEAK]
                B       .
                ENDP
BusFault_Handler\
                PROC
                EXPORT  BusFault_Handler           [WEAK]
                B       .
                ENDP
UsageFault_Handler\
                PROC
                EXPORT  UsageFault_Handler         [WEAK]
                B       .
                ENDP
SVC_Handler     PROC
                EXPORT  SVC_Handler                [WEAK]
                B       .
                ENDP
DebugMon_Handler\
                PROC
                EXPORT  DebugMon_Handler           [WEAK]
                B       .
                ENDP
PendSV_Handler  PROC
                EXPORT  PendSV_Handler             [WEAK]
                B       .
                ENDP
SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
                B       .
                ENDP

Default_Handler PROC

                EXPORT  WWDG_IRQHandler                   [WEAK]                                        
                EXPORT  PVD_IRQHandler                    [WEAK]                      
                EXPORT  TAMP_STAMP_IRQHandler             [WEAK]         
                EXPORT  RTC_WKUP_IRQHandler               [WEAK]                     
                EXPORT  FLASH_IRQHandler                  [WEAK]                                         
                EXPORT  RCC_IRQHandler                    [WEAK]                                            
                EXPORT  EXTI0_IRQHandler                  [WEAK]                                            
                EXPORT  EXTI1_IRQHandler                  [WEAK]                                             
                EXPORT  EXTI2_IRQHandler                  [WEAK]                                            
                EXPORT  EXTI3_IRQHandler                  [WEAK]                                           
                EXPORT  EXTI4_IRQHandler                  [WEAK]                                            
                EXPORT  DMA1_Stream0_IRQHandler           [WEAK]                                
                EXPORT  DMA1_Stream1_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream2_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream3_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream4_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream5_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream6_IRQHandler           [WEAK]                                   
                EXPORT  ADC_IRQHandler                    [WEAK]                         
                EXPORT  CAN1_TX_IRQHandler                [WEAK]                                                
                EXPORT  CAN1_RX0_IRQHandler               [WEAK]                                               
                EXPORT  CAN1_RX1_IRQHandler               [WEAK]                                                
                EXPORT  CAN1_SCE_IRQHandler               [WEAK]                                                
                EXPORT  EXTI9_5_IRQHandler                [WEAK]                                    
                EXPORT  TIM1_BRK_TIM9_IRQHandler          [WEAK]                  
                EXPORT  TIM1_UP_TIM10_IRQHandler          [WEAK]                
                EXPORT  TIM1_TRG_COM_TIM11_IRQHandler     [WEAK] 
                EXPORT  TIM1_CC_IRQHandler                [WEAK]                                   
                EXPORT  TIM2_IRQHandler                   [WEAK]                                            
                EXPORT  TIM3_IRQHandler                   [WEAK]                                            
                EXPORT  TIM4_IRQHandler                   [WEAK]                                            
                EXPORT  I2C1_EV_IRQHandler                [WEAK]                                             
                EXPORT  I2C1_ER_IRQHandler                [WEAK]                                             
                EXPORT  I2C2_EV_IRQHandler                [WEAK]                                            
                EXPORT  I2C2_ER_IRQHandler                [WEAK]                                               
                EXPORT  SPI1_IRQHandler                   [WEAK]                                           
                EXPORT  SPI2_IRQHandler                   [WEAK]                                            
                EXPORT  USART1_IRQHandler                 [WEAK]                                          
                EXPORT  USART2_IRQHandler                 [WEAK]                                          
                EXPORT  USART3_IRQHandler                 [WEAK]                                         
                EXPORT  EXTI15_10_IRQHandler              [WEAK]                                  
                EXPORT  RTC_Alarm_IRQHandler              [WEAK]                  
                EXPORT  OTG_FS_WKUP_IRQHandler            [WEAK]                        
                EXPORT  TIM8_BRK_TIM12_IRQHandler         [WEAK]                 
                EXPORT  TIM8_UP_TIM13_IRQHandler          [WEAK]                 
                EXPORT  TIM8_TRG_COM_TIM14_IRQHandler     [WEAK] 
                EXPORT  TIM8_CC_IRQHandler                [WEAK]                                   
                EXPORT  DMA1_Stream7_IRQHandler           [WEAK]                                          
                EXPORT  FMC_IRQHandler                    [WEAK]                                             
                EXPORT  SDIO_IRQHandler                   [WEAK]                                             
                EXPORT  TIM5_IRQHandler                   [WEAK]                                             
                EXPORT  SPI3_IRQHandler                   [WEAK]                                             
                EXPORT  UART4_IRQHandler                  [WEAK]                                            
                EXPORT  UART5_IRQHandler                  [WEAK]                                            
                EXPORT  TIM6_DAC_IRQHandler               [WEAK]                   
                EXPORT  TIM7_IRQHandler                   [WEAK]                    
                EXPORT  DMA2_Stream0_IRQHandler           [WEAK]                                  
                EXPORT  DMA2_Stream1_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream2_IRQHandler           [WEAK]                                    
                EXPORT  DMA2_Stream3_IRQHandler           [WEAK]                                    
                EXPORT  DMA2_Stream4_IRQHandler           [WEAK]                                 
                EXPORT  ETH_IRQHandler                    [WEAK]                                         
                EXPORT  ETH_WKUP_IRQHandler               [WEAK]                     
                EXPORT  CAN2_TX_IRQHandler                [WEAK]                                               
                EXPORT  CAN2_RX0_IRQHandler               [WEAK]                                               
                EXPORT  CAN2_RX1_IRQHandler               [WEAK]                                               
                EXPORT  CAN2_SCE_IRQHandler               [WEAK]                                               
                EXPORT  OTG_FS_IRQHandler                 [WEAK]                                       
                EXPORT  DMA2_Stream5_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream6_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream7_IRQHandler           [WEAK]                                   
                EXPORT  USART6_IRQHandler                 [WEAK]                                           
                EXPORT  I2C3_EV_IRQHandler                [WEAK]                                              
                EXPORT  I2C3_ER_IRQHandler                [WEAK]                                              
                EXPORT  OTG_HS_EP1_OUT_IRQHandler         [WEAK]                      
                EXPORT  OTG_HS_EP1_IN_IRQHandler          [WEAK]                      
                EXPORT  OTG_HS_WKUP_IRQHandler            [WEAK]                        
                EXPORT  OTG_HS_IRQHandler                 [WEAK]                                      
                EXPORT  DCMI_IRQHandler                   [WEAK]                                             
                EXPORT  CRYP_IRQHandler                   [WEAK]                                     
                EXPORT  HASH_RNG_IRQHandler               [WEAK]
                EXPORT  FPU_IRQHandler                    [WEAK]
                EXPORT  UART7_IRQHandler                  [WEAK]
                EXPORT  UART8_IRQHandler                  [WEAK]
                EXPORT  SPI4_IRQHandler                   [WEAK]
                EXPORT  SPI5_IRQHandler                   [WEAK]
                EXPORT  SPI6_IRQHandler                   [WEAK]
                EXPORT  SAI1_IRQHandler                   [WEAK]
                EXPORT  LTDC_IRQHandler                   [WEAK]
                EXPORT  LTDC_ER_IRQHandler                [WEAK]
                EXPORT  DMA2D_IRQHandler                  [WEAK]

WWDG_IRQHandler                                                       
PVD_IRQHandler                                      
TAMP_STAMP_IRQHandler                  
RTC_WKUP_IRQHandler                                
FLASH_IRQHandler                                                       
RCC_IRQHandler                                                            
EXTI0_IRQHandler                                                          
EXTI1_IRQHandler                                                           
EXTI2_IRQHandler                                                          
EXTI3_IRQHandler                                                         
EXTI4_IRQHandler                                                          
DMA1_Stream0_IRQHandler                                       
DMA1_Stream1_IRQHandler                                          
DMA1_Stream2_IRQHandler                                          
DMA1_Stream3_IRQHandler                                          
DMA1_Stream4_IRQHandler                                          
DMA1_Stream5_IRQHandler                                          
DMA1_Stream6_IRQHandler                                          
ADC_IRQHandler                                         
CAN1_TX_IRQHandler                                                            
CAN1_RX0_IRQHandler                                                          
CAN1_RX1_IRQHandler                                                           
CAN1_SCE_IRQHandler                                                           
EXTI9_5_IRQHandler                                                
TIM1_BRK_TIM9_IRQHandler                        
TIM1_UP_TIM10_IRQHandler                      
TIM1_TRG_COM_TIM11_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                                            
RTC_Alarm_IRQHandler                            
OTG_FS_WKUP_IRQHandler                                
TIM8_BRK_TIM12_IRQHandler                      
TIM8_UP_TIM13_IRQHandler                       
TIM8_TRG_COM_TIM14_IRQHandler  
TIM8_CC_IRQHandler                                               
DMA1_Stream7_IRQHandler                                                 
FMC_IRQHandler                                                            
SDIO_IRQHandler                                                            
TIM5_IRQHandler                                                            
SPI3_IRQHandler                                                            
UART4_IRQHandler                                                          
UART5_IRQHandler                                                          
TIM6_DAC_IRQHandler                            
TIM7_IRQHandler                              
DMA2_Stream0_IRQHandler                                         
DMA2_Stream1_IRQHandler                                          
DMA2_Stream2_IRQHandler                                           
DMA2_Stream3_IRQHandler                                           
DMA2_Stream4_IRQHandler                                        
ETH_IRQHandler                                                         
ETH_WKUP_IRQHandler                                
CAN2_TX_IRQHandler                                                           
CAN2_RX0_IRQHandler                                                          
CAN2_RX1_IRQHandler                                                          
CAN2_SCE_IRQHandler                                                          
OTG_FS_IRQHandler                                                    
DMA2_Stream5_IRQHandler                                          
DMA2_Stream6_IRQHandler                                          
DMA2_Stream7_IRQHandler                                          
USART6_IRQHandler                                                        
I2C3_EV_IRQHandler                                                          
I2C3_ER_IRQHandler                                                          
OTG_HS_EP1_OUT_IRQHandler                           
OTG_HS_EP1_IN_IRQHandler                            
OTG_HS_WKUP_IRQHandler                                
OTG_HS_IRQHandler                                                   
DCMI_IRQHandler                                                            
CRYP_IRQHandler                                                    
HASH_RNG_IRQHandler
FPU_IRQHandler  
UART7_IRQHandler                  
UART8_IRQHandler                  
SPI4_IRQHandler                   
SPI5_IRQHandler                   
SPI6_IRQHandler                   
SAI1_IRQHandler                   
LTDC_IRQHandler                   
LTDC_ER_IRQHandler                 
DMA2D_IRQHandler                  
                B       .

                ENDP

                ALIGN
;ALIGN伪指令可通过添加填充字节的方式,使当前位置满足一定的对齐方式。
;后面的表达式未指定则将当前位置对齐到下一个字的位置。

;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB
;如果定义了__MICROLIB,则为以下三个标号赋予全局属性。

                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit

                 ELSE
;否则,则引入在其他源文件中定义的标号__use_two_region_memory,
;声明全局标号__user_initial_stackheap。           

                 IMPORT  __use_two_region_memory
                 EXPORT  __user_initial_stackheap

__user_initial_stackheap
;堆栈初始化,R0保存堆起始地址,R1保存栈顶地址,R2保存堆的结束地址,R3保存栈底地址。

                 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
;ENTRY伪指令标识程序的入口点,END指示代码段结束。                

;************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE*****

三、启动文件分析

   由上文可以看到,启动文件主要完成的事情如下:

1、初始化堆栈指针 SP=_initial_sp
2、初始化 PC 指针=Reset_Handler
3、初始化中断向量表
4、配置系统时钟
5、调用 C 库函数_main 初始化用户堆栈,从而最终调用 main 函数去到 C 的世界

      启动代码中,会涉及到 ARM 的汇编指令和 Cortex 内核的指令,有关 Cortex 内核的指令我们可以参考《CM3 权威指南 CnR2》第四章:指令集。下面列 出了启动文件中使用到的 ARM 汇编指令,该列表的指令全部从 ARM Development Tools 这个帮助文档里面检索而来。其中编译器相关的指令 WEAK 和 ALIGN 为了方便也放在同 一个表格了。

e77d0abbc2d6b4d468d332f1299f2285956.jpg    

Stack—栈

Stack_Size      EQU     0x00000400
;栈大小Stack_Size为0x00000400,即1KB。 

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
;AREA伪指令新建代码段或数据段,STACK表示可变的段名,未初始化,可读可写,2^3=8字节(双字)边界对齐。
Stack_Mem       SPACE   Stack_Size
;Stack_Mem为标号,SPACE伪指令分配了一片连续的大小为Stack_Size字节的存储区域并初始化为0。
__initial_sp
;__initial_sp是个标号,代表当前指令的地址,即栈顶地址。

      开辟栈的大小为 0X00000400(1KB),名字为 STACK,NOINIT 即不初始化,可读可 写,8(2^3)字节对齐。

      栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部 SRAM 的大小。如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。 如果某一天,你写的程序出现了莫名奇怪的错误,并进入了硬 fault 的时候,这时你就要考 虑下是不是栈不够大,溢出了。

      EQU:宏定义的伪指令,相当于等于,类似与 C 中的 define。

      AREA:告诉汇编器汇编一个新的代码段或者数据段。STACK 表示段名,这个可以任 意命名;NOINIT 表示不初始化;READWRITE 表示可读可写,ALIGN=3,表示按照 2^3 对齐,即 8 字节对齐。  

      SPACE:用于分配一定大小的内存空间,单位为字节。这里指定大小等于 Stack_Size。

      标号__initial_sp 紧挨着 SPACE 语句放置,表示栈的结束地址,即栈顶地址,栈是由 高向低生长的。

Heap 堆

Heap_Size       EQU     0x00000200
;堆大小Heap_Size为0x00000200,即512B。 
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
;新建堆段,未初始化,可读可写,8字节对齐。
__heap_base
;标号,堆的起始地址。
Heap_Mem        SPACE   Heap_Size
;分配并初始化一片连续的存储空间。
__heap_limit
;标号,堆的结束地址。堆是由低向高生长的,跟栈相反。

      开辟堆的大小为 0X00000200(512 字节),名字为 HEAP,NOINIT 即不初始化,可 读可写,8(2^3)字节对齐。__heap_base 表示对的起始地址,__heap_limit 表示堆的结束 地址。堆是由低向高生长的,跟栈的生长方向相反。

      堆主要用来动态内存的分配,像 malloc()函数申请的内存就在堆上面。这个在 STM32 里面用的比较少。

                PRESERVE8
;等于PRESERVE8 {TRUE},设置文件的PRSE8编译属性,使代码保持堆栈8字节对齐。
                THUMB
;THUMB必须位于使用新语法的任何Thumb代码之前,后面指令兼容THUMB指令。

      PRESERVE8:指定当前文件的堆栈按照 8 字节对齐。

      THUMB:表示后面指令兼容 THUMB 指令。THUBM 是 ARM 以前的指令集,16bit, 现在 Cortex-M 系列的都使用 THUMB-2 指令集,THUMB-2 是 32 位的,兼容 16 位和 32 位 的指令,是 THUMB 的超级。

向量表

; Vector Table Mapped to Address 0 at Reset
;向量表在复位时映射到地址0
                AREA    RESET, DATA, READONLY
;定义一个数据段RESET,只读。
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size
;声明三个全局标号,该标号可在其他的文件中被引用。

      定义一个数据段,名字为RESET,可读。并声明 __Vectors、__Vectors_End和 __Vectors_Size 这三个标号具有全局属性,可供外部的文件调用。

      EXPORT:声明一个标号可被外部的文件使用,使标号具有全局属性。如果是 IAR 编 译器,则使用的是 GLOBAL 这个指令。

      当内核响应了一个发生的异常后,对应的异常服务例程(ESR)就会执行。为了决定 ESR 的入口地址, 内核使用了―向量表查表机制‖。这里使用一张向量表。向量表其实是一个 WORD( 32 位整数)数组,每个下标对应一种异常,该下标元素的值则是该 ESR 的入口地 址。向量表在地址空间中的位置是可以设置的,通过 NVIC 中的一个重定位寄存器来指出向 量表的地址。在复位后,该寄存器的值为 0。因此,在地址 0 (即 FLASH 地址 0)处必须包 含一张向量表,用于初始时的异常分配。要注意的是这里有个另类: 0 号类型并不是什么 入口地址,而是给出了复位后 MSP 的初值。

      下图是stm32f4的部分向量表:

be95053844c312c645bd755686cbd82977c.jpg

      下面是向量表的分配:

__Vectors       DCD     __initial_sp               ; Top of Stack    栈顶
;中断向量表起始地址,DCD伪指令用于分配一篇连续的字存储单元并用伪指令中制定的表达式初始化。
;用DCD分配的字存储单元是字(4字节)对齐的。
                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    总线错误中断
                                                   ;一般发生在数据访问异常,比如fsmc访问不当
                DCD     UsageFault_Handler         ; Usage Fault Handler    用法错误中断
                                                   ;一般是预取值、位置指令或者数据处理错误
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler    系统调用异常
                                                   ;SVC是用户模式代码中的主进程
                                                   ;用于创造对特权操作系统代码的调用
                DCD     DebugMon_Handler           ; Debug Monitor Handler    ???    
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler    挂起异常
                                                   ;用作上下文切换异常。
                DCD     SysTick_Handler            ; SysTick Handler    系统滴答定时器
                                                   ;操作系统内核时钟

                ; External Interrupts    以上都是Coretex M3内核自带的,以下为外部中断向量表
                DCD     WWDG_IRQHandler                   ; Window WatchDog
                DCD     PVD_IRQHandler                    ; PVD through EXTI Line detection    
                                                          ;PVD = Programmable Voltage Detector 
                                                          ;可编程电压监测器(Vdd和Vdda都要参与比较) 
 
中间省略其他代码


__Vectors_End
;中断向量表结束地址

__Vectors_Size  EQU  __Vectors_End - __Vectors
;计算中断向量表地址空间大小

      __Vectors 为向量表起始地址,__Vectors_End 为向量表结束地址,两个相减即可算出向量 表大小。

      向量表从 FLASH 的 0 地址开始放置,以 4 个字节为一个单位,地址 0 存放的是栈 顶地址,0X04 存放的是复位程序的地址,以此类推。从代码上看,向量表中存放的都 是中断服务函数的函数名,可我们知道 C 语言中的函数名就是一个地址。

      DCD:分配一个或者多个以字为单位的内存,以四字节对齐,并要求初始化这些内 存。在向量表中,DCD 分配了一堆内存,并且以 ESR 的入口地址初始化它们。

复位程序

                AREA    |.text|, CODE, READONLY
 ;|.text|表示由 C 编译程序产生的代码段,或用于以某种方式与 C 库关联的代码段。

定义一个名称为.text 的代码段,可读。

; Reset handler
Reset_Handler    PROC
;PROC、ENDP为过程定义伪指令,一个过程可以被其他程序所调用(用CALL指令)。
                 EXPORT  Reset_Handler             [WEAK]
;EXPORT伪指令声明一个全局标号,[WEAK]声明其他的同名标号优先于该标号被引用。               
        IMPORT  SystemInit
;IMPORT伪指令用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,
;而且无论当前源文件是否引用该标号,该标号均会被加入到当前源文件的符号表中。    
        IMPORT  __main

                 LDR     R0, =SystemInit
;LDR将跳转地址放入寄存器R0,准备调用SystemInit                
                 BLX     R0
;带链接和状态切换的跳转,根据最低位切换指令集,调用完子程序后返回。               
                 LDR     R0, =__main
                 BX      R0
;带状态切换的跳转,根据最低位切换指令集,不返回。              
                 ENDP

      复位子程序是系统上电后第一个执行的程序,调用 SystemInit 函数初始化系统时钟,

      然后调用 C 库函数_mian,最终调用 main 函数去到 C 的世界。 WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部

文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并 不是唯一的。

      IMPORT:表示该标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似。这里表 示 SystemInit 和__main 这两个函数均来自外部的文件。

      SystemInit()是一个标准的库函数,在 system_stm32f4xx.c 这个库文件总定义。主要作 用是配置系统时钟,这里调用这个函数之后,F429 的系统时钟配被配置为 180M。

      __main 是一个标准的 C 库函数,主要作用是初始化用户堆栈,最终调用 main 函数去到 C 的世界。这就是为什么我们写的程序都有一个 main 函数的原因。如果我们在这里不调用__main,那么程序最终就不会调用我们 C 文件里面的 main,如果是调皮的用户就可以修改主函数的名称,然后在这里面 IMPORT 你写的主函数名称即可。

      __main是由编译器提供的,完成了我们前文所提的疑问,其主要功能如下图所示:

9066d9f3d0b24d3f06dd1fc0588ed336ed9.jpg

     LDR、BLX、BX 是 CM4 内核的指令,可在《CM3 权威指南 CnR2》第四章-指令集里面查询到,具体作用见下表:

d63146a6c8f01b0a81366eb73e2c5a517aa.jpg

中断服务程序

      在启动文件里面已经帮我们写好所有中断的中断服务函数,跟我们平时写的中断服务 函数不一样的就是这些函数都是空的,真正的中断复服务程序需要我们在外部的 C 文件里 面重新实现,这里只是提前占了一个位置而已。

      如果我们在使用某个外设的时候,开启了某个中断,但是又忘记编写配套的中断服务程序或者函数名写错,那当中断来临的时,程序就会跳转到启动文件预先写好的空的中断服务程序中,并且在这个空函数中无线循环,即程序就死在这里。

; Dummy Exception Handlers (infinite loops which can be modified)
;虚拟的中断处理程序(可被修改的无限循环)
;这些中断服务程序都是死循环,真正的中断服务函数需要我们在外部C文件里重新实现。
;如果开了某个中断但没有重新实现中断服务函数,或者写错函数名,
;则当中断到来时程序将跳转到这里进入死循环。
NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
MemManage_Handler\
                PROC
                EXPORT  MemManage_Handler          [WEAK]
                B       .
                ENDP

中间省略其他代码

LTDC_ER_IRQHandler                 
DMA2D_IRQHandler                  
                B       .

                ENDP

     B:跳转到一个标号。这里跳转到一个‘.’,即表示无线循环。

用户堆栈初始化

                ALIGN
;ALIGN伪指令可通过添加填充字节的方式,使当前位置满足一定的对齐方式。
;后面的表达式未指定则将当前位置对齐到下一个字的位置。

       ALIGN:对指令或者数据存放的地址进行对齐,后面会跟一个立即数。缺省表示 4 字 节对齐。

;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB
;如果定义了__MICROLIB,则为以下三个标号赋予全局属性。

                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit

                 ELSE
;否则,则引入在其他源文件中定义的标号__use_two_region_memory,
;声明全局标号__user_initial_stackheap。           

                 IMPORT  __use_two_region_memory
                 EXPORT  __user_initial_stackheap

__user_initial_stackheap
;堆栈初始化,R0保存堆起始地址,R1保存栈顶地址,R2保存堆的结束地址,R3保存栈底地址。

                 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
;ENTRY伪指令标识程序的入口点,END指示代码段结束。     

      判断是否定义了__MICROLIB ,如果定义了则赋予标号__initial_sp(栈顶地址)、 __heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用。 如果没有定义(实际的情况就是我们没定义__MICROLIB)则使用默认的 C 库,然后初始 化用户堆栈大小,这部分有 C 库函数__main 来完成,当初始化完堆栈之后,就调用 main 函数去到 C 的世界。

四、stm32(ARM Cortex M3)系统启动流程

     在离开复位状态后, CM3 做的第一件事就是读取下列两个 32 位整数的值:

     1、从地址 0x0000,0000 处取出 MSP 的初始值。

     2、从地址 0x0000,0004处取出 PC的初始值——这个值是复位向量, LSB必须是 1。 然后从这个值所对应的地址处取指。

6d571e8ed5025c82ae8accc511120d17004.jpg

      请注意,这与传统的 ARM 架构不同——其实也和绝大多数的其它单片机不同。传统 的 ARM 架构总是从 0 地址开始执行第一条指令。它们的 0 地址处总是一条跳转指令。 在 CM3 中,在 0 地址处提供 MSP 的初始值,然后紧跟着就是向量表。 向量表中的数值是 32 位的地址,而不是跳转指令。向量表的第一个条目指向复位后应执行的第一条指令,就是 我们刚刚分析的 Reset_Handler 这个函数。

144a9059621f47cb1f04a77d5f93e137f3d.jpg

       因为 CM3 使用的是向下生长的满栈,所以 MSP 的初始值必须是堆栈内存的末地址加 1。举例 来说,如果我们的堆栈区域在 0x20007C00-0x20007FFF 之间,那么 MSP 的初始值 就必须是 0x20008000。

       向量表跟随在 MSP 的初始值之后——也就是第 2 个表目。要注意因为 CM3 是在 Thumb 态下执行,所以向量表中的每个数值都必须把 LSB 置 1(也就是奇数)。正是因为 这个原因,图 14-3 中使用 0x101 来表达地址 0x100。当 0x100 处的指令得到执行后,就正 式开始了程序的执行(即去到 C 的世界)。在此之前初始化 MSP 是必需的,因为可能第 1 条指令还没来得及执行,就发生了 NMI 或是其它 fault。 MSP 初始化好后就已经为它们的 服务例程准备好了堆栈。

       现在,程序就进入了我们熟悉的 C 世界,现在我们也应该明白 main 并不是系统执 行的第一个程序了。

转载于:https://my.oschina.net/fileoptions/blog/3005821

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值