Added mcu recommendation and merged project-context content from earlier
This commit is contained in:
parent
9079fefad8
commit
d6ed7cb81f
224
README.md
224
README.md
@ -3,6 +3,44 @@
|
|||||||
Firmware für das VersaPad v2 Macro-Pad.
|
Firmware für das VersaPad v2 Macro-Pad.
|
||||||
Läuft auf einem **ATSAMD21G17D** (Cortex-M0+), entwickelt mit PlatformIO + Arduino-Framework.
|
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
|
## Voraussetzungen
|
||||||
|
|
||||||
- [PlatformIO](https://platformio.org/) (CLI oder VS Code Extension)
|
- [PlatformIO](https://platformio.org/) (CLI oder VS Code Extension)
|
||||||
@ -151,6 +189,51 @@ VersaMCU/
|
|||||||
|
|
||||||
## Architektur
|
## 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
|
### Loop-Ablauf
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -172,16 +255,37 @@ Aktive Farbe = `override` wenn aktiv, sonst `base`. `clear_override()` kehrt sof
|
|||||||
|
|
||||||
### LED-Animationen
|
### LED-Animationen
|
||||||
|
|
||||||
| Animation | Verhalten |
|
Animationen modulieren die Helligkeit oder Farbe der aktiven Schicht (base oder override). Alle Berechnungen in **Integer-Arithmetik** (Cortex-M0+ hat keine FPU).
|
||||||
|---|---|
|
|
||||||
| `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 |
|
|
||||||
|
|
||||||
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?**
|
**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 |
|
| `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 |
|
| 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 |
|
| 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.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user