Detailed explanation of STM32 startup process

1. Detailed analysis of STM32 startup files

Detailed analysis of STM32 startup files (V3.5.0) Take: startup_stm32f10x_hd.s as an example

;******************** (C) COPYRIGHT 2011 STMicroelectronics ********************
;* File Name          : startup_stm32f10x_hd.s
;* Author             : MCD Application Team
;* Version            : V3.5.0
;* Date               : 11-March-2011
;* Description        : STM32F10x High Density Devices vector table for MDK-ARM 
;*                      toolchain. 
;*                      This module performs:
;*                      - Set the initial SP
;*                      - Set the initial PC == Reset_Handler
;*                      - Set the vector table entries with the exceptions ISR address
;*                      - Configure the clock system and also configure the external 
;*                        SRAM mounted on STM3210E-EVAL board to be used as data 
;*                        memory (optional, to be enabled by user)
;*                      - Branches to __main in the C library (which eventually
;*                        calls main()).
;*                      After Reset the CortexM3 processor is in Thread mode,
;*                      priority is Privileged, and the Stack is set to Main.
;* <<< Use Configuration Wizard in Context Menu >>>   
;*******************************************************************************
; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
;*******************************************************************************
 
; 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				;EQU伪指令,作用是左边的符号名代表右边的表达式</span>
 
                AREA    STACK, NOINIT, READWRITE, ALIGN=3	;定义栈段:名称为STACK,未初始化,可读写,ELF 的栈段按2^3=8对齐
Stack_Mem       SPACE   Stack_Size				;分配一片连续的存储区域并初始化为 0,栈空间:0x400个字节
__initial_sp							;栈空间顶地址
    
                                              
; <h> Heap Configuration					;堆定义
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
 
Heap_Size       EQU     0x00000200
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
 
__heap_base							;堆空间起始地址
Heap_Mem        SPACE   Heap_Size				;堆空间:0x200个字节
__heap_limit							;堆空间结束地址
 
							
	PRESERVE8 						;PRESERVE8 指令指定当前文件保持堆栈八字节对齐
	THUMB							;告诉汇编器下面是32位的Thumb指令,如果需要汇编器将插入位以保证对齐 
						
; Vector Table Mapped to Address 0 at Reset			;中断向量表定义
								;实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000000)
                AREA    RESET, DATA, READONLY			;定义一块数据段<DATA>,只可读<READONLY,默认READWRITE>,段名字是RESET
                EXPORT  __Vectors				;EXPORT:在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
                EXPORT  __Vectors_End				;在程序中声明一个全局的标号__Vectors_End
                EXPORT  __Vectors_Size				;在程序中声明一个全局的标号__Vectors_Size
								
									;DCD(DCDU)用于分配一片连续的字存储单元并用指定的数据初始化。
__Vectors       DCD     __initial_sp               ; Top of Stack  	;该处物理地址值存储__initial_sp所表示的地址值,即为 __Vetors 标号所表示的值
                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
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler
 
                ; External Interrupts					;以下为外部中断向量表
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                DCD     EXTI4_IRQHandler           ; EXTI Line 4
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
                DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                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       ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
                DCD     TIM8_BRK_IRQHandler        ; TIM8 Break
                DCD     TIM8_UP_IRQHandler         ; TIM8 Update
                DCD     TIM8_TRG_COM_IRQHandler    ; TIM8 Trigger and Commutation
                DCD     TIM8_CC_IRQHandler         ; TIM8 Capture Compare
                DCD     ADC3_IRQHandler            ; ADC3
                DCD     FSMC_IRQHandler            ; FSMC
                DCD     SDIO_IRQHandler            ; SDIO
                DCD     TIM5_IRQHandler            ; TIM5
                DCD     SPI3_IRQHandler            ; SPI3
                DCD     UART4_IRQHandler           ; UART4
                DCD     UART5_IRQHandler           ; UART5
                DCD     TIM6_IRQHandler            ; TIM6
                DCD     TIM7_IRQHandler            ; TIM7
                DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1
                DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
                DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End					;Vectors结束
 
