How do you implement a bootloader on STM32?
A bootloader allows firmware updates without a hardware programmer (e.g., via UART, USB, or CAN). Here’s how to implement one on STM32:
1. Bootloader Basics
Key Concepts
Two Memory Regions:
Bootloader (e.g.,
0x08000000
to0x0800FFFF
).Application (e.g.,
0x08010000
onwards).
Vector Table Offset: Application must relocate its interrupt vector table.
Communication Protocol: UART, USB DFU, I2C, CAN, etc.
2. Hardware Setup
STM32 Board (e.g., STM32F4 Discovery, Blue Pill).
Communication Interface (e.g., USB-UART converter for UART bootloader).
Boot Pins (Optional): Some STM32s use
BOOT0
/BOOT1
pins to enter bootloader mode.
3. Step-by-Step Implementation
(1) Partition Flash Memory
Modify the linker script (.ld
file) to split Flash into bootloader and application regions.
Example (STM32F103C8 - 64KB Flash):
MEMORY { BOOTLOADER (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* First 16KB */ APP_FLASH (rx) : ORIGIN = 0x08004000, LENGTH = 48K /* Next 48KB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K }
(2) Write the Bootloader Code
The bootloader should:
Check for Firmware Update (e.g., wait for UART command).
Erase Application Sector(s).
Receive New Firmware (via UART/USB/CAN).
Write to Application Flash.
Jump to Application.
Example (UART Bootloader - Pseudocode):
#include "stm32f1xx_hal.h" #define APP_ADDRESS 0x08004000 // Start of application void JumpToApp(void) { void (*app_reset_handler)(void); uint32_t *app_stack_ptr = (uint32_t *)APP_ADDRESS; // Disable interrupts __disable_irq(); // Set new stack pointer __set_MSP(*app_stack_ptr); // Set reset handler app_reset_handler = (void (*)(void))*(uint32_t *)(APP_ADDRESS + 4); // Jump to application app_reset_handler(); } int main(void) { HAL_Init(); UART_Init(); // Configure UART // Check for firmware update (e.g., UART 'U' command) if (UART_Receive() == 'U') { Flash_Erase(APP_ADDRESS); Flash_Write(APP_ADDRESS, new_firmware_data); } // If no update, jump to application if (*(uint32_t *)APP_ADDRESS != 0xFFFFFFFF) { JumpToApp(); } while (1); // Stay in bootloader if no app }
(3) Modify the Application
The application firmware must:
Relocate Vector Table (in
main.c
):SCB->VTOR = 0x08004000; // Set Vector Table Offset
Adjust Linker Script (ensure it starts at
0x08004000
).Compile with Correct Flash Offset.
(4) Flash the Bootloader
Use ST-Link (
STM32CubeProgrammer
orOpenOCD
).Flash the bootloader to
0x08000000
.
(5) Test Firmware Update
Generate a
.bin
or.hex
file of your application.Send it via UART (e.g., using
pySerial
orSTM32CubeProgrammer
).Bootloader writes it to
0x08004000
.Reset → Jump to Application.
4. Communication Protocols
Method | Pros | Cons |
---|---|---|
UART | Simple, widely supported | Slow, requires external tool |
USB DFU | No extra hardware | Complex setup |
CAN | Robust (automotive use) | Needs CAN transceiver |
I2C/SPI | Good for multi-device systems | Slower than UART |
5. Advanced Features
CRC Checksum Verification (ensure firmware integrity).
Dual-Bank Flash (STM32F7/H7) for safe updates.
Encrypted Firmware (secure boot).
Watchdog Timer (recover from failed updates).
6. Debugging Tips
Verify Flash writes (read back and compare).
Check
VTOR
(application crashes if vector table is wrong).Use
__disable_irq()
before jumping to the app.
7. Example Tools
STM32CubeProgrammer (USB/UART flashing).
OpenOCD (for custom bootloaders).
Python Scripts (for UART firmware upload).
Conclusion
A basic UART bootloader can be implemented in <100 lines of code. For production use, consider:
STM32’s built-in DFU bootloader (via USB).
Secure bootloaders (trusted firmware updates).
评论
发表评论