VersaMCU/README.md
Julian Appel 01c5e0930e Guard env:versapad's upload against overwriting the bootloader
pio run -e versapad --target upload writes the app starting at
0x0000 and silently destroyed the installed UF2 bootloader twice
today during testing -- no warning, no error, just a board that
stopped responding to the boot-key hold.

upload_openocd.py now checks for the bootloader (verify_image against
the locally built bootloader/.pio/build/versapad_bootloader/firmware.bin)
before an env:versapad upload and refuses if one is present, pointing
at env:versapad_usb instead. Fails closed: an inconclusive check (e.g.
bootloader not built locally, SWD not responding) blocks rather than
proceeding on a guess -- confirmed necessary the hard way, since a
"fail open" first attempt let the destructive upload through silently.
Scoped to PIOENV == "versapad" only, since bootloader/platformio.ini's
own upload reuses this same script and must always be allowed to write
0x0000. A new erase-bootloader-and-flash custom target remains as the
explicit, deliberate override.

Documented the workflow (bootloader is its own PlatformIO project,
flashed once via SWD; versapad_usb is the normal path afterward;
versapad's upload is now guarded) in README.md and
doc/10_usb_bootloader.md.

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

6.5 KiB
Raw Blame History

VersaMCU

Firmware für das VersaPad-v2-Makropad. Das Projekt läuft auf einem ATSAMD21G17D mit PlatformIO und dem Arduino-SAMD-Framework.

Aktueller Funktionsumfang

Bereich Stand
Eingaben 20 MX-Tasten, 4 Encoder-Taster und 4 Quadratur-Encoder
USB Keyboard-HID, Consumer-HID und CDC Serial
Aktionen HID-Key, Consumer-Key, Host-Event, Makro, Profilwechsel
Makros 32 Slots mit je bis zu 8 HID-Schritten
Profile 3 Profile in Config v3
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.

Hardware

Eigenschaft Detail
MCU ATSAMD21G17D, Cortex-M0+, 48 MHz
Flash / RAM 128 KiB / 16 KiB
Matrix logisch 5×5: 20 MX, 4 Encoder-SW, 1 unbelegt
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, oder USB über den UF2-Bootloader

Schnellstart

Voraussetzungen sind PlatformIO Core oder die PlatformIO IDE sowie für den Upload ein angeschlossener Atmel-ICE beziehungsweise kompatibler CMSIS-DAP-Adapter.

pio run -e versapad
pio run -e versapad --target upload

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.

Alternativ lässt sich die App-Firmware nach einem einmaligen SWD-Bootloader-Flash auch über USB aktualisieren, ganz ohne Atmel-ICE:

cd bootloader && pio run -e versapad_bootloader --target upload   # einmalig
pio run -e versapad_usb --target upload                           # danach jedes App-Update

bootloader/ ist ein eigenständiges PlatformIO-Projekt (eigene platformio.ini, kein Arduino-Framework). Für die PlatformIO-IDE-Buttons in VS Code müsste der Ordner separat als eigener Workspace geöffnet werden; über die Kommandozeile reicht cd bootloader && pio run ... im selben Fenster.

Sobald der Bootloader installiert ist, verweigert versapad --target upload den normalen Upload — dieser Weg schreibt ab 0x0000 und würde den Bootloader sonst kommentarlos überschreiben (upload_openocd.py prüft das vorher automatisch). Bauen und Debuggen über versapad bleiben uneingeschränkt möglich, nur der Upload ist betroffen. Für App-Updates danach versapad_usb verwenden; bewusst zurück zu reinem SWD-Betrieb geht über pio run -e versapad -t erase-bootloader-and-flash.

Details, Speicherlayout und die Bootloader-Aktivierung (kein physischer Reset-Taster auf dieser Platine) stehen in 10_usb_bootloader.md.

Laufzeitmodell

main.cpp besitzt genau einen CMainController. Nach einem roten Startsignal initialisiert er NVM, USB, Matrix und Encoder. Die Hauptschleife ist:

matrix_scan()
poll_vendor()
processEvents()
check_factory_reset()
updateLEDs()
  • Matrix und Encoder legen SEvents in eine feste Queue.
  • Der Controller setzt Events in HID-Aktionen, Makros, Host-Events oder Profilwechsel um.
  • poll_vendor() verarbeitet feste 8-Byte-Pakete über CDC.
  • LEDs werden nur neu übertragen, wenn ein Zustand dirty ist oder eine Animation läuft.
  • Makros, Encoder-Taps, NVM-Zugriffe und visuelles Reset-Feedback blockieren den Loop kurzzeitig; es gibt keinen Scheduler.

Wichtige Datenverträge

Config v3

  • Magic 0x56503203
  • SDeviceConfig: 740 Byte
  • CRC16-CCITT über Bytes 7..739
  • 3 Profile
  • globale und LED-spezifische Helligkeit
  • 124 Chunks mit je 6 Nutzbytes beim CDC-Transfer

Makros

  • SMacroTable: 512 Byte
  • 32 Slots × 8 Schritte × 2 Byte
  • 86 Chunks mit je 6 Nutzbytes beim CDC-Transfer

Flashzugriffe

Bereich Adresse Größe
Makros 0x1FB00..0x1FCFF 512 B
Config 0x1FD00..0x1FFFF 768 B, davon 740 B genutzt

Das aktive Linker-Skript und boards/versapad_nobl.json begrenzen das Firmware-Image auf 0x00000..0x1FAFF. Damit sind alle fünf NVM-Rows gegen Firmwarewachstum geschützt.

Werksreset

Unteren linken und unteren rechten MX-Button gleichzeitig fünf Sekunden halten:

  • die Tasten werden während des Haltens rot markiert,
  • ihre normalen Aktionen werden unterdrückt,
  • bei Erfolg blinken alle LEDs kurz rot,
  • Config und Makrotabelle werden auf Defaults zurückgesetzt.

Ein normaler SWD-Reflash löscht diese NVM-Daten nicht automatisch.

Projektstruktur

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
    |-- CButton.*             # Actions und LED-Zustand
    |-- CEventQueue.*         # feste Event-Queue
    |-- config/               # Binärformate, NVM und Pins
    `-- hal/                  # Matrix, Encoder, HID, CDC, WS2812

Einstieg für Entwickler und LLMs

Für einen neuen Kollegen:

  1. Entwicklung und Einstieg
  2. Architektur
  3. die zum Task passende Fachdokumentation im Dokumentationsindex
  4. bekannte Einschränkungen

Für einen Coding-Agent zusätzlich AGENTS.md als Repository-Anweisung mitgeben. Die Datei enthält Quellenhierarchie, Binärverträge, Änderungsregeln und die minimale Verifikation.

Dokumentation