UNIT 05 · BUILDING AND RUNNING FIRMWARE
Startup and Boot
Everything that runs before main().
By the time main() runs, a great deal has already happened. A power-on-reset circuit has waited for the supply, a boot ROM may have checked pins and checksums, the core has loaded a stack pointer and a start address from a table, and startup code has copied initialised variables into RAM, zeroed the rest, set up clocks and run constructors. When a board does not start, starts only sometimes, or behaves differently from a cold power-on than from a debugger reset, the cause is almost always here, and it is invisible unless you know what the sequence is supposed to be.
The unit in six ideas
- 1A power-on-reset circuit holds the chip in reset until the supply passes a threshold, plus a hold delay; brown-out detection does the same while running.
- 2A Cortex-M0+ reads its first SP and PC from address 0, so something valid must appear there: a fixed ROM, an aliased memory chosen at reset, or flash itself.
- 3The vector table is an array of words: word 0 is the initial SP, word n the handler for exception n, and IRQ k is exception k + 16; entry address = VTOR + 4n.
- 4On a Cortex-M, SP comes from vector word 0; some start-ups set it again so the handler is safe to enter without a reset.
- 5A full start-up does early hardware set-up, initialises memory, runs constructors and calls main(); CMSIS-style start-ups call SystemInit first, the pico-sdk initialises memory first and sets clocks in runtime_init().
- 6A complete Cortex-M0+ start-up is a vector table (initial SP, Reset_Handler, weak defaults) plus a reset handler that copies .data, zeroes .bss, calls main() and never returns.
Lessons
What Happens at Reset?
Your firmware’s first line runs in an environment that someone else set up: which parts of it can you count on, and which parts are still random?
Boot Sources and Address Mapping
Who decides what the core finds at address 0, and what happens when the answer is “nothing valid”?
Entry Points and Exception Tables
What is the table it reads, and what goes wrong when one word of it is wrong?
Initializing the Stack and Runtime Memory
What exactly does it do, and how long does it take?
From Startup Code to the Application
Which code runs before main(), in what order, and what is each piece allowed to assume?
Writing a Minimal Startup Sequence
What is the smallest start-up that honestly gives C everything it promises?