Bird
Raised Fist0
Embedded Cprogramming~15 mins

Startup sequence and reset vector in Embedded C - Deep Dive

Choose your learning style10 modes available
Overview - Startup sequence and reset vector
What is it?
The startup sequence is the set of steps a microcontroller or processor follows when it is powered on or reset. The reset vector is a special memory address where the processor begins executing code after a reset. Together, they prepare the system by initializing hardware and software before running the main program.
Why it matters
Without a proper startup sequence and reset vector, the processor wouldn't know where to begin executing instructions, leading to unpredictable behavior or system failure. This concept ensures the device boots correctly every time, making embedded systems reliable and stable.
Where it fits
Learners should first understand basic processor architecture and memory concepts. After this topic, they can explore interrupt handling, bootloaders, and low-level hardware initialization.
Mental Model
Core Idea
The reset vector is the processor's starting point after reset, triggering the startup sequence that sets up the system before running the main program.
Think of it like...
It's like turning on a car: the reset vector is the ignition key position that starts the engine, and the startup sequence is the engine warming up and systems checking before you can drive.
┌───────────────┐
│ Power On / Reset │
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ Reset Vector  │  <-- Fixed memory address
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ Startup Code  │  <-- Initialize hardware, stack, clocks
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ Main Program  │  <-- Application runs
└───────────────┘
Build-Up - 7 Steps
1
FoundationWhat is a Reset Vector?
🤔
Concept: Introduce the reset vector as a fixed memory address where the processor starts after reset.
When a microcontroller powers on or resets, it needs a known place to begin executing instructions. This place is called the reset vector. It is a specific address in memory hardwired into the processor. The processor fetches the instruction from this address first.
Result
The processor always starts executing code from the reset vector after reset.
Understanding the reset vector is key to knowing how the processor knows where to start running code.
2
FoundationPurpose of the Startup Sequence
🤔
Concept: Explain why the startup sequence is needed before the main program runs.
The startup sequence prepares the system by setting up hardware components like clocks, memory, and stack pointers. It also initializes variables and configures peripherals. This ensures the main program runs in a stable and predictable environment.
Result
The system is ready and stable before the main program starts.
Knowing the startup sequence prevents confusion about why the main program can't run immediately after reset.
3
IntermediateTypical Steps in Startup Code
🤔
Concept: Detail common tasks performed during the startup sequence.
Startup code usually does these steps: 1. Disable interrupts to avoid unexpected behavior. 2. Initialize the stack pointer. 3. Copy initialized data from ROM to RAM. 4. Zero out uninitialized data (BSS section). 5. Configure system clocks. 6. Enable interrupts. 7. Call the main() function.
Result
The system memory and hardware are properly configured for the application.
Recognizing these steps helps understand how embedded systems prepare their environment before running user code.
4
IntermediateReset Vector Location and Linker Role
🤔
Concept: Explain how the reset vector address is set and how the linker places startup code there.
The reset vector is at a fixed address defined by the processor architecture. The linker script tells the compiler where to place the startup code so it matches this address. This ensures the processor fetches the correct instructions after reset.
Result
Startup code is correctly located at the reset vector address in memory.
Understanding the linker's role clarifies how code placement affects startup behavior.
5
IntermediateReset Sources and Their Effects
🤔Before reading on: Do you think all resets start the startup sequence the same way? Commit to your answer.
Concept: Introduce different reset sources and how they trigger the startup sequence.
Resets can come from power-on, external reset pins, watchdog timers, or software commands. Regardless of source, the processor jumps to the reset vector and runs the startup sequence. However, some systems may handle certain resets differently in software.
Result
The startup sequence runs after any reset source, ensuring consistent initialization.
Knowing reset sources helps design robust systems that handle unexpected resets gracefully.
6
AdvancedCustomizing Startup Code for Optimization
🤔Before reading on: Do you think startup code must always initialize everything, or can it be optimized? Commit to your answer.
Concept: Explain how startup code can be tailored for faster boot or specific hardware needs.
Developers can customize startup code to skip unnecessary initializations or add hardware-specific setups. For example, if certain memory sections don't need clearing, skipping saves time. Also, some systems initialize clocks differently for power saving or speed.
Result
Startup time can be reduced and hardware configured precisely for application needs.
Understanding customization options enables efficient and tailored embedded system designs.
7
ExpertReset Vector and Startup in Complex Systems
🤔Before reading on: In multi-core or secure systems, do you think all cores share the same reset vector? Commit to your answer.
Concept: Explore how reset vectors and startup sequences work in multi-core or security-focused processors.
In multi-core processors, each core may have its own reset vector and startup sequence. Secure systems may have protected reset vectors or bootloaders that verify code integrity before running startup code. This adds complexity to the startup process to ensure security and correct multi-core operation.
Result
Startup sequences adapt to system complexity, ensuring secure and coordinated booting.
Knowing these complexities prepares developers for advanced embedded system challenges.
Under the Hood
When reset occurs, the processor hardware sets the program counter to the reset vector address. This triggers fetching the first instruction from that location. The startup code runs, configuring CPU registers, memory sections, and peripherals. The stack pointer is set to a known location to manage function calls and interrupts. After initialization, control passes to main().
Why designed this way?
Processors use a fixed reset vector to simplify hardware design and ensure a known start point. The startup sequence is separated from main() to handle low-level setup transparently. This design allows application code to focus on functionality without worrying about hardware initialization details.
┌───────────────┐
│ Hardware Reset│
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ PC ← Reset Vector Address │
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ Startup Code  │
│ - Init SP     │
│ - Copy Data   │
│ - Clear BSS   │
│ - Setup Clocks│
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ main()        │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does the reset vector contain the full startup code? Commit to yes or no.
Common Belief:The reset vector holds the entire startup code instructions.
Tap to reveal reality
Reality:The reset vector usually contains a jump instruction to the startup code located elsewhere in memory.
Why it matters:Misunderstanding this can cause incorrect linker scripts or startup code placement, leading to boot failures.
Quick: After reset, does the processor immediately run main()? Commit to yes or no.
Common Belief:The processor runs main() immediately after reset.
Tap to reveal reality
Reality:The processor runs the startup sequence first to initialize hardware and memory before calling main().
Why it matters:Skipping startup initialization can cause unpredictable program behavior or crashes.
Quick: Do all resets behave identically in embedded systems? Commit to yes or no.
Common Belief:All resets trigger the same startup sequence without variation.
Tap to reveal reality
Reality:Some resets, like watchdog resets, may require special handling or cause different startup behavior.
Why it matters:Ignoring reset source differences can lead to missed error recovery or system instability.
Quick: In multi-core systems, do all cores share one reset vector? Commit to yes or no.
Common Belief:All cores in multi-core processors share the same reset vector address.
Tap to reveal reality
Reality:Each core often has its own reset vector and startup sequence to allow independent booting.
Why it matters:Assuming a single reset vector can cause incorrect startup code design in multi-core systems.
Expert Zone
1
Some processors support relocating the reset vector to RAM for faster boot or patching without reflashing ROM.
2
Startup code often disables watchdog timers early to prevent unintended resets during initialization.
3
In secure boot systems, the reset vector may point to a bootloader that verifies firmware integrity before running startup code.
When NOT to use
Relying solely on the default startup sequence is not suitable for systems requiring fast boot times or custom hardware initialization. In such cases, custom minimal startup code or bootloaders should be used.
Production Patterns
In production, startup code is often hand-optimized in assembly for speed and size. Bootloaders precede startup code to handle firmware updates and security checks. Multi-core systems use coordinated startup sequences with inter-core signaling.
Connections
Interrupt Vector Table
Builds-on
Understanding the reset vector helps grasp how processors use vector tables to handle interrupts and exceptions similarly.
Bootloader Design
Precedes and extends
The startup sequence often follows the bootloader, so knowing startup helps understand how bootloaders prepare systems for application code.
Operating System Kernel Initialization
Similar pattern in software
The startup sequence in embedded systems parallels OS kernel initialization, where hardware and memory are set up before user programs run.
Common Pitfalls
#1Forgetting to initialize the stack pointer in startup code.
Wrong approach:void Reset_Handler() { main(); }
Correct approach:void Reset_Handler() { __set_MSP(stack_top_address); // Initialize stack pointer main(); }
Root cause:Assuming the processor sets the stack pointer automatically leads to crashes when functions use the stack.
#2Placing startup code at the wrong memory address.
Wrong approach:Linker script places startup code at 0x2000 instead of reset vector address 0x0000.
Correct approach:Linker script places startup code at 0x0000, matching the reset vector address.
Root cause:Not aligning code placement with processor reset vector causes the CPU to fetch invalid instructions.
#3Not disabling interrupts during startup initialization.
Wrong approach:void Reset_Handler() { // interrupts enabled initialize_hardware(); main(); }
Correct approach:void Reset_Handler() { __disable_irq(); initialize_hardware(); __enable_irq(); main(); }
Root cause:Interrupts firing before system is ready can cause unpredictable behavior or crashes.
Key Takeaways
The reset vector is a fixed memory address where the processor starts executing after reset.
The startup sequence prepares hardware and memory so the main program can run reliably.
Startup code typically initializes the stack pointer, copies data, clears memory, and sets up clocks.
Linker scripts must place startup code at the reset vector address to ensure correct booting.
Advanced systems may customize startup sequences for speed, security, or multi-core coordination.

Practice

(1/5)
1. What is the primary role of the reset vector in an embedded C program?
easy
A. It manages power consumption modes.
B. It initializes all global variables to zero.
C. It handles interrupts during program execution.
D. It tells the microcontroller where to start executing code after a reset.

Solution

  1. Step 1: Understand the reset vector concept

    The reset vector is a special address in memory that points to the first instruction executed after a reset.
  2. Step 2: Identify its role in program start

    When the microcontroller resets, it jumps to the reset vector to begin running the startup code.
  3. Final Answer:

    It tells the microcontroller where to start executing code after a reset. -> Option D
  4. Quick Check:

    Reset vector = start address after reset [OK]
Hint: Reset vector points to start code after reset [OK]
Common Mistakes:
  • Confusing reset vector with interrupt vector
  • Thinking reset vector initializes variables
  • Assuming reset vector manages power modes
2. Which of the following is the correct way to declare the reset vector in embedded C?
easy
A. int ResetVector = 0x0000;
B. void ResetVector() { main(); }
C. void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler;
D. char *ResetVector = "Reset_Handler";

Solution

  1. Step 1: Understand reset vector declaration

    The reset vector is usually a pointer to a function placed in a special memory section.
  2. Step 2: Check syntax correctness

    void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler; correctly declares a constant function pointer to Reset_Handler placed in the ".reset_vector" section using GCC attribute syntax.
  3. Final Answer:

    void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler; -> Option C
  4. Quick Check:

    Function pointer in reset vector section = correct declaration [OK]
Hint: Reset vector is a function pointer in special section [OK]
Common Mistakes:
  • Declaring reset vector as int or char pointer
  • Defining reset vector as a function instead of pointer
  • Missing section attribute for placement
3. Given the following code snippet, what will be the output after reset?
void Reset_Handler(void) {
    int x = 5;
    x += 10;
    while(1) {}
}

void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler;
medium
A. The program will enter an infinite loop after setting x to 15.
B. The program will run main() and print 15.
C. The program will cause a runtime error due to missing main.
D. The program will reset repeatedly.

Solution

  1. Step 1: Analyze Reset_Handler behavior

    Reset_Handler sets x to 5, adds 10 making x = 15, then enters an infinite loop.
  2. Step 2: Understand program flow after reset

    After reset, the microcontroller jumps to Reset_Handler and stays in the infinite loop; no main() is called.
  3. Final Answer:

    The program will enter an infinite loop after setting x to 15. -> Option A
  4. Quick Check:

    Reset_Handler runs then loops forever = infinite loop [OK]
Hint: Reset_Handler runs then loops forever, no main called [OK]
Common Mistakes:
  • Assuming main() is called automatically
  • Expecting output or print statements
  • Confusing variable x scope and effect
4. Identify the error in this startup code snippet:
void Reset_Handler(void) {
    // Initialize data
    extern int _sidata, _sdata, _edata;
    int *src = &_sidata;
    int *dst = &_sdata;
    while(dst < &_edata) {
        *dst++ = *src++;
    }
    main();
}

void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler;
medium
A. Reset_Handler should not call main() directly.
B. The pointers _sidata, _sdata, _edata should be declared as extern char, not int.
C. The while loop condition should use <= instead of <.
D. ResetVector should not be a function pointer.

Solution

  1. Step 1: Check pointer types for memory copy

    Memory sections like _sidata, _sdata, _edata represent byte addresses and should be pointers to char or unsigned char, not int.
  2. Step 2: Understand pointer arithmetic impact

    Using int pointers causes incorrect copying because pointer arithmetic advances by sizeof(int), skipping bytes.
  3. Final Answer:

    The pointers _sidata, _sdata, _edata should be declared as extern char, not int. -> Option B
  4. Quick Check:

    Memory pointers for data init = char* not int* [OK]
Hint: Use char pointers for memory copy in startup [OK]
Common Mistakes:
  • Using int pointers for byte-wise memory copy
  • Changing loop condition incorrectly
  • Thinking main() call is wrong here
5. You want to create a startup sequence that initializes .data and .bss sections and then jumps to main(). Which of the following code snippets correctly implements this in embedded C?
hard
A. void Reset_Handler(void) { extern char _sidata, _sdata, _edata, _sbss, _ebss; char *src = &_sidata; char *dst = &_sdata; while(dst < &_edata) *dst++ = *src++; dst = &_sbss; while(dst < &_ebss) *dst++ = 0; main(); } void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler;
B. void Reset_Handler(void) { int *src = &_sidata; int *dst = &_sdata; while(dst <= &_edata) *dst++ = *src++; main(); } void ResetVector = Reset_Handler;
C. void Reset_Handler(void) { main(); } void (* ResetVector)(void) = Reset_Handler;
D. void Reset_Handler(void) { extern char _sidata, _sdata, _edata; char *src = &_sdata; char *dst = &_sidata; while(src < &_edata) *dst++ = *src++; main(); } void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler;

Solution

  1. Step 1: Verify .data section initialization

    void Reset_Handler(void) { extern char _sidata, _sdata, _edata, _sbss, _ebss; char *src = &_sidata; char *dst = &_sdata; while(dst < &_edata) *dst++ = *src++; dst = &_sbss; while(dst < &_ebss) *dst++ = 0; main(); } void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler; correctly copies initialized data from flash (_sidata) to RAM (_sdata to _edata) using char pointers and proper loop.
  2. Step 2: Verify .bss section zero initialization

    void Reset_Handler(void) { extern char _sidata, _sdata, _edata, _sbss, _ebss; char *src = &_sidata; char *dst = &_sdata; while(dst < &_edata) *dst++ = *src++; dst = &_sbss; while(dst < &_ebss) *dst++ = 0; main(); } void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler; zeroes the .bss section (_sbss to _ebss) by setting bytes to 0 before calling main().
  3. Step 3: Check reset vector declaration

    void Reset_Handler(void) { extern char _sidata, _sdata, _edata, _sbss, _ebss; char *src = &_sidata; char *dst = &_sdata; while(dst < &_edata) *dst++ = *src++; dst = &_sbss; while(dst < &_ebss) *dst++ = 0; main(); } void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler; declares ResetVector as a constant function pointer placed in the reset vector section, which is correct.
  4. Final Answer:

    Option A correctly implements startup sequence with .data and .bss initialization and reset vector. -> Option A
  5. Quick Check:

    Proper .data/.bss init + correct reset vector = void Reset_Handler(void) { extern char _sidata, _sdata, _edata, _sbss, _ebss; char *src = &_sidata; char *dst = &_sdata; while(dst < &_edata) *dst++ = *src++; dst = &_sbss; while(dst < &_ebss) *dst++ = 0; main(); } void (* const ResetVector)(void) __attribute__((section(".reset_vector"))) = Reset_Handler; [OK]
Hint: Initialize .data from flash, zero .bss, then call main() [OK]
Common Mistakes:
  • Using int pointers instead of char pointers
  • Swapping source and destination pointers
  • Missing .bss zero initialization
  • Incorrect reset vector declaration
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard