New project under bootloader/ with the same structure as color_switcher: Dockerfile, docker-compose, modular CMake, and APP_BOOT + SYS_ECU stub components. Reuses common/ submodules for MCU_UART, MCU_USB, HAL_COM, STD_TYPES. TODO.md lists all open design decisions (interface, protocol, flash layout, entry trigger, integrity checks, flash strategy) and the implementation tasks that depend on them.
3.0 KiB
3.0 KiB
Bootloader — Design Decisions & TODO
Open Design Decisions
These must be resolved before implementation begins:
1. Firmware update interface
- UART only
- USB-CDC only
- Both (selectable via config or auto-detect)
- Notes: We have MCU_UART and MCU_USB in common/ ready to use via HAL_COM.
2. Transfer protocol
- Custom simple protocol (length + CRC32 + raw binary)
- XMODEM / YMODEM (standard, many terminal tools support it)
- Custom framed protocol (start byte, length, payload, CRC, end byte)
- Notes: Custom is simplest to implement. XMODEM is widely supported by serial tools.
3. Flash memory layout
- Define bootloader size (e.g., first 16 KB, 32 KB, or 64 KB of flash)
- Define application start address
- Define metadata region (app version, CRC, valid flag)
- Notes: RP2040 has 2 MB flash. Pico SDK linker script needs modification to place the bootloader and app at different addresses.
4. Bootloader entry trigger
- Always enter bootloader, wait N seconds for firmware, then jump to app
- Check a GPIO pin (button held = stay in bootloader)
- Check a magic value in flash/RAM (set by the application to request update)
- Combination: check button first, then magic value, then jump to app
- Notes: "Button + timeout" is the most user-friendly approach.
5. Application jump mechanism
- Read the app's vector table at the app start address
- Set the MSP (main stack pointer) from the vector table
- Jump to the reset handler from the vector table
- Notes: Standard Cortex-M0+ boot sequence. Need to disable interrupts and peripherals before jumping.
6. Integrity verification
- CRC32 check on the received firmware before writing to flash
- CRC32 check on the stored application before jumping (boot-time validation)
- Signature verification (stretch goal — not needed for initial version)
7. Flash write strategy
- Erase + write as chunks arrive (streaming)
- Buffer entire firmware in RAM, then erase + write at once (limited by RAM size)
- Dual-bank: write to alternate region, swap on success (A/B update)
- Notes: Streaming is most memory-efficient. A/B is safest (rollback on failure) but uses 2x flash.
Implementation Tasks
Once design decisions are made:
- Create linker scripts (bootloader.ld, application.ld) with correct flash regions
- Implement APP_BOOT_enuInit — check entry trigger, decide boot vs update mode
- Implement firmware receive via HAL_COM (protocol parsing, CRC validation)
- Implement flash write using Pico SDK hardware_flash API
- Implement application jump (disable interrupts, set MSP, branch to reset handler)
- Implement boot-time app validation (CRC check before jumping)
- Modify color_switcher's linker script to start at the app address (not 0x10000000)
- Test: flash bootloader, then send color_switcher firmware over UART/USB
- Test: corrupt firmware scenario — bootloader should stay in update mode