__Vectors_Size  EQU  __Vectors_End - __Vectors 		;得到向量表的大小,304个字节也就是0x130个字节 
 
                AREA    |.text|, CODE, READONLY 	;定义一个代码段,可读,段名字是.text
                					;|.text|  用于表示由 C 编译程序产生的代码段,或用于以某种方式与 C 库关联的代码段
; Reset handler						;利用PROC、ENDP这一对伪指令标记程序开始、结束,把程序段分为若干个过程,使程序的结构加清晰
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK];WEAK声明其他的同名标号优先于该标号被引用,就是说如果外面声明了的话,调用外面的对应函数
                IMPORT  __main				;IMPORT:伪指令用于通知编译器要使用的标号在其他的源文件中定义
                IMPORT  SystemInit
                LDR     R0, =SystemInit			;系统初始化
                BLX     R0 				;带链接的跳转,切换指令集,跳到SystemInit
                LDR     R0, =__main			;__main为运行时库提供的函数;完成堆栈,堆的初始化等工作,会调用下面定义的__user_initial_stackheap
                BX      R0				;切换指令集,main函数不返回跳到__main,进入C的世界
                ENDP
                
; Dummy Exception Handlers (infinite loops which can be modified)
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
							;输出异常向量表标号,方便外部实现异常的具体功能,[WEAK]是弱定义的意思,如果外部定义了,优先执行外部定义,否则下面的函数定义
                EXPORT  WWDG_IRQHandler            [WEAK]
                EXPORT  PVD_IRQHandler             [WEAK]
                EXPORT  TAMPER_IRQHandler          [WEAK]
                EXPORT  RTC_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_Channel1_IRQHandler   [WEAK]
                EXPORT  DMA1_Channel2_IRQHandler   [WEAK]
                EXPORT  DMA1_Channel3_IRQHandler   [WEAK]
                EXPORT  DMA1_Channel4_IRQHandler   [WEAK]
                EXPORT  DMA1_Channel5_IRQHandler   [WEAK]
                EXPORT  DMA1_Channel6_IRQHandler   [WEAK]
                EXPORT  DMA1_Channel7_IRQHandler   [WEAK]
                EXPORT  ADC1_2_IRQHandler          [WEAK]
                EXPORT  USB_HP_CAN1_TX_IRQHandler  [WEAK]
                EXPORT  USB_LP_CAN1_RX0_IRQHandler [WEAK]
                EXPORT  CAN1_RX1_IRQHandler        [WEAK]
                EXPORT  CAN1_SCE_IRQHandler        [WEAK]
                EXPORT  EXTI9_5_IRQHandler         [WEAK]
                EXPORT  TIM1_BRK_IRQHandler        [WEAK]
                EXPORT  TIM1_UP_IRQHandler         [WEAK]
                EXPORT  TIM1_TRG_COM_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  RTCAlarm_IRQHandler        [WEAK]
                EXPORT  USBWakeUp_IRQHandler       [WEAK]
                EXPORT  TIM8_BRK_IRQHandler        [WEAK]
                EXPORT  TIM8_UP_IRQHandler         [WEAK]
                EXPORT  TIM8_TRG_COM_IRQHandler    [WEAK]
                EXPORT  TIM8_CC_IRQHandler         [WEAK]
                EXPORT  ADC3_IRQHandler            [WEAK]
                EXPORT  FSMC_IRQHandler            [WEAK]
                EXPORT  SDIO_IRQHandler            [WEAK]
                EXPORT  TIM5_IRQHandler            [WEAK]
                EXPORT  SPI3_IRQHandler            [WEAK]
                EXPORT  UART4_IRQHandler           [WEAK]
                EXPORT  UART5_IRQHandler           [WEAK]
                EXPORT  TIM6_IRQHandler            [WEAK]
                EXPORT  TIM7_IRQHandler            [WEAK]
                EXPORT  DMA2_Channel1_IRQHandler   [WEAK]
                EXPORT  DMA2_Channel2_IRQHandler   [WEAK]
                EXPORT  DMA2_Channel3_IRQHandler   [WEAK]
                EXPORT  DMA2_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					;默认是字对齐方式,也说明了代码是4字节对齐的
 
