Mohamed Salem 4f1199a3e6 Scaffold bootloader project with TODO checklist
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.
2026-04-18 23:37:33 +02:00

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