Origin of the problem
In the process of writing STM32 OTA program, I was confused about the implementation of the first word storage stack top address and the second word storage interrupt vector table in FLASH. I was not sure at which stage of the program these two addresses were fixed in FLASH. After querying the data, I found that they were originally in the startup file.
Before writing applications, we started thinking about the process from the custom main function. Although we always knew that there was a startup file, we didn't have an in-depth understanding because it was written in assembly language. This time, we take this opportunity to go through the process and specific functions of the startup file.
The following code is accompanied by specific comments. There are few actual assembly instructions, and the specific functions are explained below.
code analysis
;******************************************************************************* ;* File Name : startup_stm32f407xx.s ;* Author : MCD Application Team ;* Description : STM32F407xx devices vector table for MDK-ARM toolchain. Device vector table for MDK-ARM Compiler tool chain ;* This module performs: This module executes ;* - Set the initial SP Set the initial stack pointer ;* - Set the initial PC == Reset_Handler Set the program counter value as the reset interrupt processing function ;* - Set the vector table entries with the exceptions ISR address Set the vector table entry as the abnormal interrupt address? ;* - Branches to __main in the C library (which eventually ;* calls main()). Run to C In Library__main function(Final call main()). ;* After Reset the CortexM4 processor is in Thread mode, ;* priority is Privileged, and the Stack is set to Main. After reset, CortexM4 The processor is in thread mode, the priority is privilege, and the stack is set to Main. ;********************************Stack space is set in memory************************************************ Stack_Size EQU 0x400 ;Define stack space size as 0 x400 Bytes, i.e. 1 Kbyte. Equivalent to: C in#define Stack_Size 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size ;Pseudo instruction AREA,Indicates that the size of a section is Stack_Size Memory space as stack. READWRITE Indicates in memory __initial_sp ;grade__initial_sp,Represents the top address of stack space. ;***********************************Heap space is set in memory********************************************* Heap_Size EQU 0x200 ;The defined heap space size is 0 x400 Bytes, also 1 Kbyte. AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;Pseudo instruction AREA,READWRITE Indicates in memory __heap_base ;grade__heap_base,Indicates the starting address of heap space. Heap_Mem SPACE Heap_Size ;Open up a section of size Heap_Size Memory space as heap. __heap_limit ;grade__heap_limit,Indicates the end address of heap space. PRESERVE8 ;Tells the compiler to align with 8 bytes. THUMB ;Tell the compiler to use THUMB Instruction set. ;***********************************The break vector table is set in FLASH in********************************************* ; Vector Table Mapped to Address 0 at Reset ; ;Defining read-only data segments is actually CODE Zone (assumed) STM32 from FLASH Start, the starting address of this interrupt vector table is 0 x8000000) AREA RESET, DATA, READONLY ;READONLY Representative in CODE Area, that is FLASH area EXPORT __Vectors ;Label__Vectors Declared as a global label so that external files can use this label. be similar to C Medium extern EXPORT __Vectors_End ;ditto EXPORT __Vectors_Size ;ditto ;Important: the following is to establish the interrupt vector table, that is, first place these addresses in the FLASH The starting position, here is why FLASH The first word stores the top address of the stack, and the second word stores the origin of the reset interrupt function! __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 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 detection 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 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 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 DCD 0 ; Reserved DCD HASH_RNG_IRQHandler ; Hash and Rng DCD FPU_IRQHandler ; FPU __Vectors_End __Vectors_Size EQU __Vectors_End - __Vectors AREA |.text|, CODE, READONLY ;Definition stored in FLASH in ; Reset handler Reset interrupt function Reset_Handler PROC ;PROC...ENDP Structure represents the beginning and end of a program. EXPORT Reset_Handler [WEAK] ;Declare reset interrupt vector Reset_Handler Is a global attribute, so that external files can call this reset interrupt service. IMPORT SystemInit ;Import SystemInit function IMPORT __main ; Import__main function __main Is a function provided by the compiler, which jumps to C Medium main function LDR R0, =SystemInit BLX R0 ;implement SystemInit function LDR R0, =__main BX R0 ;implement main function ENDP ; Dummy Exception Handlers (infinite loops which can be modified) ; Interrupt handling function in the definition,[WEAK]Represents a weak function, which can be overridden elsewhere, similar to JAVA Rewriting in 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 HASH_RNG_IRQHandler [WEAK] EXPORT FPU_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 HASH_RNG_IRQHandler FPU_IRQHandler B . ENDP ALIGN ;******************************************************************************* ; User Stack and Heap initialization ; User stack initialization ;******************************************************************************* ; : IF...ELSE...ENDIF Structure, judge whether to use DEF:__MICROLIB(Not used here). IF :DEF:__MICROLIB EXPORT __initial_sp EXPORT __heap_base EXPORT __heap_limit ;If used DEF:__MICROLIB,Will__initial_sp,__heap_base,__heap_limit That is, the top address of the stack and the beginning and end address of the heap are given global attributes so that external programs can use them. ELSE IMPORT __use_two_region_memory ;Define global label__use_two_region_memory. EXPORT __user_initial_stackheap ;Declare global label__user_initial_stackheap,In this way, the external program can also call this label. Labels are similar to function names or function pointers __user_initial_stackheap ;grade__user_initial_stackheap,Represents the user stack initializer entry. The function is in__main Call in function LDR R0, = Heap_Mem LDR R1, =(Stack_Mem + Stack_Size) LDR R2, = (Heap_Mem + Heap_Size) LDR R3, = Stack_Mem ;Save the stack top pointer and stack size, heap start address and heap size to R0,R1,R2,R3 Register. BX LR ALIGN ENDIF END ;************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE*****
Analysis of assembly instructions used in startup file:
AREA instruction: pseudo instruction, used to define code segment or data segment, followed by attribute label.
1. The label "READONLY" indicates that the segment is read-only. When connected to the internal storage medium of STM32, it can be seen that the segment with read-only attribute is saved in the FLASH area, that is, after the address of 0x8000000.
2. The label "READONLY" indicates that the segment is "read-write" attribute. It can be seen that the "read-write" segment is saved in the SRAM area, that is, after the address 0x2000000., Stack segments are located in SRAM space.
The storage location of interrupt vector table is determined by using area reset, data and readonly. All entry addresses under the code are placed in the FLASH area, which is also the code that operates FLASH first in the whole code. Therefore, the top address is stored from the starting 0x8000000 address__ initial_sp, the address 0x80000004 stores the reset interrupt vector Reset_Handler, and so on.
This explains the problem that has been puzzled and is also the key to the implementation of IAP.
DCD instruction: its function is to open up a space, and its meaning is equivalent to the address symbol "&" in C language.
Each instruction uses a pointer to an interrupt table, which is similar to that of B C C. Each instruction uses a pointer to an interrupt table.
Label: the word "label" is used in many places above. Label is mainly used to represent a certain position in a memory space, which is equivalent to the concept of "address" in C language. Address only represents a location of storage space. From the perspective of C language, there is no difference in essence between the address of variable, the address of array or the entry address of function__ The main label does not indicate the entry address of the main function in the C program__ The main label represents an initialization subroutine in the C/C + + standard real-time library function__ The entry address of main. One of the main functions of the program is to initialize the stack (for this program, jump to the _user_initial_stackheap label to initialize the stack), initialize the image file, and finally jump to the main function in the C program.
This explains why all C programs must have a main function as the starting point of the program - because this is specified by the C/C + + standard real-time Library - and cannot be changed, because the C/C + + standard real-time library does not develop source code. Therefore, in fact, on the premise that the user is visible,
Program in__ Jump to in the main function The main function in the C file starts to execute the C program.
summary
In short, the following operations are performed in the startup file:
- The stack address and size are defined and allocated in SRAM,
- Place the stack top address and interrupt vector table at the starting position of FLASH. The first word at 0x8000000 is the stack top address, and the second word at 0x8000004 is the starting address of the interrupt vector table. The first item in the interrupt vector table is the entry address of the reset interrupt function. After the system is reset, enter the reset interrupt function to execute, and then execute__ main function
- Execute SystemInit function
- Jump to c library__ The main function is executed in__ Calling main in function user_ initial_ Stack heap initializes the stack (saves the stack address to the register), and finally jumps to the main function written by the user
This is the start-up process of STM32.