Compared with the mainstream ARM7/ARM9 core architecture of the previous generation of ARM, the startup method of the new generation of Cortex core architecture has changed significantly. After the controller of the ARM7/ARM9 core is reset, the CPU will fetch the first instruction from the absolute address 0x000000 of the storage space to execute the reset interrupt service program to start, that is, the starting address after reset is fixed to 0x000000 (PC = 0x000000), and the location of the interrupt vector table is not fixed. The Cortex-M3 core is just the opposite. There are three situations:
1. The interrupt vector table can be located in the SRAM area through the boot pin setting, that is, the starting address is 0x2000000, and the PC pointer is located at 0x2000000 after reset;
2. The interrupt vector table can be located in the FLASH area through the boot pin setting, that is, the starting address is 0x8000000, and the PC pointer is located at 0x8000000 after reset;
3. The interrupt vector table can be located in the built-in Bootloader area through the boot pin setting. This article does not discuss this situation;
the Cortex-M3 core stipulates that the starting address must store the top pointer of the stack, and the second address must store the reset interrupt entry vector address. In this way, after the Cortex-M3 core is reset, the reset interrupt entry vector will be automatically taken from the next 32-bit space of the starting address and jump to execute the reset interrupt service program. Compared with the ARM7/ARM9 core, the Cortex-M3 core has a fixed position of the interrupt vector table and a variable starting address.
With the above preparations, the following is a brief and comprehensive analysis of the STM32 startup process using the startup file "stm32f10x_vector.s" provided by the STM32 2.02 firmware library as a template.
Listing 1:
File "stm32f10x_vector.s", with comments as line numbers
DATA_IN_ExtSRAM EQU 0 ;1 Stack_Size EQU 0x00000400 ;2 AREA STACK, NOINIT, READWRITE, ALIGN = 3 ;3 Stack_Mem SPACE Stack_Size ;4 __initial_sp ;5 Heap_Size EQU 0x00000400 ;6 AREA HEAP, NOINIT, READWRITE, ALIGN = 3 ;7 __heap_base ;8 Heap_Mem SPACE Heap_Size ;9 __heap_limit ;10 THUMB ;11 PRESERVE8 ;12 IMPORT NMIException ;13 IMPORT HardFaultException ;14 IMPORT MemManageException ;15 IMPORT BusFaultException ;16 IMPORT UsageFaultException ;17 IMPORT SVCHandler ;18 IMPORT DebugMonitor ;19 IMPORT PendSVC ;20 IMPORT SysTickHandler ;21 IMPORT WWDG_IRQHandler ;22 IMPORT PVD_IRQHandler ;23 IMPORT TAMPER_IRQHandler ;24 IMPORT RTC_IRQHandler ;25 IMPORT FLASH_IRQHandler ;26 IMPORT RCC_IRQHandler ;27 IMPORT EXTI0_IRQHandler ;28 IMPORT EXTI1_IRQHandler ;29 IMPORT EXTI2_IRQHandler ;30 IMPORT EXTI3_IRQHandler ;31 IMPORT EXTI4_IRQHandler ;32 IMPORT DMA1_Channel1_IRQHandler ;33 IMPORT DMA1_Channel2_IRQHandler ;34 IMPORT DMA1_Channel3_IRQHandler ;35 IMPORT DMA1_Channel4_IRQHandler ;36 IMPORT DMA1_Channel5_IRQHandler ;37 IMPORT DMA1_Channel6_IRQHandler ;38 IMPORT DMA1_Channel7_IRQHandler ;39 IMPORT ADC1_2_IRQHandler ;40 IMPORT USB_HP_CAN_TX_IRQHandler ;41 IMPORT USB_LP_CAN_RX0_IRQHandler ;42 IMPORT CAN_RX1_IRQHandler ;43 IMPORT CAN_SCE_IRQHandler ;44 IMPORT EXTI9_5_IRQHandler ;45 IMPORT TIM1_BRK_IRQHandler ;46 IMPORT TIM1_UP_IRQHandler ;47 IMPORT TIM1_TRG_COM_IRQHandler ;48 IMPORT TIM1_CC_IRQHandler ;49 IMPORT TIM2_IRQHandler ;50 IMPORT TIM3_IRQHandler ;51 IMPORT TIM4_IRQHandler ;52 IMPORT I2C1_EV_IRQHandler ;53 IMPORT I2C1_ER_IRQHandler ;54 IMPORT I2C2_EV_IRQHandler ;55 IMPORT I2C2_ER_IRQHandler ;56 IMPORT SPI1_IRQHandler ;57 IMPORT SPI2_IRQHandler ;58 IMPORT USART1_IRQHandler ;59 IMPORT USART2_IRQHandler ;60 IMPORT USART3_IRQHandler ;61 IMPORT EXTI15_10_IRQHandler ;62 IMPORT RTCAlarm_IRQHandler ;63 IMPORT USBWakeUp_IRQHandler ;64 IMPORT TIM8_BRK_IRQHandler ;65 IMPORT TIM8_UP_IRQHandler ;66 IMPORT TIM8_TRG_COM_IRQHandler ;67 IMPORT TIM8_CC_IRQHandler ;68 IMPORT ADC3_IRQHandler ;69 IMPORT FSMC_IRQHandler ;70 IMPORT SDIO_IRQHandler ;71 IMPORT TIM5_IRQHandler ;72 IMPORT SPI3_IRQHandler ;73 IMPORT UART4_IRQHandler ;74 IMPORT UART5_IRQHandler ;75 IMPORT TIM6_IRQHandler ;76 IMPORT TIM7_IRQHandler ;77 IMPORT DMA2_Channel1_IRQHandler ;78 IMPORT DMA2_Channel2_IRQHandler ;79 IMPORT DMA2_Channel3_IRQHandler ;80 IMPORT DMA2_Channel4_5_IRQHandler ;81 AREA RESET, DATA, READONLY ;82 EXPORT __Vectors ;83 __Vectors ;84 DCD __initial_sp ;85 DCD Reset_Handler ;86 DCD NMIException ;87 DCD HardFaultException ;88 DCD MemManageException ;89 DCD BusFaultException ;90 DCD UsageFaultException ;91 DCD 0 ;92 DCD 0 ;93 DCD 0 ;94 DCD 0 ;95 DCD SVCHandler ;96 DCD DebugMonitor ;97 DCD 0 ;98 DCD PendSVC ;99 DCD SysTickHandler ;100 DCD WWDG_IRQHandler ;101 DCD PVD_IRQHandler ;102 DCD TAMPER_IRQHandler ;103 DCD RTC_IRQHandler ;104 DCD FLASH_IRQHandler ;105 DCD RCC_IRQHandler ;106 DCD EXTI0_IRQHandler ;107 DCD EXTI1_IRQHandler ;108 DCD EXTI2_IRQHandler ;109 DCD EXTI3_IRQHandler ;110 DCD EXTI4_IRQHandler ;111 DCD DMA1_Channel1_IRQHandler ;112 DCD DMA1_Channel2_IRQHandler ;113 DCD DMA1_Channel3_IRQHandler ;114 DCD DMA1_Channel4_IRQHandler ;115 DCD DMA1_Channel5_IRQHandler ;116 DCD DMA1_Channel6_IRQHandler ;117 DCD DMA1_Channel7_IRQHandler ;118 DCD ADC1_2_IRQHandler ;119 DCD USB_HP_CAN_TX_IRQHandler ;120 DCD USB_LP_CAN_RX0_IRQHandler ;121 DCD CAN_RX1_IRQHandler ;122 DCD CAN_SCE_IRQHandler ;123 DCD EXTI9_5_IRQHandler ;124 DCD TIM1_BRK_IRQHandler ;125 DCD TIM1_UP_IRQHandler ;126 DCD TIM1_TRG_COM_IRQHandler ;127 DCD TIM1_CC_IRQHandler ;128 DCD TIM2_IRQHandler ;129 DCD TIM3_IRQHandler ;130 DCD TIM4_IRQHandler ;131 DCD I2C1_EV_IRQHandler ;132 DCD I2C1_ER_IRQHandler ;133 DCD I2C2_EV_IRQHandler ;134 DCD I2C2_ER_IRQHandler ;135 DCD SPI1_IRQHandler ;136 DCD SPI2_IRQHandler ;137 DCD USART1_IRQHandler ;138 DCD USART2_IRQHandler ;139 DCD USART3_IRQHandler ;140 DCD EXTI15_10_IRQHandler ;141 DCD RTCAlarm_IRQHandler ;142 DCD USBWakeUp_IRQHandler ;143 DCD TIM8_BRK_IRQHandler ;144 DCD TIM8_UP_IRQHandler ;145 DCD TIM8_TRG_COM_IRQHandler ;146 DCD TIM8_CC_IRQHandler ;147 DCD ADC3_IRQHandler ;148 DCD FSMC_IRQHandler ;149 DCD SDIO_IRQHandler ;150 DCD TIM5_IRQHandler ;151 DCD SPI3_IRQHandler ;152 DCD UART4_IRQHandler ;153 DCD UART5_IRQHandler ;154 DCD TIM6_IRQHandler ;155 DCD TIM7_IRQHandler ;156 DCD DMA2_Channel1_IRQHandler ;157 DCD DMA2_Channel2_IRQHandler ;158 DCD DMA2_Channel3_IRQHandler ;159 DCD DMA2_Channel4_5_IRQHandler ;160 AREA |.text|, CODE, READONLY ;161 Reset_Handler PROC ;162 EXPORT Reset_Handler ;163 IF DATA_IN_ExtSRAM == 1 ;164 LDR R0,= 0x00000114 ;165 LDR R1,= 0x40021014 ;166 STR R0,[R1] ;167 LDR R0,= 0x000001E0 ;168 LDR R1,= 0x40021018 ;169 STR R0,[R1] ;170 LDR R0,= 0x44BB44BB ;171 LDR R1,= 0x40011400 ;172 STR R0,[R1] ;173 LDR R0,= 0xBBBBBBBB ;174 LDR R1,= 0x40011404 ;175 STR R0,[R1] ;176 LDR R0,= 0xB44444BB ;177 LDR R1,= 0x40011800 ;178 STR R0,[R1] ;179 LDR R0,= 0xBBBBBBBB ;180 LDR R1,= 0x40011804 ;181 STR R0,[R1] ;182 LDR R0,= 0x44BBBBBB ;183 LDR R1,= 0x40011C00 ;184 STR R0,[R1] ;185 LDR R0,= 0xBBBB4444 ;186 LDR R1,= 0x40011C04 ;187 STR R0,[R1] ;188 LDR R0,= 0x44BBBBBB ;189 LDR R1,= 0x40012000 ;190 STR R0,[R1] ;191 LDR R0,= 0x44444B44 ;192 LDR R1,= 0x40012004 ;193 STR R0,[R1] ;194 LDR R0,= 0x00001011 ;195 LDR R1,= 0xA0000010 ;196 STR R0,[R1] ;197 LDR R0,= 0x00000200 ;198 LDR R1,= 0xA0000014 ;199 STR R0,[R1] ;200 ENDIF ;201 IMPORT __main ;202 LDR R0, =__main ;203 BX R0 ;204 ENDP;205 ALIGN ;206 IF :DEF:__MICROLIB ;207 EXPORT __initial_sp ;208 EXPORT __heap_base ;209 EXPORT __heap_limit ;210 ELSE ;211 IMPORT __use_two_region_memory ;212 EXPORT __user_initial_stackheap ;213 __user_initial_stackheap ;214 LDR R0, = Heap_Mem ;215 LDR R1, = (Stack_Mem + Stack_Size) ;216 LDR R2, = (Heap_Mem + Heap_Size) ;217 LDR R3, = Stack_Mem ;218 BX LR ;219 ALIGN ;220 ENDIF ;221 END ;222 ENDIF ;223 END ;224
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
As shown in Listing 1, the startup code of STM32 has a total of 224 lines, which are written in assembly language. The main reasons for this will be explained below. Now let's analyze from the first line:
Line 1: Define whether to use external SRAM, 1 means use, 0 means not use. If this line is expressed in C language, it is equivalent to:
#define DATA_IN_ExtSRAM 0
Line 2: Define the stack space size as 0x00000400 bytes, that is, 1Kbyte. This line is also equivalent to:
#define Stack_Size 0x00000400
Line 3: Pseudo-instruction AREA, indicating
Line 4: Open up a memory space of size Stack_Size as a stack.
Line 5: Label __initial_sp, indicating the top address of the stack space.
Line 6: Define the heap space size as 0x00000400 bytes, also 1Kbyte.
Line 7: Pseudo-instruction AREA, indicating
Line 8: Label __heap_base, indicating the starting address of the heap space.
Line 9: Allocate a memory space of size Heap_Size as the heap.
Line 10: Label __heap_limit, indicating the end address of the heap space.
Line 11: Tell the compiler to use the THUMB instruction set.
Line 12: Tell the compiler to align with 8 bytes.
Lines 13-81: IMPORT directive, indicating that the subsequent symbols are defined in an external file (similar to the global variable declaration in C language), and these symbols may be used in the following text.
Line 82: Define the read-only data segment, which is actually in the CODE area (assuming that STM32 is started from FLASH, the starting address of this interrupt vector table is 0x8000000) Line 83:
Declare the label __Vectors as a global label, so that external files can use this label.
Line 84: Label __Vectors, indicating the entry address of the interrupt vector table.
Lines 85-160: Create an interrupt vector table. Line
161:
Line 162: Reset the interrupt service routine, and the PROC...ENDP structure indicates the beginning and end of the program.
Line 163: Declare the reset interrupt vector Reset_Handler as a global attribute, so that external files can call this reset interrupt service.
Line 164: IF...ENDIF is a pre-compiled structure to determine whether to use external SRAM, which has been defined as "not used" in line 1.
Lines 165-201: The purpose of this part of the code is to set the FSMC bus to support SRAM. Since external SRAM is not used, this part of the code will not be compiled.
Line 202: Declare the __main label.
Lines 203-204: Jump to the __main address to execute.
Line 207: IF...ELSE...ENDIF structure to determine whether to use DEF:__MICROLIB (not used here).
Lines 208-210: If DEF:__MICROLIB is used, __initial_sp, __heap_base, __heap_limit, that is, the stack top address and the heap start and end address are assigned global attributes so that external programs can use them.
Line 212: Define the global label __use_two_region_memory.
Line 213: declare the global label __user_initial_stackheap, so that external programs can also call this label.
Line 214: label __user_initial_stackheap, indicating the user stack initialization program entry.
Lines 215-218: save the stack top pointer and stack size, stack start address and stack size to R0, R1, R2, R3 registers respectively.
Line 224: program ends.
The above is the complete analysis of the STM32 startup code. Next, explain a few small places:
1. AREA instruction: pseudo-instruction, used to define the code segment or data segment, followed by the attribute label. One of the more important labels is "READONLY" or "READWRITE", where "READONLY" means that the segment is read-only. In connection with 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 0x8000000. "READONLY" indicates that the segment has the "readable and writable" attribute. It can be seen that the "readable and writable" segment is stored in the SRAM area, that is, after the address 0x2000000. Therefore, we can know from the 3rd and 7th lines of code that the stack segment is located in the SRAM space. From the 82nd line, we can know that the interrupt vector table is placed in the FLASH area, and this is also the first data to be placed in the FLASH area in the entire startup code. Therefore, we can get an important piece of information: the address 0x8000000 stores the stack top address __initial_sp, and the address 0x8000004 stores the reset interrupt vector Reset_Handler (STM32 uses a 32-bit bus, so the storage space is 4-byte aligned).
2. DCD instruction: Its function is to open up a space, and its meaning is equivalent to the address symbol "&" in C language. Therefore, the interrupt vector table established from line 84 is similar to defining a pointer array using C language, and each member is a function pointer, pointing to each interrupt service function.
3. Label: The word "label" is used in many places in the previous text. Labels are mainly used to indicate a certain location in a piece of memory space, which is equivalent to the concept of "address" in C language. Address only indicates a location in the storage space. From the perspective of C language, there is no essential difference between the address of a variable, the address of an array or the entry address of a function.
4. The __main label in line 202 does not indicate the entry address of the main function in the C program, so line 204 does not jump to the main function to start executing the C program. The __main label indicates the entry address of an initialization subroutine __main in the C/C++ standard real-time library function. One of the main functions of this program is to initialize the stack (for Listing 1, it jumps 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 stipulated by the C/C++ standard real-time library - and it cannot be changed because the C/C++ standard real-time library does not develop source code to the outside world. Therefore, in fact, under the premise that it is visible to the user, the program jumps to the main function in the .c file after line 204 and starts executing the C program.
At this point, we can summarize the startup file and startup process of STM32. First, define the size of the stack and heap, and establish an interrupt vector table at the beginning of the code area. The first table entry is the stack top address, and the second table entry is the reset interrupt service entry address. Then jump to the __main function of the C/C++ standard real-time library in the reset interrupt service program. After completing the initialization of the user stack, jump to the main function in the .c file to start executing the C program. Assuming that STM32 is set to start from the internal FLASH (which is also the most common case), the starting position of the interrupt vector table is 0x8000000, then the stack top address is stored at 0x8000000, and the reset interrupt service entry address is stored at 0x8000004. When STM32 encounters a reset signal, it takes out the reset interrupt service entry address from 0x80000004, then executes the reset interrupt service program, then jumps to the __main function, and finally enters the mian function to come to the world of C.
Previous article:Write STM32 OS step by step [IV] OS basic framework
Next article:Run the first STM32 program using Keil MDK
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Keysight Technologies Helps Samsung Electronics Successfully Validate FiRa® 2.0 Safe Distance Measurement Test Case
- Innovation is not limited to Meizhi, Welling will appear at the 2024 China Home Appliance Technology Conference
- Innovation is not limited to Meizhi, Welling will appear at the 2024 China Home Appliance Technology Conference
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- GNSS Antenna Design Recommendations
- [Raspberry Pi 3B+ Review] Thread Suspension and Resumption & CPU Temperature Detection
- I am a beginner and I need answers to two questions.
- [Operation Tutorial] Practical operation of ATX-100 series wire harness tester!
- MSP430 low power event driven working mode
- How to achieve communication between heterogeneous processors - Mir takes you to play with the i.MX 8M Plus development board
- How to select switching power supply topology-Video sharing
- 【AT32F421 Review】+ Introduction and Development Environment Construction
- How to make an embedded device enumerate as a WinUSB device
- All the TWS wireless Bluetooth headset designs you want are here!