Search topics...
Boot & StartupBoot Sequencefoundational

Describe what happens from power-on until main() is called on a Cortex-M microcontroller.

0 upvotes
Practice with AISoon
Study the fundamentals first — Boot & Startup topic page

When a Cortex-M processor comes out of reset, the hardware performs exactly two memory reads before executing any instruction. First, it reads the 32-bit value at address 0x00000000 (the first entry of the vector table) and loads it into the Main Stack Pointer (MSP) — this is the initial stack pointer value. Second, it reads the 32-bit value at address 0x00000004 (the second entry) and loads it into the Program Counter (PC) — this is the address of the Reset_Handler. The CPU then begins executing instructions at the Reset_Handler address. No bootloader, no BIOS, no firmware is involved in these two reads — they are hardwired into the Cortex-M core logic itself.

The Reset_Handler is the first code that runs, and it is typically written in assembly (found in the startup file, e.g., startup_stm32f4xx.s). Its job is to prepare the C runtime environment. It copies the .data section from its load address in Flash (where the initialized global variable values are stored by the linker) to its runtime address in RAM, using symbols like _sidata, _sdata, and _edata provided by the linker script. It then zeroes the .bss section in RAM (from _sbss to _ebss), since uninitialized global variables must start as zero per the C standard. Without these two steps, global variables would contain garbage values and any C code relying on them would produce undefined behavior.

After .data and .bss are initialized, the startup code calls SystemInit() (which configures clocks, Flash wait states, and optionally the FPU), then branches to main(). Some toolchains also call C library initialization (__libc_init_array) for static constructors before main(). The entire sequence — hardware vector fetch, Reset_Handler, memory initialization, SystemInit, main — is deterministic and happens in microseconds. Understanding this chain is essential for debugging hard faults that occur before main(), which are almost always caused by incorrect linker scripts, corrupt vector tables, or misconfigured clock settings in SystemInit().

Source: Boot & Startup Q&A