From d6ed7cb81fab42f6f18b70e5be467e4ce94c0077 Mon Sep 17 00:00:00 2001 From: Julian Appel Date: Mon, 30 Mar 2026 19:53:34 +0200 Subject: [PATCH] Added mcu recommendation and merged project-context content from earlier --- README.md | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 215 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 840ef79..67d2ead 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,44 @@ Firmware für das VersaPad v2 Macro-Pad. Läuft auf einem **ATSAMD21G17D** (Cortex-M0+), entwickelt mit PlatformIO + Arduino-Framework. +## Hardware + +| Eigenschaft | Detail | +|---|---| +| MCU | ATSAMD21**G17D** (Cortex-M0+, 128 KB Flash, 16 KB RAM) | +| Taktfrequenz | 48 MHz (DFLL, intern – kein externer 32 kHz-Quarz) | +| Framework | Arduino SAMD Core 1.8.14, PlatformIO | +| Programmer | Atmel-ICE via SWD (kein Bootloader) | + +### Button-Matrix + +- **5×5-Matrix** (COL_0–4 × ROW_0–4) = 25 logische Keys +- **20 Cherry MX Switches** (COL_1–4 × ROW_0–4), je eine WS2812-LED +- **4 Encoder-SW-Buttons** (COL_0 × ROW_0–3), keine LEDs +- COL_0 × ROW_4 = nicht belegt +- **Dioden**: D4148 je Taste, Anode an Switch, Kathode an ROW → Ghost-Key-freies Scannen +- **Scan-Richtung**: ROW wird OUTPUT LOW getrieben, COL-Leitungen haben 10 kΩ-Pullup nach 3V3 (werden gelesen) + +### Rotary Encoder + +- 4× Encoder (ENC0 = USB-nah, ENC3 = USB-fern) +- Alle A/B-Leitungen auf EIC (PA16–PA23), Quadratur-Dekodierung via ISR + 4-State-Lookup +- Jeder Encoder hat drei Aktionen: **CW**, **CCW**, **SW** (alle aus NVM konfigurierbar) + +### LEDs (WS2812) + +- 20× WS2812B, serpentinen-verdrahtet (Reihe 0: L→R, Reihe 1: R→L, …) +- Datenleitung: **PB22 (D18)**, bit-bang via Adafruit NeoPixel Library +- **LED_INDEX-Formel**: `row * 4 + ((row & 1) ? (4 - col) : (col - 1))` +- **Pegelproblematik**: WS2812 sind 5V-Devices (HIGH-Schwelle ~3,5 V), SAMD21 liefert 3,3 V ohne Level-Shifter. LED 0 empfängt einen marginal gültigen Pegel; ab LED 1 regeneriert jede LED intern auf 5 V → alle weiteren problemlos. Fix nächste PCB-Revision: Level-Shifter oder Diode in der VDD-Leitung. + +### Fader (ADC) + +- 3× Linearpotentiometer: PA02 (A0), PA03 (A1, auch VREFA), PB08 (A2) +- Noch nicht implementiert (siehe Roadmap) + +--- + ## Voraussetzungen - [PlatformIO](https://platformio.org/) (CLI oder VS Code Extension) @@ -151,6 +189,51 @@ VersaMCU/ ## Architektur +### Schichten + +``` +┌────────────────────────────────────────────────┐ +│ main.cpp │ +│ CMainController (setup / work) │ +├────────────────────────────────────────────────┤ +│ Modell │ +│ CButton (LED 2-Layer, Action, dirty-Flag) │ +│ CEventQueue (Ring-Buffer FIFO, 16 Slots) │ +├────────────────────────────────────────────────┤ +│ HAL │ +│ hal/matrix – 5×5-Scan, 10 ms Debounce │ +│ hal/encoder – Quadratur via EIC-ISR │ +│ hal/ws2812 – Adafruit NeoPixel bit-bang │ +│ hal/usb_hid – HID Keyboard + Consumer │ +│ hal/usb_serial– CDC Serial bidirektional │ +├────────────────────────────────────────────────┤ +│ Config │ +│ config/pins.h – Pin-Mapping │ +│ config/action.h – ActionType + SAction │ +│ config/nvm_config – Flash R/W, CRC16 │ +└────────────────────────────────────────────────┘ +``` + +### Datenfluss + +``` +HAL (matrix_scan, Encoder-ISR) + └─► matrix_cb / encoder_cb + └─► CEventQueue.push() + └─► CMainController.processEvents() + ├─► CButton.on_press() / on_release() + ├─► execute_action() → usb_hid_send_key / send_consumer + └─► usb_serial_send() (nur bei HOST_COMMAND) + +SerialUSB (PC → Board, 8-Byte-Pakete) + └─► CMainController.poll_vendor() + └─► CButton.set_override() / set_base() / clear_override() + +CMainController.updateLEDs() + └─► CButton.render_led() → ws2812_set() + └─► ws2812_show() (nur wenn dirty) +``` + ### Loop-Ablauf ``` @@ -172,16 +255,37 @@ Aktive Farbe = `override` wenn aktiv, sonst `base`. `clear_override()` kehrt sof ### LED-Animationen -| Animation | Verhalten | -|---|---| -| `STATIC` | Feste Farbe | -| `BLINK` | Binäres An/Aus | -| `PULSE` | Lineares Dreieck 0→255→0 | -| `FADE_IN / FADE_OUT` | Einmaliges Ein-/Ausblenden | -| `COLOR_CYCLE` | Hue-Sweep (Regenbogen), ignoriert base/override | -| `COLOR_FADE` | Crossfade zu Zielfarbe | +Animationen modulieren die Helligkeit oder Farbe der aktiven Schicht (base oder override). Alle Berechnungen in **Integer-Arithmetik** (Cortex-M0+ hat keine FPU). -Alle Berechnungen in Integer-Arithmetik (kein FPU auf Cortex-M0+). +| Animation | Typ | Verhalten | `period_ms`-Semantik | +|---|---|---|---| +| `STATIC` | – | Feste Helligkeit (Standardzustand) | – | +| `BLINK` | Helligkeit | Binäres An/Aus, endlos | Halbperiode (An = Aus) | +| `PULSE` | Helligkeit | Lineares Dreieck 0→255→0, endlos | Vollperiode | +| `FADE_IN` | Helligkeit | Einmalig: schwarz → voll, dann STATIC | Dauer | +| `FADE_OUT` | Helligkeit | Einmalig: voll → schwarz, dann STATIC + base=schwarz | Dauer | +| `COLOR_CYCLE` | Farbe | Hue-Sweep Regenbogen, endlos, ignoriert base/override | Eine volle Runde | +| `COLOR_FADE` | Farbe | Einmalig: Crossfade akt. Farbe → Zielfarbe, dann STATIC + base=Ziel | Dauer | + +**API:** + +```cpp +set_anim(LEDAnim, period_ms, phase_offset_ms = 0) +// Für alle Typen außer COLOR_FADE. +// phase_offset_ms verschiebt den Startpunkt in die Vergangenheit → +// mehrere LEDs versetzt starten (z. B. Regenbogen-Welle). + +set_color_fade(RGB to, period_ms) +// Startet COLOR_FADE von aktueller Farbe zu `to`. + +clear_anim() +// Sofort zurück zu STATIC (volle Helligkeit). + +render_led() +// Gibt true zurück solange dirty oder Animation läuft → ws2812_show() nötig. +``` + +**Idle-Zustand:** Alle 20 MX-LEDs laufen mit `COLOR_CYCLE` (4 s/Runde, 40 % Helligkeit). Der Phasenversatz ist gleichmäßig über alle 20 LEDs verteilt, sodass immer ein vollständiger Regenbogen auf dem Pad liegt. **Warum Bit-Bang statt DMA?** @@ -271,3 +375,105 @@ Via Linkerscript reserviert. Bei ungültigem Magic/Version/CRC werden Defaults g | `ws2812_show()` blockiert ~600 µs | Dirty-Flag-Pattern: nur aufrufen wenn nötig, nie aus ISR | | SAction muss `__attribute__((packed))` haben | Ohne packed: 4B statt 3B → CRC-Mismatch beim Config-Laden | | Windows HID-Descriptor-Cache | Bei PID-Änderung Board neu einstecken | +| `SERCOM5 CTRLB.RXEN` Sync-Bug | `while(SYNCBUSY.bit.CTRLB)` hängt vor ENABLE → nur relevant bei manueller SERCOM5-Konfiguration; nicht im Normalbetrieb | +| `PluggableUSBModule` nicht nutzbar | `USB_SendControl` / `USB_RecvControl` nicht verlinkt in dieser Core-Version → CDC Serial statt Vendor HID für PC-Kommunikation verwenden | +| HID-Descriptor vor USB-Enumeration registrieren | Registrierung via globalem Konstruktor (läuft vor `main()`), nicht in `setup()` | + +--- + +## Next-Generation Hardware – MCU-Empfehlung + +### Warum der SAMD21G17D an seine Grenzen stößt + +| Einschränkung | Auswirkung auf geplante Features | +|---|---| +| **128 KB Flash** | Mehrere Profile + lange Makros + OLED-Fonts füllen den Speicher vollständig | +| **16 KB RAM** | OLED-Framebuffer (128×64 px = 1 KB) + Profil-Puffer + Makro-Tabellen + Stack = kaum Luft | +| **Kein FPU** | LED-Animationen erfordern Integer-Arithmetik-Workarounds; aufwändigere Effekte unwirtschaftlich | +| **Kein Ethernet-MAC** | Ethernet nur via langsamen SPI-Chip möglich | +| **Kein USB High-Speed** | CDC bleibt auf 12 Mbit/s (Full Speed); für schnelle Konfigurationsübertragungen ausreichend, aber kein Spielraum | +| **WS2812 bit-bang blockiert 600 µs** | Mit mehr LEDs oder höherer Auflösung kritisch; kein DMA ohne SERCOM-Umbau | + +--- + +### Empfehlung: Microchip SAME54P20A + +**Primäre Empfehlung** – selber Hersteller, gleicher Toolchain-Stack, deutlich mehr Reserven. + +| Merkmal | SAMD21G17D (aktuell) | SAME54P20A (empfohlen) | +|---|---|---| +| Kern | Cortex-M0+, 48 MHz | Cortex-M4F, 120 MHz | +| **FPU** | ✗ | ✓ (single-precision) | +| **Flash** | 128 KB | **1 MB** | +| **RAM** | 16 KB | **256 KB** | +| **USB** | Full Speed (12 Mbit/s) | Full Speed + optionaler HS-PHY | +| **Ethernet MAC** | ✗ | ✓ (IEEE 802.3, braucht ext. PHY) | +| **DMA** | 12 Kanäle | 32 Kanäle | +| SERCOM | 6 | 8 | +| NVM (intern) | 128 KB | 1 MB (kein ext. Flash nötig) | +| Preis (LCSC ca.) | ~2 € | ~8–10 € | + +**Warum SAME54?** +- Direkter Upgrade-Pfad: Arduino-Framework, PlatformIO, gleiche HAL-Konzepte +- Ethernet-MAC integriert → nur externer PHY nötig (z.B. **KSZ8081** oder **LAN8720A**, ~1–2 €) +- 1 MB Flash reicht für viele Profile, lange Makros und OLED-Font-Tabellen ohne externen Flash +- 256 KB RAM: OLED-Framebuffer, Profil-Puffer und komplexe Makro-Engines kein Problem +- FPU: sauberere LED-Animationen, kein Integer-Workaround mehr nötig +- DMA: WS2812 via SERCOM-SPI + DMA möglich → kein Bit-Bang, keine Interrupt-Sperre + +--- + +### Alternative: Raspberry Pi RP2350 + +Falls Ethernet nicht zwingend auf dem MCU selbst integriert sein muss (z.B. W5500 via SPI): + +| Merkmal | RP2350 | +|---|---| +| Kern | Dual Cortex-M33 oder RISC-V, 150 MHz | +| FPU | ✓ | +| RAM | **520 KB** SRAM | +| Flash | Kein interner; ext. QSPI (typ. 2–16 MB) | +| USB | Full Speed (Device + Host) | +| Ethernet MAC | ✗ (W5500 via SPI, ~3 €) | +| PIO | 3 × 4 PIO-Blöcke → WS2812 hardwareseitig ohne CPU | +| Preis | ~1,50 € | + +**Vorteil:** PIO-Blöcke übernehmen WS2812-Timing hardwareseitig (kein bit-bang, kein DMA-Setup). Sehr viel RAM für komplexe Logik. Günstiger als SAME54. + +**Nachteil:** Kein integrierter Ethernet-MAC. W5500 übernimmt TCP/IP-Stack per SPI (ausreichend für einfaches HTTP/Telnet-Protokoll), ist aber kein vollwertiger Network-Stack. + +--- + +### System-Architektur für PoE-Betrieb + +PoE erfordert unabhängig vom MCU zusätzliche Hardware: + +``` +RJ45-Buchse (mit integrierten Magnetics) + └─► PoE-PD-Controller (z.B. TPS2372-4, AG9800) + ├─► DC/DC-Wandler → 3.3V / 5V Versorgung des Boards + └─► Ethernet-Signal → MCU-Ethernet-MAC → ext. PHY (LAN8720A / KSZ8081) +``` + +Der PoE-PD-Controller ist zwingend: Er verhandelt mit dem PoE-Switch (IEEE 802.3af/at), isoliert galvanisch und liefert geregelte Spannung. Typische PoE-Leistungsklasse 0 (15,4 W) reicht für MCU + LEDs + Display mehrfach aus. + +**Empfohlene ICs:** + +| Funktion | IC | Preis ca. | +|---|---|---| +| PoE PD Controller | AG9800 oder TPS2372-4 | 1–3 € | +| Ethernet PHY | LAN8720A oder KSZ8081 | 1–2 € | +| QSPI-Flash (falls RP2350) | W25Q128 (16 MB) | ~0,80 € | +| OLED Controller | SSD1306 (128×64, I2C/SPI) | im Modul enthalten | + +--- + +### Empfehlung nach Szenario + +| Szenario | Empfehlung | +|---|---| +| Voller Feature-Umfang (Ethernet-MAC, PoE, Profile, OLED) | **SAME54P20A** + LAN8720A + PoE-PD | +| Maximale RAM/Flash-Reserve, WS2812 ohne CPU-Last | **RP2350** + W5500 + PoE-PD | +| Minimaler Footprint, kein Ethernet | **RP2040** (günstiger als RP2350, 264 KB RAM reicht für OLED + Profile) | + +Für VersaPad v3 mit allen genannten Features ist der **SAME54P20A** die solideste Wahl: gleicher Hersteller, etablierter Toolchain, integrierter Ethernet-MAC, und der Firmware-Code von v2 (HAL-Struktur, Event-Queue, CButton-Modell) ist weitgehend übertragbar.