SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: How to Write a Bootloader for a Microcontroller
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

How to Write a Bootloader for a Microcontroller

Elijah Erickson
Last updated: September 8, 2023 12:49 pm
Elijah Erickson 6 Min Read
Share
SHARE

A bootloader is a small program that runs when a microcontroller first powers up and helps load your main application code into memory. Writing your own bootloader gives you more control and customization for your embedded project.

Contents
1. Understanding the Boot Process2. Selecting a Bootloader Location3. Minimal Hardware Initialization4. Implement Bootloader-Application Handoff5. Communication Interfaces6. Updating the Bootloader7. Advanced Capabilities8. Optimizing Size vs Functionality9. Testing the Bootloader10. Documentation and Release

1. Understanding the Boot Process

When a microcontroller first receives power, it begins executing instructions starting at a preset memory address called the reset vector. This is where the bootloader code needs to live. The bootloader’s job is to initialize hardware, set up memory, and ultimately load the main firmware application.

A typical boot sequence looks like this:

  1. Microcontroller comes out of reset and jumps to the reset vector
  2. Bootloader code begins executing
  3. Bootloader sets up hardware like clocks, memory, peripherals
  4. Bootloader copies application from storage into RAM
  5. Bootloader jumps to start of application code

Once the application is running, the bootloader is no longer needed. Good bootloader design minimizes its footprint while maximizing flexibility and functionality.

2. Selecting a Bootloader Location

The bootloader needs to live in non-volatile memory so it persists across power cycles. Some options include:

  • On-chip flash – Saves space and cost but can’t be modified without an external programmer
  • External flash – Allows in-circuit reprogramming of the bootloader
  • ROM – Cheapest option but bootloader cannot be changed

The right choice depends on your budget, use case, and how often you expect to modify the bootloader. Using on-chip flash offers convenience while external flash provides more flexibility.

3. Minimal Hardware Initialization

The bootloader only needs to initialize the hardware necessary to load and run the application. This includes:

  • Clocks – Set up oscillator, PLL, system clocks
  • Memory – Initialize RAM and flash
  • Peripherals – Minimal UART, I/O for application loading

Keep the bootloader hardware initialization code lean. Leave more intensive setup for the main application.

4. Implement Bootloader-Application Handoff

To launch the user application, the bootloader must jump to the correct location in memory. This handoff requires:

  1. Copy application from storage into RAM
  2. Configure memory protection for bootloader region
  3. Set stack pointer for application
  4. Jump to application reset vector in code

Use linker scripts to ensure the application ends up at the expected address in memory. The bootloader can then cleanly jump to that known location.

5. Communication Interfaces

The bootloader needs some interface to load the application binary onto the microcontroller. Common options are:

  • UART – Universal asynchronous receiver/transmitter for serial communication
  • USB – Host support for external flash drives or host PC
  • Ethernet – Network bootloader for centralized application loading
  • CAN – Robust automotive bus for embedded networks

Add only the communication necessary for your particular application loading method. UART is simplest, while USB, Ethernet, or CAN enable more advanced use cases.

6. Updating the Bootloader

Sometimes the bootloader itself needs to be upgraded and reflashed. Several techniques allow this:

  • External programmer – Full chip erase and reprogram flash
  • Bootloader flash section – Separate memory region for just bootloader code
  • Application uploading new bootloader – Some interfaces allow self-updating

Allowing field upgrades requires planning to avoid bricking devices. Having at least one backup loading method is wise.

7. Advanced Capabilities

Some additional features to consider adding to bootloaders:

  • Encryption – Code signing and authentication to prevent tampering
  • Compression – Save bandwidth by compressing application binaries
  • Error checking – CRC, checksums to validate application integrity
  • Fallback image – Rollback to last working firmware version

These add security, robustness, and flexibility. But they also increase complexity and boot time. Only implement features needed for your use case.

8. Optimizing Size vs Functionality

Design decisions for bootloaders involve tradeoffs between size and functionality. Some guidelines include:

  • Use only necessary hardware features to minimize code space
  • Disable interrupts and complex peripherals if not needed
  • Divide code into separate modules for selective inclusion
  • Reuse initialization and functionality from application when possible

A minimal bootloader might be only a few KB. More advanced ones with extensive features can grow to 10-30KB. Find the right balance for each project.

9. Testing the Bootloader

Thoroughly test bootloader operation before relying on it for production. Some key tests:

  • Verify bootloader initializes hardware properly
  • Test loading applications to memory successfully
  • Validate robustness with corrupted application images
  • Confirm fallback and recovery mechanisms function
  • Try power cycling and resetting device through all states

Catching bootloader bugs late in development is costly. Test rigorously on prototype hardware before finalizing design.

10. Documentation and Release

Don’t forget good documentation on bootloader operation, interfaces, error codes, capabilities, etc. Include:

  • In-code comments explaining operation
  • Textual guide for usage and features
  • Changelog for version history
  • Sample code and examples

This allows others to successfully leverage your bootloader in their applications. Consider open sourcing the bootloader code for community benefit.

Writing a custom bootloader from scratch is challenging but very rewarding. Use the techniques outlined here for a robust bootloader tailored to your embedded system needs.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article ARM Cortex M Boot Sequence
Next Article Bootloader Code Example
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

Arm’s Compare and Branch Instructions (CBZ and CBNZ) Explained

The ARM Cortex series of chips support conditional execution of…

8 Min Read

Stack Frame Layout During Cortex-M Interrupts

When an interrupt occurs on a Cortex-M processor, the processor…

7 Min Read

Is bare metal low level code?

Bare metal code refers to programs that run directly on…

8 Min Read

Arm Sleep-On-Exit

Arm sleep-on-exit is a power saving feature in ARM processors…

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

Sign in to your account