A bootloader is a small program that runs when a microcontroller like STM32 first powers up. It initializes the device, performs basic checks, and can load firmware into the main flash memory. Using a bootloader allows you to update firmware without external programmers. Here is an overview of how to create a simple bootloader for STM32 devices.
Bootloader Goals
The main goals of an STM32 bootloader are:
- Initialize system clocks, peripherals, and memory
- Check for forced entry to bootloader mode
- Optionally erase flash, write new firmware, then reboot
- Boot into main firmware if no update needed
This gives a way to load new firmware onto an STM32 over serial, USB, Ethernet, or other interface without needing a debugger or external flash tool.
Bootloader Code Location
The bootloader code must fit into the internal bootloader memory reserved on the STM32. This is around 16kB on most chips. The linker script must be configured to place the bootloader code and data into the correct memory region. The vector table also needs to be offset to the bootloader region base address.
Entering Bootloader Mode
The bootloader needs a way to detect if it should stay in bootloader mode or boot the main firmware. Some options are:
- Button press on powerup
- Special pulses on reset pin
- Force bootloader mode via option bytes
- Check a “bootloader request” variable in backup SRAM
The simplest approach is using the system reset button. Hold it down while powering up to enter bootloader mode.
Bootloader Initialization
The bootloader code needs to initialize enough system resources to function:
- Setup clock sources and PLL
- Configure SYSCFG and interrupts
- Initialize GPIO for bootloader signals
- Configure USART, I2C, or other interfaces
- Setup systick for delays
It does not need to initialize unused peripherals to save space. The initialization code can often be shared or based on the main application firmware for efficiency.
Firmware Update Mechanism
The bootloader needs a way to actually update the main firmware. Some options are:
- UART – Simple serial DFU protocol
- USB – CDC-ACM or DFU class
- I2C/SPI – External flash chip
- Ethernet – TCP/IP based update
- CAN – Automotive-oriented update bus
UART is the easiest protocol for initial testing. The firmware file can be sent over serial from a PC terminal program. Example open source DFU bootloaders like stm32-dfu or dfu-util provide portable DFU implementations.
Flashing Firmware
To program the new firmware received over the interface, the bootloader must:
- Erase the entire flash memory array
- Write each packet of firmware data to the flash
- Optionally verify the flash contents
- Reset and boot the new firmware
The STM32 HAL provides functions to erase and write to flash. The bootloader can use these to avoid low-level flash programming details.
Booting Main Firmware
After completing any firmware update or determining no update is required, the bootloader should branch to the main firmware entry point. This is done by loading the Stack Pointer (SP) and Program Counter (PC) from the firmware vector table.
To reduce bootloader size, it can disable interrupts and some peripherals before booting the firmware. This avoids having driver code for devices unused by the bootloader.
Development Workflow
A typical workflow for developing an STM32 bootloader is:
- Create bootloader project
- Write basic initialization code
- Add interface and DFU logic
- Implement flash programming functions
- Split main application into separate project
- Generate HEX file for bootloader
- Flash bootloader once onto device
- Iteratively update main firmware via bootloader
The bootloader only needs to be flashed initially using SWD or JTAG. After that, new firmware can be loaded solely through the bootloader interface like UART or USB.
Debugging the Bootloader
Debugging bootloader code brings some unique challenges:
- Cannot debug before bootloader flashes
- Limited space for debug logic
- Hardware debugger access disappears when booting firmware
Possible techniques to debug bootloaders include:
- Logging over serial or other interface
- Debug mode entered via codeword or input sequence
- Hybrid debug access using SWD and serial together
- Simulate update process on simple test board first
Extensive use of LEDs as status indicators is very helpful. Being able to log messages over the firmware update interface provides visibility into the bootloader operation.
Bootloader Security Features
Some enhancements to provide security in STM32 bootloaders:
- Cryptographic signature verification on firmware images
- Write protection disable only after authentication
- Validated firmware version numbers
- Readback verify to detect flash tampering
The STM32 hardware encryption accelerators like AES can enable efficient signing of firmware files. U-boot and TrustZone options also available for advanced security.
Example Projects
Some open source STM32 bootloader example projects to study:
- STLink – Simple serial DFU loader
- MCUBoot – Secure bootloader
- STM32-DFU – USB DFU bootloader
- STM32duino Ethernet – Web update
Leveraging reference designs like these can help accelerate bootloader development and ensure best practices.
Conclusion
Developing a custom bootloader for STM32 provides a flexible way to field update device firmware. It requires planning the update interface, initialization sequence, flash programming, and branch to main firmware. With careful coding it can fit into 16kB or less. Example open source projects are available to learn from and speed up bootloader creation.