SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: What is the bootloader and startup code in embedded systems?
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

What is the bootloader and startup code in embedded systems?

Ryan Ryan
Last updated: September 16, 2023 3:30 am
Ryan Ryan 10 Min Read
Share
SHARE

Embedded systems rely on a bootloader and startup code to initialize the hardware and software components and get the system up and running. The bootloader is a small piece of code that runs when the system first powers on and gets things started. The startup code then takes over and completes the system initialization before the main application code runs.

Contents
The BootloaderBootloader DesignStartup CodeStartup Code OrganizationBootloader vs Startup CodeBootloader DevelopmentBootloader TestingStartup Code DevelopmentStartup OptimizationConclusion

The Bootloader

The primary job of the bootloader is to load the main program into memory and start executing it. This requires a few key tasks:

  • Initialize critical hardware components like CPU, RAM, clocks, and I/O peripherals
  • Detect and initialize external memory if present
  • Copy the main program from non-volatile storage (flash or ROM) into RAM
  • Pass control to the startup code of the main program

The bootloader runs from internal ROM or flash memory and has access to limited hardware resources. It needs to set up just enough of the system to be able to read the main program into RAM and start it running. The bootloader typically runs in a special CPU mode with minimal stack space.

Bootloader Design

Several design decisions go into implementing an embedded bootloader:

  • Integrated vs Separated: The bootloader code can be linked into the same executable as the main program or exist as a completely separate program.
  • Boot Medium: The bootloader needs to access the medium containing the main program, such as flash memory, SD card, or external EEPROM.
  • Communication: A communication protocol may be needed for the bootloader to download the main program over a network link.
  • Security: Some bootloaders incorporate security features like digital signatures to verify the authenticity of the main firmware image before booting it.
  • Updatability: The bootloader may need to support field upgrades of the main program image.

Bootloader code often lives in a separate partition of internal flash memory. This reserves space for the bootloader while keeping it isolated from the main code which may need to be updated. The bootloader partition will also need to be protected against accidental writes or erasure.

Startup Code

After the bootloader passes control to the main program, the startup code completes the hardware and software initialization. This enables the full functionality required by the main application. Typical startup tasks include:

  • Enable protected/privileged CPU modes as needed
  • Set up memory regions and segments for code, data, stack, heap, etc.
  • Initialize CPU registers and critical variables
  • Set up the stack pointer and stack overflow checks
  • Initialize system clocks, bus speeds, and power management
  • Configure peripheral devices drivers like GPIO, I2C, SPI, UARTs, etc.
  • Test and initialize external RAM and memories
  • Load initialized data from ROM to RAM as needed
  • Clear or initialize RAM contents as desired
  • Call constructors for global C++ objects
  • Initialize operating system and device drivers as needed

The startup code culminates in a call to the main() function of the application. At this point the hardware is fully operational and all OS, libraries, and drivers are ready for use. The application main loop will run until the system is rebooted.

Startup Code Organization

The startup code may be implemented across multiple files and modules:

  • Low-level CPU and hardware initialization code
  • Board/SoC specific system initialization
  • OS kernel and thread initialization
  • Device driver initialization functions
  • C/C++ runtime and library initialization like heap allocation
  • Constructors for global objects
  • Main function call

The order of operations is very important in the startup sequence. Things like the stack pointer, exceptions, and interrupts must be set up before any substantive initialization code can run. There may also be ordering dependencies like initializing the system clocks before SPI peripherals.

Bootloader vs Startup Code

The bootloader and startup code serve related but distinct purposes:

  • The bootloader is a standalone program that runs upfront to load the main firmware.
  • The startup code is part of the main program that runs initialization before the main loop.
  • Bootloader focuses on minimal viable hardware for loading firmware.
  • Startup enables full functionality for main application needs.
  • Bootloader runs in a limited standalone environment.
  • Startup runs as part of main program with all resources available.
  • Bootloader code is buried in internal ROM or flash.
  • Startup code is linked into each main firmware image.

