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.
61 lines
3.0 KiB
Markdown
61 lines
3.0 KiB
Markdown
# 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 |