VersaMCU/doc/10_usb_bootloader.md
Julian Appel 33d9e85992 Fold bootloader documentation into the main doc/ index
Adds doc/10_usb_bootloader.md as the primary reference for the UF2
bootloader (memory layout, key-based boot entry, build/flash steps,
hardware test findings, known limitations), following the existing
numbered-doc convention. Updates doc/INDEX.md, doc/09_known_limitations.md
(bootloader is no longer "not supported", just scoped), and
doc/08_development.md accordingly.

Removes bootloader/TESTING.md (its findings now live in
doc/10_usb_bootloader.md) and trims bootloader/README.md down to what
belongs with that subproject specifically: upstream attribution/license
and local build/flash commands, plus the OpenOCD manual-flashing
warning since that's implementation-specific detail that would clutter
the higher-level doc.

Updates the top-level README.md (feature table, hardware table,
quickstart, project tree, doc links) to reflect USB flashing as a
supported path alongside SWD.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 22:49:56 +02:00

4.6 KiB
Raw Blame History

USB-Bootloader (UF2)

Zweiter Firmware-Update-Weg neben SWD: ein UF2-Bootloader unter bootloader/ erlaubt, die App-Firmware über USB zu aktualisieren, ohne Atmel-ICE. Der Bootloader selbst wird einmalig per SWD geflasht; danach reicht für App-Updates ein PlatformIO-Befehl.

Speicherlayout

Bereich Adresse Größe Environment
Bootloader 0x00000..0x01FFF 8 KiB versapad_bootloader (in bootloader/)
App-Firmware 0x02000..0x1FAFF 118,75 KiB versapad_usb
NVM (Makros + Config) 0x1FB00..0x1FFFF 1,25 KiB

Gleiches NVM-Layout wie beim SWD-Ziel versapad_nobl (siehe 06_nvm_config.md); nur die Firmware-Obergrenze sinkt um die 8 KiB Bootloader. Linkerskript: variants/versapad/linker_scripts/gcc/flash_with_bootloader.ld, Boarddatei: boards/versapad.json.

Bootloader-Einstieg ohne Reset-Taster

Die Platine hat keinen dedizierten Reset-/Boot-Taster. Statt eines physischen Pins wird die unterste rechte Cherry-MX-Taste (key_id 24, COL4 × ROW4, siehe 01_matrix.md) beim Boot geprüft: check_start_application() in bootloader/src/main.c treibt ROW4 kurz auf LOW und liest COL4 zurück — noch vor der App-Adress-Validierung, funktioniert also auch bei kaputter oder fehlender App-Firmware.

Bedienung: USB-Kabel ziehen, Taste gedrückt halten, wieder einstecken (Taste weiter halten) → Board bootet in den Massenspeicher-Modus (VERSABOOT). Ohne gehaltene Taste startet die App normal.

Bauen und Flashen

Bootloader einmalig per SWD (überschreibt nur 0x0000..0x1FFF):

cd bootloader
pio run -e versapad_bootloader --target upload

Danach App-Firmware per USB (Board vorher wie oben in den Bootloader-Modus versetzen):

pio run -e versapad_usb --target upload

Baut die App, wandelt firmware.bin über uf2conv.py (Repo-Root, eigene minimale Implementierung, kein Upstream-Code) in firmware.uf2 und kopiert es über upload_uf2.py aufs erkannte VERSABOOT-Laufwerk. Der Bootloader erkennt den Schreibzugriff und springt selbständig in die neue App.

upload_uf2.py sucht das Laufwerk aktuell nur über die Windows-API (GetVolumeInformationW) — keine macOS/Linux-Unterstützung.

Herkunft und Details

Der Bootloader ist abgeleitet und stark eingekürzt aus microsoft/uf2-samdx1 (MIT), auf den SAMD21G17D-Chip dieses Boards zugeschnitten. Herkunft, Lizenz und vollständige Implementierungsdetails stehen in bootloader/README.md.

Hardwaretest (2026-08-05) und gefundene Bugs

Kompletter Weg auf echter Hardware verifiziert: Bootloader-Flash, USB-Enumeration, Tastencheck-Einstieg, App-Firmware per .uf2 schreiben, automatischer Rücksprung in die neue App. Details, Fehlerbilder und Fixes stehen in bootloader/README.md unter "Hardwaretest"; kurz zusammengefasst:

  • Fehlende Synchronisationsbarriere beim Sprung Bootloader→App. Der Sprung (__set_MSPSCB->VTORbx) faultete bei jedem eigenständigen Boot. Fix: __DSB(); __ISB(); vor dem bx in check_start_application() — von ARM für dieses Pattern vorgeschrieben, fehlte im vendorten Code.
  • USB-PID-Kollision. Die ursprünglich übernommene PID 0x0011 ist Adafruits eigene Gemma-M0-Bootloader-PID; Windows-Rechner mit installiertem Adafruit-Treiber banden das Board fälschlich als Adafruit Circuit Playground-COM-Port statt als Massenspeicher. Fix: eigene PID 0x0043.
  • OpenOCD-Falle beim manuellen SWD-Debuggen: program datei.elf verify ohne explizite Zieladresse hat wiederholt den Bootloader mit rohen ELF-Datei-Bytes überschrieben, sobald Bootloader- und App-Flash im selben OpenOCD-Aufruf kombiniert wurden. Bei manuellem Flashen beider Bereiche immer .bin mit expliziter Adresse und getrennte OpenOCD-Aufrufe verwenden — Details in bootloader/README.md, "Achtung bei manuellem SWD-Flashen".

Bekannte Einschränkungen

  • Bootloader-Flash-Auslastung ~90 % (7364 von 8192 Byte) — wenig Puffer für Änderungen am Bootloader selbst.
  • Kein Status-LED-Feedback im Bootloader-Modus (nur WS2812-Kette, dafür ist der Original-Code nicht ausgelegt).
  • USB-PID 0x0043 ist kollisionsfrei verifiziert, aber kein offiziell registrierter Wert unter Adafruits VID 0x239A.
  • upload_uf2.py ist Windows-only (siehe oben).
  • Kein Software-Trigger, um aus der laufenden App heraus in den Bootloader zurückzuspringen — nur der physische Kabel-raus/Taste-halten/Kabel-rein-Weg. Wäre über einen neuen CDC-Befehl (siehe 07_serial_protocol.md) nachrüstbar, der dieselbe DBL_TAP_MAGIC-RAM-Adresse setzt und NVIC_SystemReset() aufruft.