The bootloader hands off control to the startup code of the main program once it has copied the firmware image to RAM and can start executing it. The startup code then picks up where the bootloader left off and initializes everything needed for the main application code to run.

Bootloader Development

Developing an embedded bootloader requires attention to some unique aspects:

  • Restricted execution environment – Limited memory, stack, interrupts, etc.
  • May need to support multiple CPU architectures or hardware configurations.
  • Requires access to non-volatile storage like flash memory or external memories.
  • Needs fault tolerance for recovery from invalid firmware images.
  • Security features to prevent tampering with firmware images.
  • Methods for updating the bootloader itself as needed.

As a result bootloaders are usually written in Assembly or C languages for low level access, speed, small size, and avoidance of runtime dependencies. The code needs to be thoroughly tested under various failure conditions like power cycles during firmware updates. Secure bootloaders require significant expertise in cryptographic functions, key storage, and authentication techniques.

Some processors have dedicated boot ROM functionality or standardized interfaces that simplify bootloader development. This helps handle the processor and hardware initialization while the bootloader focuses on loading the desired firmware image from external memories and starting it up properly.

Bootloader Testing

Rigorous testing helps ensure the bootloader is robust and fault-tolerant:

  • Try corrupt firmware images or partially erased flashes
  • Introduce faulty image headers or invalid signatures
  • Simulate unsuccessful flash erase/write operations
  • Cut power during firmware image updates
  • Try overflowing fixed bootloader buffers
  • Manipulate CPU modes and privilege levels
  • Check fallback recovery modes like default images

Hardware tools like logic analyzers help capture the detailed boot up sequences. Bootloader code will be some of the most heavily exercised in the entire system – it runs on every reset and power cycle.

Startup Code Development

On the startup code side, key aspects include:

  • Ordering initialization steps properly
  • Tuning performance of startup sequence
  • Setting up memory regions and segments
  • Early initialization of core peripherals
  • Late initialization of optional drivers/features
  • Calling constructors in right order
  • InitializingVariables before code access
  • Error handling if initialization fails

The startup code executes in a more flexible environment than the bootloader but still must follow strict ordering rules. Complex hardware, OS, and drivers can make the startup sequence quite lengthy. The startup code also needs to play nicely with bootloader limitations like avoiding its reserved memory regions.

Startup Optimization

Startup time directly impacts user experience on resets and wakeups. Some optimization techniques include:

  • Initialize hardware asynchronously or on-demand if possible
  • Break startup into required and optional modules
  • Initialize RAM in bulk instead of bytewise clears
  • Order code to avoid unnecessary jumps
  • Tune compiler settings for smaller code size
  • Initialize global variables on first use

Faster startup gets the main application running quicker at the cost of some added complexity. The optimal tradeoff depends on the application needs. Latencies may range from milliseconds for simple microcontrollers to seconds for complex embedded OS boots.

Conclusion

The bootloader and startup code form the crucial foundation needed to transition an embedded system from power on to full operation. The compact bootloader initializes just enough hardware to load the main program into memory and begin executing it. The flexible startup code then brings up all the capabilities required for the main application code to run successfully. Together they allow an embedded system to efficiently move from reset to real world functioning.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article What is the difference between bootloader, startup code and bootstrap loader?
Next Article What are SP (stack) and LR in ARM?
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

What is bare metal embedded programming?

Bare metal embedded programming refers to developing firmware directly on…

9 Min Read

Optimizing make_mmi_file.tcl Generation Time for Cortex-M1 Systems

Generating the make_mmi_file.tcl script is a key step in building…

6 Min Read

What architectural features of Cortex-M3 make it a low power device?

The Cortex-M3 processor from ARM is designed to be an…

7 Min Read

ARM Cortex-M4 DSP

The ARM Cortex-M4 processor is a 32-bit RISC CPU that…

5 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account