;*******************************************************************************
; User Stack and Heap initialization 用户堆栈初始化
;*******************************************************************************
                 IF      :DEF:__MICROLIB		;判断是否使用DEF:__MICROLIB(micro lib),如果勾选了micro lib
                
                 EXPORT  __initial_sp			;将栈顶地址、堆起始地址、堆结束地址赋予全局属性,使外部程序可用
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                
                 ELSE					;如果没有勾选micro lib
                
                 IMPORT  __use_two_region_memory	;两区堆栈空间,堆和栈有各自的空间地址
                 EXPORT  __user_initial_stackheap
                 
__user_initial_stackheap				;标号__user_initial_stackheap,表示用户堆栈初始化程序入口
							;此处是初始化两区的堆栈空间,堆是从由低到高的增长,栈是由高向低生长的,两个是互相独立的数据段,并不能交叉使用。
                 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					;END命令指示汇编器,已到达一个源文件的末尾
 
;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****

2. The position and redirection of the STM32 interrupt vector table
Know how to jump to the main function, then, after the interrupt occurs, how do you go to the interrupt entry address?

As can be seen from stm32f10x.s, a large number of interrupt response functions have been defined. This is the interrupt vector table, labeled __Vectors, indicating the entry address of the interrupt vector table, for example:

AREA RESET, DATA, READONLY ; Define the read-only data segment, which is actually in the CODE area (assuming that STM32 starts from FLASH, the starting address of this interrupt vector table is 0x8000000)
 

                EXPORT  __Vectors
IMPORT  OS_CPU_SysTickHandler
       IMPORT  OS_CPU_PendSVHandler
__Vectors       DCD     __initial_sp              ; Top of Stack
                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
                DCD     UsageFault_Handler        ; Usage Fault Handler

The writing of this vector table is particular, it corresponds to the hardware one-to-one and cannot be written randomly. It is up to the CPU to find the entry address. The beginning of the bin file is their address. You can see the arrangement in section 10.1.2 of the reference manual RM0008.

Let’s combine the characteristics of CORTEX-M3. After it is powered on, it determines the position of the PC according to the boot pin. For example, if the boot is set to flash startup, the PC will jump to 0x08000000 after startup. At this time, the CPU will first take 2 addresses, the first is the top address of the stack, and the second is the reset exception address, so with the above writing method, it will jump to reset_handler.

So what is the actual address of this reset_handler.? What is the address of the following piles such as Nmi_handler? How did the interrupt go to this address? Let's explain one by one below.

1. We can know these entry addresses through the reverse direction. You can see the map file under the project. This address is closely related to the target->flash start address set in keil. In fact, we don’t need to care about it. Let’s compile Device allocation, the interrupt vector table puts their addresses.

2. Compared with the ARM7/ARM9 core, the Cortex-M3 core has fixed the position of the interrupt vector table and the starting address can be changed.
3. After entering the C language, the NVIC will be configured first. The start address and offset of the interrupt vector table can be configured in NVIC_SetVectorTable(), which mainly tells the CPU whether the vector table is located in Flash or Ram, and what the offset is. For example, if it is set to be located in Flash, the offset is the program address to burn in, which can be set in Keil target. In this way, the CPU knows the entry address.

4. After an interrupt occurs, the CPU finds the address of the interrupt vector table, and then finds the interrupt address according to the offset (check mark), and then skips it.

Let's take a screenshot to illustrate, map file:
 

 For the corresponding bin file, see if it is placed at the above address:

 

Obviously, 200039c0 is the address of the top of the stack, and 08006F21 is the address of reset_handler!


How to locate? Take putting 0x20000000 as an example

1. Keil sets the start of ram to 0x20000100, we put the interrupt vector table at 0x20000000~0x20000100, and others are used by the program

2. Set NVIC_SetVectorTable(NVIC_VectTab_FLASH,0);

3. When jumping to C, copy the interrupt vector table to 0x20000000
 

Guess you like

Origin blog.csdn.net/jhyBOSS/article/details/121115587