No description
Find a file
cjjohn 13c3e41c91 Add lightweight READ_STATUS command to avoid blocking LED updates during polling
CONFIG_READ was being (ab)used by the Windows viewer's Live-Sync feature
to poll just the active profile every 1.5s, but the handler sends the
full 740-byte config as ~124 blocking chunk packets from inside
poll_vendor() -- which runs before updateLEDs() in the same loop
iteration (see the loop-order comment at the top of
CMainController.cpp). Every poll cycle stalled updateLEDs() long enough
that running Pulse/Blink animations visibly stuttered, since their
brightness is computed from an absolute millis() timestamp and jumps
forward once the stall clears instead of catching up smoothly.

Added USB_CMD_READ_STATUS (0x06) / USB_EVT_STATUS (0x86): a single NVM
read (no serial I/O) and one 8-byte reply packet with the active
profile in Data[1], no chunking. Documented in
doc/07_serial_protocol.md alongside why CONFIG_READ is unsuitable for
polling. CONFIG_READ stays as-is for actual full-dump use (e.g. "Vom
Board laden").

Verified on hardware after flashing via env:versapad_usb: READ_STATUS
returns the correct profile in ~well under CONFIG_READ's dump time,
Live-Sync no longer visibly disturbs LED animations.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 15:37:21 +02:00
boards Fix off-by-512-byte error in the app-side bootloader linker script 2026-08-05 22:30:03 +02:00
bootloader Guard env:versapad's upload against overwriting the bootloader 2026-08-05 23:27:02 +02:00
doc Add lightweight READ_STATUS command to avoid blocking LED updates during polling 2026-08-07 15:37:21 +02:00
src Add lightweight READ_STATUS command to avoid blocking LED updates during polling 2026-08-07 15:37:21 +02:00
variants/versapad Fix off-by-512-byte error in the app-side bootloader linker script 2026-08-05 22:30:03 +02:00
.gitignore Add end-to-end USB flashing for the app firmware via UF2 2026-08-05 21:35:19 +02:00
AGENTS.md Harden firmware state and transfer handling 2026-07-24 09:49:21 +02:00
platformio.ini Add end-to-end USB flashing for the app firmware via UF2 2026-08-05 21:35:19 +02:00
README.md Guard env:versapad's upload against overwriting the bootloader 2026-08-05 23:27:02 +02:00
uf2conv.py Add end-to-end USB flashing for the app firmware via UF2 2026-08-05 21:35:19 +02:00
upload_openocd.py Guard env:versapad's upload against overwriting the bootloader 2026-08-05 23:27:02 +02:00
upload_uf2.py Add end-to-end USB flashing for the app firmware via UF2 2026-08-05 21:35:19 +02:00

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