From 33d9e85992e8456407dbee1df104787322093aad Mon Sep 17 00:00:00 2001 From: Julian Appel Date: Wed, 5 Aug 2026 22:49:56 +0200 Subject: [PATCH] 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 --- README.md | 22 ++++++-- bootloader/README.md | 109 ++---------------------------------- bootloader/TESTING.md | 65 --------------------- doc/08_development.md | 7 ++- doc/09_known_limitations.md | 45 +++++++-------- doc/10_usb_bootloader.md | 104 ++++++++++++++++++++++++++++++++++ doc/INDEX.md | 2 + 7 files changed, 153 insertions(+), 201 deletions(-) delete mode 100644 bootloader/TESTING.md create mode 100644 doc/10_usb_bootloader.md diff --git a/README.md b/README.md index b5f0b14..7e07422 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ ATSAMD21G17D mit PlatformIO und dem Arduino-SAMD-Framework. | LEDs | 20 WS2812B mit Base-/Override-Farbe und 7 Animationsmodi | | Persistenz | Config und Makros im internen Flash | | Recovery | Werksreset über zwei Tasten | +| Firmware-Update | SWD (Atmel-ICE) oder USB (UF2-Bootloader, `bootloader/`) | Die drei Fader-Pins sind im Board-Variant definiert, werden von der aktuellen Firmware aber noch nicht eingelesen. @@ -29,7 +30,7 @@ Firmware aber noch nicht eingelesen. | Encoder | 4× Quadratur über EIC-Interrupts | | LEDs | 20× WS2812B an `PB22` | | USB | Native USB als HID + CDC Composite Device | -| Programmer | Atmel-ICE/CMSIS-DAP über SWD, standardmäßig ohne Bootloader | +| Programmer | Atmel-ICE/CMSIS-DAP über SWD, oder USB über den UF2-Bootloader | ## Schnellstart @@ -46,9 +47,17 @@ Das Standard-Environment `versapad` baut für `boards/versapad_nobl.json`. Der Upload wird durch `upload_openocd.py` über das von PlatformIO installierte OpenOCD ausgeführt. -Das in `platformio.ini` auskommentierte Bootloader-Environment ist derzeit -nicht als Produktionsziel unterstützt. Details stehen unter -[bekannte Einschränkungen](doc/09_known_limitations.md). +Alternativ lässt sich die App-Firmware nach einem einmaligen +SWD-Bootloader-Flash auch über USB aktualisieren, ganz ohne Atmel-ICE: + +```bash +cd bootloader && pio run -e versapad_bootloader --target upload # einmalig +pio run -e versapad_usb --target upload # danach jedes App-Update +``` + +Details, Speicherlayout und die Bootloader-Aktivierung (kein physischer +Reset-Taster auf dieser Platine) stehen in +[10_usb_bootloader.md](doc/10_usb_bootloader.md). ## Laufzeitmodell @@ -119,9 +128,13 @@ VersaMCU/ |-- AGENTS.md # Kontext und Richtlinien für Coding-LLMs |-- README.md |-- platformio.ini +|-- upload_openocd.py # SWD-Upload-Hook (env:versapad) +|-- uf2conv.py # .bin -> .uf2 Konverter (App-Firmware) +|-- upload_uf2.py # USB-Upload-Hook (env:versapad_usb) |-- boards/ # PlatformIO-Boarddefinitionen |-- variants/versapad/ # Pinmapping und Linker-Skripte |-- doc/ # Architektur- und Protokolldokumentation +|-- bootloader/ # UF2-Bootloader (eigenes PlatformIO-Projekt) `-- src/ |-- main.cpp |-- CMainController.* # Orchestrierung @@ -157,3 +170,4 @@ Binärverträge, Änderungsregeln und die minimale Verifikation. - [CDC-Protokoll](doc/07_serial_protocol.md) - [Entwicklung und Einstieg](doc/08_development.md) - [Bekannte Einschränkungen](doc/09_known_limitations.md) +- [USB-Bootloader](doc/10_usb_bootloader.md) diff --git a/bootloader/README.md b/bootloader/README.md index 3090d60..113872e 100644 --- a/bootloader/README.md +++ b/bootloader/README.md @@ -2,18 +2,11 @@ USB-Bootloader für das VersaPad-v2-Makropad. Wird per Atmel-ICE/SWD einmalig auf den ATSAMD21G17D geflasht und belegt `0x0000..0x1FFF` (8 KiB). Danach -lässt sich die App-Firmware ohne SWD über USB aktualisieren: Bootloader-Modus -aktivieren, Board erscheint als USB-Laufwerk `VERSABOOT`, `.uf2`-Datei drauf -kopieren. +lässt sich die App-Firmware ohne SWD über USB aktualisieren. -Der komplette Weg — Bootloader-Einstieg, `.uf2`-Erzeugung, Kopieren aufs -Laufwerk, automatischer Rücksprung in die neu geschriebene App — ist auf -echter Hardware verifiziert, siehe [Hardwaretest](#hardwaretest-2026-08-05). - -Diese Platine hat keinen dedizierten Reset-/Boot-Taster. Bootloader-Modus -aktivieren heißt hier: unterste rechte Cherry-MX-Taste (key_id 24) beim -Einstecken/Reset gedrückt halten. Siehe -[Hardware-Bootloader-Einstieg](#hardware-bootloader-einstieg-ohne-reset-taster). +Speicherlayout, Bootloader-Aktivierung, Bedienung und Hardwaretest-Ergebnisse +stehen in [`../doc/10_usb_bootloader.md`](../doc/10_usb_bootloader.md). Diese +Datei beschreibt nur das Bootloader-Unterprojekt selbst. ## Herkunft @@ -52,42 +45,6 @@ da nur `0x0000..0x1FFF` beschrieben wird) pio run -e versapad_bootloader --target upload ``` -## Hardware-Bootloader-Einstieg ohne Reset-Taster - -Die Platine hat keinen dedizierten Reset-/Boot-Taster (Custom-PCB-Design). -Der klassische UF2-"Doppel-Tap-Reset" braucht aber gar keinen physischen Pin — -`check_start_application()` in `src/main.c` prüft ein RAM-Flag -(`DBL_TAP_PTR`/`DBL_TAP_MAGIC`), das bei jedem Reset gesetzt wird, unabhängig -von der Reset-Quelle. - -Statt eines eigenen Tasters wird die unterste rechte Cherry-MX-Taste -(`key_id 24` in der App-Firmware, siehe `../src/config/pins.h`) missbraucht: - -- `key_id 24` liegt auf COL4 (`PA08`) × ROW4 (`PA15`) -- `boot_key_pressed()` in `src/main.c` treibt ROW4 kurz auf LOW und liest - COL4 zurück — kein voller Matrixscan nötig, nur ein Drei-Pin-Check -- der Check läuft ganz am Anfang von `check_start_application()`, noch vor - der App-Adress-Validierung und vor der RCAUSE-/DBL-TAP-Logik: funktioniert - also auch bei kaputter/gelöschter App-Firmware und bei normalem Power-On - (Stecker ziehen/reinstecken), kein Software-Trigger in der App nötig -- Pin-Konstanten stehen in `include/board_config.h` - (`BOOT_KEY_ROW_PIN`/`BOOT_KEY_COL_PIN`) - -Bedienung: USB-Kabel ziehen, unterste rechte Taste gedrückt halten, Kabel -wieder einstecken (Taste dabei weiter halten) → Board bootet direkt in -`VERSABOOT`. Ohne gehaltene Taste startet die App normal. - -## App-Firmware per USB flashen (nach dem einmaligen Bootloader-Flash) - -```bash -# Board zuerst in den Bootloader-Modus versetzen: USB ziehen, unterste -# rechte Taste halten, wieder einstecken (siehe oben) -pio run -e versapad_usb --target upload -``` - -Baut die App-Firmware (Repo-Root, nicht `bootloader/`), erzeugt `firmware.uf2` -und kopiert es aufs `VERSABOOT`-Laufwerk. Kein Atmel-ICE mehr nötig. - ## Achtung bei manuellem SWD-Flashen von Bootloader UND App `upload_openocd.py` (App, `env:versapad`) und der Bootloader-Upload (oben) @@ -111,61 +68,3 @@ verwenden (nie `.elf`) und die Zieladresse **immer explizit angeben** App-Schreibvorgang **in getrennten OpenOCD-Aufrufen**, nicht in einer gemeinsamen `-c`-Kommandokette. Im Zweifel danach mit `dump_image` in einer frischen, unabhängigen Sitzung verifizieren. - -## Hardwaretest (2026-08-05) - -Erster vollständiger Hardwaretest auf einem echten VersaPad-v2-Board über -Atmel-ICE/SWD. Ergebnisse: - -- Bootloader-Build/-Flash/-Verify laufen sauber (89,9 % Flash, 7364/8192 Byte). -- USB-Enumeration und `VERSABOOT`-Massenspeicher-Modus funktionieren nach dem - PID-Fix (siehe unten) korrekt, inklusive korrektem `INFO_UF2.TXT`. -- Der Tastencheck (oben) funktioniert wie vorgesehen: gehaltene Taste beim - Boot → `VERSABOOT`, sonst normaler App-Start. -- **Kritischer Bug gefunden und behoben:** Der Sprung vom Bootloader in die - App (`__set_MSP` → `SCB->VTOR` → `bx`) führte bei jedem echten, - eigenständigen Boot (auch bei komplett getrenntem Debugger) zu einem - Hard-Fault/Lockup der CPU. Identische Register-/VTOR-Werte, vom Debugger - bei angehaltener CPU direkt injiziert, liefen dagegen einwandfrei — das - grenzte den Fehler auf die *Ausführung* der Sprungsequenz selbst ein, nicht - auf falsche Werte. Fix: `__DSB(); __ISB();` zwischen dem `SCB->VTOR`-Schreib- - zugriff und dem `bx` in `check_start_application()` (`src/main.c`) — von ARM - für genau dieses Bootloader-Pattern vorgeschrieben, hat im vendorten Code - gefehlt. Nach dem Fix bootet die App-Firmware zuverlässig, mit und ohne - angeschlossenen Debugger. -- **Zweiter Bug beim manuellen Debuggen gefunden:** Beim anschließenden - manuellen SWD-Debugging (Suche nach der Ursache des Tastencheck-Problems, - siehe oben) hat `openocd -c "program app.elf verify"` ohne explizite - Zieladresse wiederholt den Bootloader mit rohen ELF-Datei-Bytes - überschrieben, sobald Bootloader- und App-Flash im selben OpenOCD-Aufruf - kombiniert wurden — siehe "Achtung bei manuellem SWD-Flashen" oben. Nach - einem vollständigen Chip-Erase und getrennten `.bin`-Flashes mit expliziten - Adressen liefen beide Bereiche wieder zuverlässig, Tastencheck und - App-Start bestätigt funktionsfähig. -- **Kompletter USB-Flashweg getestet:** `pio run -e versapad_usb --target - upload` (App-Firmware, Repo-Root) baut `firmware.bin`, wandelt es über - [`../uf2conv.py`](../uf2conv.py) in `firmware.uf2` und kopiert es über - [`../upload_uf2.py`](../upload_uf2.py) automatisch aufs erkannte - `VERSABOOT`-Laufwerk. Der Bootloader erkennt den Schreibzugriff und - springt danach selbständig in die neue App — kein manuelles Auswerfen - oder Reset nötig. Voraussetzung: Board zuvor per gehaltener Taste (siehe - oben) in den Bootloader-Modus versetzt. - -## Bekannte Einschränkungen - -- Flash-Auslastung ~90 % (7364 von 8192 Byte). Wenig Puffer für Änderungen. -- Kein Status-LED-Feedback im Bootloader-Modus, da die Platine nur eine - WS2812-Kette (kein einfaches GPIO-LED oder DotStar) hat und der - Original-Code dafür nicht ausgelegt ist. -- USB_PID war ursprünglich `0x0011` (Adafruit Gemma M0s eigene - Bootloader-PID, unverändert aus der Vorlage übernommen) — kollidierte auf - Rechnern mit installiertem Adafruit-Treiber, wurde als `Adafruit Circuit - Playground`-COM-Port statt als Massenspeicher gebunden. Verifiziert am - 2026-08-05, seither `0x0043`. Bleibt ein Wert ohne echte Registrierung - (kein offiziell zugeteilter PID unter Adafruits VID); ein sauber eigener - VID (z. B. über pid.codes) wäre die langfristig korrekte Lösung, ist aber - nicht Teil dieses Branches. -- [`../upload_uf2.py`](../upload_uf2.py) sucht das `VERSABOOT`-Laufwerk aktuell - nur über die Windows-API (`GetVolumeInformationW`) — passend zur bisherigen - Dev-Umgebung dieses Projekts, aber nicht plattformübergreifend. Für - macOS/Linux müsste die Laufwerkssuche noch ergänzt werden. diff --git a/bootloader/TESTING.md b/bootloader/TESTING.md deleted file mode 100644 index 2bc26b6..0000000 --- a/bootloader/TESTING.md +++ /dev/null @@ -1,65 +0,0 @@ -# Bootloader-Testflash -- Ergebnis - -Der UF2-Bootloader (siehe [README.md](README.md)) wurde am 2026-08-05 auf -einem echten VersaPad-v2-Board über Atmel-ICE/SWD getestet. Zusammenfassung -der Ergebnisse steht im [Hardwaretest-Abschnitt der README](README.md#hardwaretest-2026-08-05). -Dieses Dokument hält den Testablauf und die Antworten auf die ursprünglichen -Prüffragen fest. - -**Sicherheitsrahmen, der eingehalten wurde:** Der Bootloader-Flash schreibt -nur `0x0000..0x1FFF` (8 KiB). Die App-Firmware ab `0x2000` blieb dabei -unangetastet. Über SWD war der Chip jederzeit neu beschreibbar; ein Brick war -zu keinem Zeitpunkt möglich, solange der Atmel-ICE-Zugriff funktionierte. - -## Voraussetzungen - -- Board per Atmel-ICE/SWD angeschlossen, wie beim normalen - App-Firmware-Flashen (`pio run -e versapad --target upload`, - siehe `../doc/08_development.md`) -- PlatformIO Core (hier: PlatformIO-IDE-penv unter - `%USERPROFILE%\.platformio\penv\Scripts\pio.exe`) - -## Ablauf - -1. `git checkout feature/usb-bootloader` -2. `cd bootloader && pio run -e versapad_bootloader` — Build sauber - (89,9 % Flash, 7364/8192 Byte) -3. `pio run -e versapad_bootloader --target upload` — Flash + Verify über - Atmel-ICE/SWD - -## Ursprüngliche Prüffragen und Antworten - -- **Ist der Flash-Befehl ohne Fehler durchgelaufen?** Ja, `** Verified OK **` - bei jedem Flash. -- **Erscheint nach dem Bootloader-Einstieg ein Laufwerk `VERSABOOT`?** Ja. - Getestete Board-Revision hat **keinen physischen Reset-/Boot-Taster** - (Custom-PCB) — der ursprünglich geplante Doppel-Tap-Reset-Test war damit - nicht durchführbar. Stattdessen wurde ein Hardware-Bootloader-Einstieg über - eine gehaltene Cherry-MX-Taste ergänzt, siehe - [README.md](README.md#hardware-bootloader-einstieg-ohne-reset-taster). - Mit dieser Ergänzung: gehaltene Taste beim Power-On → `VERSABOOT`. -- **Was steht in `INFO_UF2.TXT`?** - ``` - UF2 Bootloader versapad-1 SFHWRO - Model: VersaPad v2 - Board-ID: SAMD21G17D-VersaPad-v2 - ``` -- **Reagiert das Board normal als App-Firmware, wenn man es ohne gehaltene - Taste ansteckt?** Ja, nach dem in der README beschriebenen DSB/ISB-Fix. - Vor dem Fix: nein, siehe unten. -- **Ungewöhnliches?** Ja, ein echter Bug: siehe - [Hardwaretest-Abschnitt der README](README.md#hardwaretest-2026-08-05) für - die Fehlersuche (Bootloader-eigener Sprung faultete zuverlässig, obwohl vom - Debugger injizierte identische Register-/VTOR-Werte einwandfrei liefen) und - den Fix (fehlende `__DSB()`/`__ISB()` vor dem `bx` in - `check_start_application()`). -- **USB-Identität korrekt, kein Fremdtreiber-Konflikt?** Nach PID-Wechsel von - `0x0011` auf `0x0043` ja (siehe README, "Bekannte Einschränkungen" zum - ursprünglichen Adafruit-PID-Konflikt). - -## Noch NICHT getestet - -Firmware tatsächlich über das `VERSABOOT`-Laufwerk flashen. Der -Firmware-Build der App erzeugt noch keine `.uf2`-Datei (nur `.bin`/`.elf` für -den SWD-Weg) — das ist der nächste Schritt, siehe README, "Bekannte -Einschränkungen". diff --git a/doc/08_development.md b/doc/08_development.md index 9e50f00..f9607ee 100644 --- a/doc/08_development.md +++ b/doc/08_development.md @@ -26,9 +26,9 @@ pio run -e versapad --target upload Der Upload nutzt `upload_openocd.py`, das das von PlatformIO installierte OpenOCD mit `interface/cmsis-dap.cfg` und `target/at91samdXX.cfg` startet. -Das in `platformio.ini` nur als Beispiel enthaltene Environment -`versapad_usb` ist auskommentiert und mit dem aktuellen NVM-/Linker-Layout -nicht als unterstützt anzusehen. +Für App-Updates über USB (nach einem einmaligen Bootloader-Flash) gibt es +zusätzlich `env:versapad_usb`, siehe +[10_usb_bootloader.md](10_usb_bootloader.md). ## Was beim Start passiert @@ -63,6 +63,7 @@ und NVM-Schreibvorgängen. Es gibt keinen Scheduler und keine Threads. | LEDs | `05_led_system.md` | `CButton.*`, `hal/ws2812.*` | | Persistente Config | `06_nvm_config.md` | `config/nvm_config.*`, Linker-Skripte | | Host-Protokoll | `07_serial_protocol.md` | `hal/usb_serial.*`, Controller | +| USB-Bootloader | `10_usb_bootloader.md` | `bootloader/`, `variants/versapad/linker_scripts/gcc/flash_with_bootloader.ld`, `boards/versapad.json`, `uf2conv.py`, `upload_uf2.py` | ## Verifikation diff --git a/doc/09_known_limitations.md b/doc/09_known_limitations.md index 748cfab..9c79ffa 100644 --- a/doc/09_known_limitations.md +++ b/doc/09_known_limitations.md @@ -3,36 +3,33 @@ Diese Liste beschreibt den aktuellen Implementierungsstand nach den Robustheitskorrekturen. Sie ist keine Liste bereits umgesetzter Features. -## Bootloader-Ziel bleibt nicht unterstützt +## USB-Bootloader hat einen eingeschränkten Gültigkeitsbereich -Das aktive Ziel `versapad_nobl` reserviert den kompletten Bereich -`0x1FB00..0x1FFFF` für Makros und Config. +Der UF2-Bootloader (`bootloader/`, App-Environment `env:versapad_usb`, +Details in [10_usb_bootloader.md](10_usb_bootloader.md)) ist auf echter +Hardware verifiziert und ergänzt den SWD-Weg, ersetzt ihn aber nicht: der +Bootloader selbst muss weiterhin einmalig per Atmel-ICE/SWD geflasht werden. -Ein USB-Bootloader-Pfad wird im Branch `feature/usb-bootloader` aufgebaut -(`bootloader/`, App-Environment `env:versapad_usb`). Der komplette Weg ist -dort auf echter Hardware verifiziert: Bootloader-Flash, USB-Enumeration, -Tastencheck-Einstieg (kein physischer Reset-Taster auf diesem Board, siehe -`bootloader/README.md`, "Hardware-Bootloader-Einstieg"), App-Firmware per -`.uf2` über `env:versapad_usb --target upload` schreiben, automatischer -Rücksprung in die neue App. Details und ein gefundener/behobener -Hard-Fault-Bug beim Sprung Bootloader→App (fehlende `__DSB()`/`__ISB()` vor -dem `bx`) stehen in `bootloader/README.md`, "Hardwaretest". -`env:versapad_usb`s Linkerskript -(`variants/versapad/linker_scripts/gcc/flash_with_bootloader.ld`) reserviert -inzwischen denselben NVM-Bereich wie `flash_without_bootloader.ld`. +Verbleibende Einschränkungen: -Trotzdem noch kein Merge-fertiges Produktionsziel: Der `.bin`→`.uf2`-Weg -(`uf2conv.py`, `upload_uf2.py`, Repo-Root) sucht das `VERSABOOT`-Laufwerk -bisher nur über die Windows-API, keine macOS/Linux-Unterstützung. Die -Bootloader-USB-PID (`0x0043`) ist zwar kollisionsfrei verifiziert, aber kein -offiziell registrierter Wert unter Adafruits VID `0x239A`. +- `uf2conv.py`/`upload_uf2.py` (Repo-Root) suchen das `VERSABOOT`-Laufwerk + nur über die Windows-API, keine macOS/Linux-Unterstützung. +- Die Bootloader-USB-PID (`0x0043`) ist kollisionsfrei verifiziert, aber kein + offiziell registrierter Wert unter Adafruits VID `0x239A`. +- Kein Software-Trigger, um aus der laufenden App heraus in den + Bootloader-Modus zu wechseln — nur der physische Weg (Kabel ziehen, Taste + halten, wieder einstecken). +- Bootloader-Flash-Auslastung ~90 % (7364 von 8192 Byte), wenig Puffer für + Änderungen am Bootloader selbst. -Die aktive Boarddatei benennt die MCU als `samd21g17d`, setzt für den +Sowohl `boards/versapad_nobl.json` (SWD-Ziel) als auch `boards/versapad.json` +(USB-Bootloader-Ziel) benennen die MCU als `samd21g17d`, setzen für den Arduino-Core aber weiterhin das Kompatibilitätsmakro `__SAMD21G18A__`. Der PlatformIO-Build meldet korrekt 128 KiB physischen Flash, 16 KiB RAM und -129.792 Byte nutzbaren Firmwarebereich. Vor device-spezifischen -Core-Änderungen sollte die historische Makro-Abweichung trotzdem geprüft -werden. +129.792 Byte (`versapad_nobl`) beziehungsweise 121.600 Byte +(`versapad`, abzüglich 8 KiB Bootloader) nutzbaren Firmwarebereich. Vor +device-spezifischen Core-Änderungen sollte die historische Makro-Abweichung +trotzdem geprüft werden. ## Event-Queue hat eine feste Kapazität diff --git a/doc/10_usb_bootloader.md b/doc/10_usb_bootloader.md new file mode 100644 index 0000000..0397fa9 --- /dev/null +++ b/doc/10_usb_bootloader.md @@ -0,0 +1,104 @@ +# 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](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](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`): + +```bash +cd bootloader +pio run -e versapad_bootloader --target upload +``` + +Danach App-Firmware per USB (Board vorher wie oben in den Bootloader-Modus +versetzen): + +```bash +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](https://github.com/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_MSP` → `SCB->VTOR` → `bx`) 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](07_serial_protocol.md)) nachrüstbar, der dieselbe + `DBL_TAP_MAGIC`-RAM-Adresse setzt und `NVIC_SystemReset()` aufruft. diff --git a/doc/INDEX.md b/doc/INDEX.md index 91852c7..d70d4d3 100644 --- a/doc/INDEX.md +++ b/doc/INDEX.md @@ -17,6 +17,7 @@ Bereiche stehen ausdrücklich in | [07_serial_protocol.md](07_serial_protocol.md) | 8-Byte-Protokoll, Config-/Makro-Transfer, ACK/NACK | | [08_development.md](08_development.md) | Setup, Build, Einstieg nach Änderungstyp, Verifikation | | [09_known_limitations.md](09_known_limitations.md) | Aktuelle technische Einschränkungen und Risiken | +| [10_usb_bootloader.md](10_usb_bootloader.md) | UF2-Bootloader, Speicherlayout, Tastencheck-Einstieg, USB-Flashweg | Die Repository-weiten Richtlinien und der kompakte LLM-Kontext stehen in [`../AGENTS.md`](../AGENTS.md). @@ -29,3 +30,4 @@ Die Repository-weiten Richtlinien und der kompakte LLM-Kontext stehen in - Action-Semantik und HID-Hold: [03_action_engine.md](03_action_engine.md) - CDC-Protokoll und Chunk-Zahlen: [07_serial_protocol.md](07_serial_protocol.md) - bekannte Risiken vor strukturellen Änderungen: [09_known_limitations.md](09_known_limitations.md) +- Firmware per USB statt SWD flashen: [10_usb_bootloader.md](10_usb_bootloader.md)