VersaMCU/doc/00_architecture.md
2026-03-30 19:52:37 +02:00

84 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# VersaMCU Architektur-Übersicht
## Ziel-Hardware
| Merkmal | Wert |
|---|---|
| MCU | ATSAMD21G17D (Cortex-M0+, 48 MHz) |
| Flash | 128 KB (davon 512 B am Ende für NVM-Config reserviert) |
| RAM | 16 KB |
| FPU | Keine alle Berechnungen in Integer-Arithmetik |
| USB | Native USB, DFLL48M via USB-SOF-Kalibrierung (`-DCRYSTALLESS`) |
| Framework | Arduino + PlatformIO, kein Bootloader (Direktflash via SWD/Atmel-ICE) |
## Loop-Ablauf
```
setup()
├── macro_config_load() Makro-Tabelle aus NVM in RAM laden
├── init_buttons() CButton-Objekte aus NVM initialisieren
├── usb_hid_init() HID-Descriptor (No-Op, läuft via global ctor)
├── usb_serial_init() CDC Serial öffnen
├── matrix_init(cb) 5×5-Matrix + Debounce-Zustand
└── encoder_init(cb) EIC-Interrupts für 4 Encoder
loop() [~20 ms Iteration]
├── matrix_scan() Debounce-Zustand prüfen → Events in Queue
├── poll_vendor() CDC-Pakete vom PC verarbeiten (LED-Cmds, Config, Makros)
├── processEvents() Queue leeren: Aktionen ausführen, HOST_COMMAND melden
└── updateLEDs() Dirty-CButtons → WS2812-Buffer → show() (nur wenn dirty)
```
Encoder-ISRs laufen asynchron (CHANGE-Interrupt auf A und B) und schreiben direkt in die Event-Queue. Die Queue ist interrupt-sicher (keine Locks nötig auf Single-Core-M0+).
## Datenfluss
```
HAL-Callbacks (matrix_cb, encoder_cb)
└─► CEventQueue (16 Slots, Ring-Buffer, kein Heap)
└─► processEvents()
├─► CButton.on_press() / on_release() [Hooks, aktuell leer]
├─► execute_action() → USB HID / Makro-Ablauf
└─► usb_serial_send() → HOST_COMMAND-Events an PC
SerialUSB (CDC, PC → Board)
└─► poll_vendor()
├─► CButton.set_override() / clear_override() / set_base()
└─► Config/Makro-Transfer (chunked, 6 B/Paket)
```
## Komponenten-Übersicht
| Datei | Verantwortung |
|---|---|
| `main.cpp` | `setup()` / `loop()` ruft nur CMainController auf |
| `CMainController` | Zentraler Orchestrator, hält alle CButton-Instanzen |
| `CButton` | LED-Layering, Animations-Engine, Action-Referenz |
| `CEventQueue` | ISR-sicherer Ring-Buffer, 16 Events |
| `hal/matrix` | 5×5-Matrix-Scan, 10 ms Debounce |
| `hal/encoder` | Quadratur-Dekodierung via EIC-ISR |
| `hal/ws2812` | Thin Wrapper um Adafruit NeoPixel (bit-bang) |
| `hal/usb_hid` | HID Keyboard + Consumer Control |
| `hal/usb_serial` | CDC bidirektional, 8-Byte-Pakete, Ring-Buffer |
| `config/nvm_config` | SDeviceConfig: laden, speichern, CRC16, Defaults |
| `config/macro_config` | SMacroTable: laden, speichern (NVM Row 1) |
| `config/action` | SAction-Struct + ActionType-Enum |
## Key-ID-Schema
```
key_id 03 : Encoder-SW-Buttons (COL_0 × ROW_03), kein LED
key_id 4 : nicht belegt (COL_0 × ROW_4)
key_id 524 : MX-Buttons (COL_14 × ROW_04), je ein WS2812-LED
```
LED-Index folgt serpentiner Verdrahtung: `LED_INDEX(col, row)`.
## Invarianten / Constraints
- **Kein Heap**: kein `new`/`malloc` alle Objekte statisch oder als Felder in CMainController.
- **Kein Float**: Cortex-M0+ hat keine FPU; Float würde per Software emuliert (~1020× langsamer).
- **Packed Structs**: `SAction` und `SDeviceConfig` sind `__attribute__((packed))` damit die Byte-Größen mit der C#-Serialisierung in VersaGUI übereinstimmen.
- **Aligned NVM-Writes**: `nvm_write_page` castet Pointer zu `uint32_t*`; Puffer müssen vor dem Aufruf in `__attribute__((aligned(4)))`-Variablen kopiert werden (sonst HardFault auf M0+).
- **DTR-Check**: `usb_serial_send()` prüft ob SerialUSB aktiv ist, bevor Bytes gesendet werden.