laitimes

Microcontroller startup process analysis (from microcontroller to Linux is very necessary to see)

author:Embedded studio

An overview of the microcontroller start-up process

After the microcontroller is powered on, it goes through a total of 5 steps until it is ready for the C language runtime environment and jumps to the main function execution:

1. Kernel initialization;

2. Force the PC pointer to point to the reset interrupt vector of the interrupt vector table to execute the reset interrupt function;

3. Call the SystemInit function in the reset interrupt function, initialize the clock, configure the interrupt vector table, etc

4. Call the __main function to complete the initialization and relocation of global/static variables, initialize the stack and library functions

5. Jump to main function execution

2 Kernel initialization

After the microcontroller is powered on, a series of kernel initializations will first be carried out, and we only need to understand this part of the work, and the following things are mainly done in the process of kernel initialization:

1. Kernel reset and NVIC register partial zeroing;

2. Kernel setting stack: The kernel reads out the stack address from the vector table 0 address and sets the main stack pointer (SP_main);

3. Set the PC and LR registers

a. The LR setting does not initially reset the value 0xFFFF FFFF

b. The internal hardware mechanism of the microcontroller automatically positions the PC pointer to the reset interrupt vector of the interrupt vector table, assigns the address Reset_Handler the reset interrupt function to the PC pointer, and then jumps to execute the Reset_Handler.

Three Reset Interrupt Functions Reset_Handler

In the final step of the kernel reset, the PC pointer is pointed to the reset interrupt vector, and the content in the reset interrupt service function is what we really need to care about. Looking at the *.s microcontroller assembly boot file in an IAR environment has the following paragraph:

Reset_Handler PROC

EXPORT Reset_Handler [WEAK]

IMPORT __main

IMPORT SystemInit

LDR R0, =SystemInit ; Load the systemInit address into register R0

BLX R0 ; Jump to address execution in R0 (execute systemInit function)

LDR R0, =__main ; Load the systemInit address into register R0

BX R0 ; Jump to address execution in R0 (execute __main function)

ENDP

1

2

3

4

5

6

7

8

9

The above code is the interrupt service function Reset_Handler, you can see that in the service interrupt function, two functions are declared with IMPORT first, __main, SystemInit, and then the SystemInit and __main functions are executed sequentially. Let's take a look at what these two functions do:

SystemInit function:

In the system_stm32f4xx.c file we can see the definition of the function, which mainly does the following two things:

1. Initialization clocks: SYSCLK, HCLK, PCLK2 and PCLK1 prescalers

2. Configure the interrupt vector table: whether the positioning of the interrupt vector table is flash or SRAM, whether it needs to be offset)

Note: The system clock frequency (by setting the correlation coefficient of the phase-locked loop), the address of the interrupt vector table (located in SRAM or Flsah, whether it is offset, how many offset addresses, etc.) can be modified by the macro definition in the system_stm32f4xx file.

__main() function (__iar_program_start in IAR):

The function is encapsulated in the compiler's library, so the name of the function is different from IDE to IDE, but the function is roughly similar:

1. Complete the initialization and relocation of global variables/static variables/constants:

a. Jump into the __scatterload_rt2 function: Configure the loading domain and running domain of the content to be copied (static variables, global variables, constants) by setting four registers, set the size of the content to be copied, and serve the functions of subsequent __scatterload_cpy().

b. Jump into the __scatterload_cpy function to complete the relocation of static variables, global variables, and constants from flash to SRAM.

c. Jump into the __scatterload_zeroinit function to complete the initialization of the uninitialized global variable.

2. Initialize the stack (in this case, the program stack) and library functions:

Jump to the __user_steup_stackheap function: Call the __user_libspac__user_libspace to keep static data for the C library. This is a 96-byte, 0-initialized block of data that was created by the C library. It can be used as a temporary stack during C library initialization. Then call __user_initial_stackheap the user's initialization stack function, implement the configuration of the user's stack, call _fp_init and __rt_fp_status_addr (C library function) two function calls to implement floating-point operation support.

3. Jump the program and enter the main() function:

Jumps into the user's main function

note:

Uninitialized and initial values of zero global variables, static variables are generally in RAM, and global variables/static variables with an initial value of not zero are generally in FLASH.

Because Flash cannot be written randomly (only 0, not 1), global variables with non-zero values that are not initially reset to RAM are generally relocated before the program runs.

The addresses of both global variables and constants are allocated at compile time (so they can be seen in the .map file), while local variables are created in the stack when the program is running, and the stack space size can be set in the IDE.

When the microcontroller starts, there is no need to move the code from ROM to RAM, which ARM does. The process of microcontroller program execution is divided into three steps: take the execution - > the analysis instruction - > execute the instruction. The task of taking instructions is to read out instructions from program memory according to the value of the PC and send them to the instruction registers. The analysis is then executed. In this way, the microcontroller removes code instructions from the internal program memory and accesses the relevant data from RAM. It should be known that the speed of RAM fetching is much higher than that of ROM, but the microcontroller itself is not running at a high frequency, so the slow withdrawal of instructions from ROM does not affect. Unlike ARM, the CPU runs at a high frequency, much faster than the speed of reading and writing from the ROM, so when there is a large operating system, it is necessary to copy the code part into the RAM and then execute.

————————————————

Copyright Notice: This article is the original article of CSDN blogger "GWen9", in accordance with the CC 4.0 BY-SA copyright license, reproduced please attach the original source link and this statement.

Original link: https://blog.csdn.net/aa386447225/article/details/109546384