Webseiten-Werkzeuge


weitere_hardware:nesso_n1

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
weitere_hardware:nesso_n1 [18.04.2026 19:24] mellinuxweitere_hardware:nesso_n1 [21.04.2026 14:55] (aktuell) mellinux
Zeile 1: Zeile 1:
 **HINWEIS:** Befindet sich in der Testphase! **HINWEIS:** Befindet sich in der Testphase!
 +
 +**HINWEIS:** team-nessoN1-meshcore muss aus Gesundheitlichen Gründen Pausieren. Wer mag kann Ihn wegen Details der Projektübergabe unter E-Mail --- //[[@team-nessoN1-meshcore@posteo.de@|team-nessoN1-meshcore]]// kontaktieren.
  
 ====== MeshCore — Arduino Nesso N1 (ESP32-C6) ====== ====== MeshCore — Arduino Nesso N1 (ESP32-C6) ======
  
-**Author:** team-nessoN1-meshcore — team-nessoN1-meshcore@posteo.de  +**Autor:** team-nessoN1-meshcore — team-nessoN1-meshcore@posteo.de\\
 **Stand:** April 2026 **Stand:** April 2026
  
-Dieses Verzeichnis enthält die Hardware-Abstraktionsschicht (HAL) für den +Diese Seite beschreibt die Hardware-Abstraktionsschicht (HAL) für den **Arduino Nesso N1** als MeshCore-Zielplattform. Das Board wurde gemeinsam von Arduino und M5Stack entwickelt und kombiniert einen ESP32-C6 Mikrocontroller mit einem SX1262 LoRa-Transceiver, Wi-Fi 6, Bluetooth 5.3, Thread/Zigbee und einem 1,14″-Touchscreen in einem kompakten, batteriebetriebenen Gehäuse.
-**Arduino Nesso N1** als MeshCore-Zielplattform. Das Board wurde gemeinsam +
-von Arduino und M5Stack entwickelt und kombiniert einen ESP32-C6 Mikrocontroller +
-mit einem SX1262 LoRa-Transceiver, Wi-Fi 6, Bluetooth 5.3, Thread/Zigbee und +
-einem 1,14″-Touchscreen in einem kompakten, batteriebetriebenen Gehäuse. +
- +
-===== Aktueller Status April 2026: ===== +
- +
-Die Migration läuft (Repeater, Companion). Umfangreiche Tests stehen an. Das  +
-eigentliche Produkt Nesso N1 ist jung und hat einige Fehler in der Doku. +
-Der Source wurden noch nicht veröffentlicht, weil Alpha Versionstatus. +
- +
-----+
  
 ===== Hardware-Überblick ===== ===== Hardware-Überblick =====
  
-Komponente Details +Komponente Details ^
-|---|---|+
 | MCU | Espressif ESP32-C6 (RISC-V, 160 MHz) | | MCU | Espressif ESP32-C6 (RISC-V, 160 MHz) |
 | Flash | 16 MB | | Flash | 16 MB |
Zeile 34: Zeile 23:
 | Akku | 250 mAh LiPo, USB-C Laden | | Akku | 250 mAh LiPo, USB-C Laden |
 | Konnektivität | Wi-Fi 6, BT 5.3, Thread/Zigbee (802.15.4), LoRa | | Konnektivität | Wi-Fi 6, BT 5.3, Thread/Zigbee (802.15.4), LoRa |
- 
----- 
  
 ===== Besonderheiten dieser Portierung ===== ===== Besonderheiten dieser Portierung =====
Zeile 41: Zeile 28:
 ==== SX1262 Reset und RF-Switch über I²C-Expander ==== ==== SX1262 Reset und RF-Switch über I²C-Expander ====
  
-Anders als bei den meisten anderen MeshCore-Zielplattformen sind beim Nesso N1 +Anders als bei den meisten anderen MeshCore-Zielplattformen sind beim Nesso N1 die LoRa-Steuerleitungen **nicht direkt** mit GPIO-Pins des ESP32-C6 verbunden, sondern laufen über einen **PI4IOE5V6408 I²C-GPIO-Expander** (Adresse 0x43):
-die LoRa-Steuerleitungen **nicht direkt** mit GPIO-Pins des ESP32-C6 verbunden, +
-sondern laufen über einen **PI4IOE5V6408 I²C-GPIO-Expander** (Adresse 0x43):+
  
-Signal Expander-Pin Funktion +Signal Expander-Pin Funktion ^
-|---|---|---|+
 | SX_NRST | P7 | Hardware-Reset des SX1262 | | SX_NRST | P7 | Hardware-Reset des SX1262 |
 | SX_ANT_SW | P6 | Antennen-RF-Schalter | | SX_ANT_SW | P6 | Antennen-RF-Schalter |
Zeile 53: Zeile 37:
 | KEY2 | P1 | Taste B (Input) | | KEY2 | P1 | Taste B (Input) |
  
-Konsequenz: RadioLib's ''setRfSwitchTable()'' funktioniert nicht (nur direkte GPIOs). +Konsequenz: RadioLib's ''setRfSwitchTable()'' funktioniert nicht (nur direkte GPIOs). ''NessoN1Board'' implementiert stattdessen das ''RfSwitchCallback''-Interface, das ''CustomSX1262Wrapper'' bei jedem TX/RX-Übergang aufruft.
-''NessoN1Board'' implementiert stattdessen das ''RfSwitchCallback''-Interface, +
-das ''CustomSX1262Wrapper'' bei jedem TX/RX-Übergang aufruft.+
  
 ==== Geteilter SPI-Bus (SX1262 + ST7789) ==== ==== Geteilter SPI-Bus (SX1262 + ST7789) ====
  
-Signal GPIO +Signal GPIO ^
-|---|---|+
 | MOSI | G21 | | MOSI | G21 |
 | MISO | G22 | | MISO | G22 |
Zeile 68: Zeile 49:
 | LCD DC | G16 | | LCD DC | G16 |
  
-''lora_spi.begin()'' wird **ohne NSS-Argument** aufgerufen. Mit NSS würde +''lora_spi.begin()'' wird **ohne NSS-Argument** aufgerufen. Mit NSS würde Arduino einen APB-Hardware-CS-Callback für GPIO23 registrieren; M5GFX tut dasselbe für GPIO17 — zwei Callbacks auf demselben Bus führen zu ''addApbChangeCallback: duplicate'' und SPI-Korruption.
-Arduino einen APB-Hardware-CS-Callback für GPIO23 registrieren; M5GFX tut +
-dasselbe für GPIO17 — zwei Callbacks auf demselben Bus führen zu +
-''addApbChangeCallback: duplicate'' und SPI-Korruption.+
  
 ==== FSPI statt Default-SPI ==== ==== FSPI statt Default-SPI ====
Zeile 79: Zeile 57:
 ==== USB-CDC und BLE schließen sich aus ==== ==== USB-CDC und BLE schließen sich aus ====
  
-Firmware ''ARDUINO_USB_CDC_ON_BOOT'' Debug-Output +Firmware ''ARDUINO_USB_CDC_ON_BOOT'' Debug-Output ^
-|---|---|---|+
 | Repeater | ''1'' | USB-Serial aktiv | | Repeater | ''1'' | USB-Serial aktiv |
 | Companion BLE | ''0'' | kein USB-Serial | | Companion BLE | ''0'' | kein USB-Serial |
 | Companion WiFi | ''0'' | kein USB-Serial | | Companion WiFi | ''0'' | kein USB-Serial |
- 
----- 
  
 ===== Display-Architektur ===== ===== Display-Architektur =====
Zeile 91: Zeile 66:
 ==== Auflösung und UITask-Layoutprüfung ==== ==== Auflösung und UITask-Layoutprüfung ====
  
-Das ST7789P3 hat **240×135 Pixel** (Landscape, ''setRotation(1)''). +Das ST7789P3 hat **240×135 Pixel** (Landscape, ''setRotation(1)''). Alle UITask-Standardlayouts passen ohne Überlauf:
-Alle UITask-Standardlayouts passen ohne Überlauf:+
  
-Element Breite x (zentriert) Rechte Kante Passt +Element Breite x (zentriert) Rechte Kante Passt ^
-|---|---|---|---|---|+
 | MeshCore-Logo (64×36 px XBM) | 64 px | 88 | 152 | ✅ | | MeshCore-Logo (64×36 px XBM) | 64 px | 88 | 152 | ✅ |
 | Versionszeile (setTextSize 2) | 156 px | 42 | 198 | ✅ | | Versionszeile (setTextSize 2) | 156 px | 42 | 198 | ✅ |
Zeile 112: Zeile 85:
   4. display.begin()         M5GFX Lazy Construction — zwingend nach std_init!   4. display.begin()         M5GFX Lazy Construction — zwingend nach std_init!
 </code> </code>
- 
----- 
  
 ===== Bekannte Probleme und ihre Fixes ===== ===== Bekannte Probleme und ihre Fixes =====
Zeile 119: Zeile 90:
 ==== Fix 1 — Display schwarz nach wenigen Sekunden ==== ==== Fix 1 — Display schwarz nach wenigen Sekunden ====
  
-**Datum:** April 2026  +**Datum:** April 2026\\
 **Betroffene Datei:** ''platformio.ini'', ''[env:NessoN1_repeater_display]'' **Betroffene Datei:** ''platformio.ini'', ''[env:NessoN1_repeater_display]''
  
-**Symptom:** Display zeigt Boot-Screen (~4 Sek.) und Home-Screen (~10 Sek.), +**Symptom:** Display zeigt Boot-Screen (~4 Sek.) und Home-Screen (~10 Sek.), dann dauerhaft schwarz. Kein Wakeup durch Tastendruck.
-dann dauerhaft schwarz. Kein Wakeup durch Tastendruck.+
  
-**Ursache — präzise:** +**Ursache:** ''UITask.h'' (MeshCore, ''examples/simple_repeater/UITask.h'') definiert den Makro ''SCREEN_TIMEOUT'' (Standardwert: 10 000 ms). Nach Ablauf wird intern ''display.turnOff()'' aufgerufen. Der Wakeup-Pfad in UITask prüft ''PIN_USER_BTN'' — einen direkten GPIO-Pin. Auf dem Nesso N1 hängen KEY1 und KEY2 **über I²C-Expander 0** (Adresse 0x43, Pins P0/P1). UITask hat damit **keinen Wakeup-Mechanismus** — das Display bleibt nach Timeout-Ablauf permanent schwarz.
-''UITask.h'' (MeshCore, ''examples/simple_repeater/UITask.h'') definiert den +
-Makro ''SCREEN_TIMEOUT'' (Standardwert: 10 000 ms). Nach Ablauf wird intern +
-''display.turnOff()'' aufgerufen. Der Wakeup-Pfad in UITask prüft ''PIN_USER_BTN'' +
-— einen direkten GPIO-Pin der bei einem Tastendruck HIGH wird. Auf dem Nesso N1 +
-hängen KEY1 und KEY2 **über I²C-Expander 0** (Adresse 0x43, Pins P0/P1)+
-Ein direkter GPIO als ''PIN_USER_BTN'' steht nicht zur Verfügung. UITask hat +
-damit **keinen Wakeup-Mechanismus** — das Display bleibt nach Timeout-Ablauf +
-permanent schwarz.+
  
 **Fix:** **Fix:**
-<code>ini+<code ini>
 ; platformio.ini — [env:NessoN1_repeater_display]: ; platformio.ini — [env:NessoN1_repeater_display]:
 -D SCREEN_TIMEOUT=0 -D SCREEN_TIMEOUT=0
 -D DISPLAY_TIMEOUT=0 -D DISPLAY_TIMEOUT=0
 </code> </code>
-Beide Flags auf 0 deaktivieren den Timeout vollständig. ''DISPLAY_TIMEOUT'' 
-wird zusätzlich gesetzt weil verschiedene UITask-Versionen im MeshCore-Repository 
-unterschiedliche Makronamen verwenden. 
  
-**Hinweis Akku-Betrieb:** Sinnvoller Wert z.B. ''-D SCREEN_TIMEOUT=30000''+Beide Flags auf 0 deaktivieren den Timeout vollständig. ''DISPLAY_TIMEOUT'' wird zusätzlich gesetztweil verschiedene UITask-Versionen unterschiedliche Makronamen verwenden.
-Der Button-Wakeup ist über ''nesso_ui_tick()'' bereits integriert (siehe Fix 7). +
- +
----- +
- +
-==== Fix 7 — Tasten ohne Funktion im Repeater-Display-Modus ==== +
- +
-**Datum:** April 2026   +
-**Betroffene Dateien:** ''simple_repeater/main.cpp'', ''simple_repeater/UITask.h'', +
-''simple_repeater/UITask.cpp'', ''simple_repeater/MyMesh.h'' +
- +
-**Symptom:** KEY1 und KEY2 reagieren scheinbar nicht. Im Serial-Log erscheint +
-''[ui] KEY1 erkannt'' — die Taste wird erkanntaber es passiert nichts am Display. +
- +
-**Ursache — präzise:**   +
-''nesso_ui_tick()'' gibt bei erkannter Taste ''-1'' (KEY1) oder ''-2'' (KEY2) zurück, +
-wenn das Display bereits an ist. In ''main.cpp'' war die Auswertung dieser Werte +
-vollständig **auskommentiert**. Zusätzlich hatte ''UITask'' keine navigierbaren +
-Screens und keine Verbindung zu ''MyMesh'', um Nachbardaten oder einen +
-Discover-Request abrufen zu können. +
- +
-**Fix — drei Ebenen:** +
- +
-1. **Neues Interface ''UIActions.h''** — entkoppelt UITask von MyMesh: +
-<code>cpp +
-class UIActions { +
-public: +
-  virtual void uiGetNeighborList(char* buf, int bufSize) = 0; +
-  virtual void uiSendDiscover() = 0; +
-}; +
-</code> +
- +
-2. **''MyMesh'' implementiert ''UIActions''** — in ''MyMesh.h'': +
-<code>cpp +
-class MyMesh : public mesh::Mesh, public CommonCLICallbacks, public UIActions { +
-  ... +
-  void uiGetNeighborList(char* buf, int bufSize) override { formatNeighborsReply(buf);+
-  void uiSendDiscover() override { sendNodeDiscoverReq();+
-}; +
-</code> +
- +
-3. **''UITask'' bekommt 3 Screens + Navigation**, verbunden via ''setActions()'': +
-<code> +
-SCREEN_HOME       — Node-Name, Frequenz, SF/BW/CR +
-SCREEN_NEIGHBOURS — Nachbarliste (HEX-ID, Alter, SNR) +
-SCREEN_POLL_SENT  — Feedback "Poll gesendet" für 2 Sek. +
-</code> +
- +
-4. **''main.cpp'' wertet ''btn'' aus** (vorher auskommentiert): +
-<code>cpp +
-if (btn == -1) ui_task.nextScreen();   // KEY1: vorwärts / Poll +
-if (btn == -2) ui_task.prevScreen();   // KEY2: zurück +
-</code> +
- +
-**Bedienung nach dem Patch:** +
- +
-| Taste | Display AUS | Display AN (Home) | Display AN (Nachbarn) | +
-|-------|-------------|-------------------|-----------------------| +
-| KEY1 | Wakeup | → Nachbarn-Screen | → Poll senden | +
-| KEY2 | Wakeup | bleibt Home | → Home-Screen | +
- +
-Nach dem Poll zeigt der Screen 2 Sekunden "Poll gesendet", +
-dann wechselt er automatisch zurück zur (aktualisierten) Nachbarliste. +
- +
----- +
- +
-==== Fix 8 — Tasten nicht erkannt: Wire-Konflikt zwischen M5GFX und Expander-Treiber ==== +
- +
-**Datum:** April 2026   +
-**Betroffene Dateien:** ''NessoDisplayDriver.cpp'', ''NessoDisplayDriver.h'', ''platformio.ini'' +
- +
-**Symptom:** KEY1 und KEY2 werden trotz korrekter Flanken-Erkennung und Boot-Sperre +
-nicht oder unzuverlässig registriert. Im Serial-Log erscheinen: +
-<code> +
-[E][Wire.cpp:131] setPins(): bus already initialized. change pins only when not. +
-[E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=... +
-</code> +
- +
-**Ursache — präzise:**   +
-M5GFX initialisiert den I²C-Bus intern über ''WireInternal.begin(SDA, SCL)''+
-Der eigene ''PI4IOE5V6408''-Treiber in ''NessoN1Board'' initialisiert ''Wire'' ebenfalls +
-direkt. Beide greifen auf **denselben Bus** (SDA=GPIO10, SCL=GPIO8) zu — +
-mit unterschiedlichen ''TwoWire''-Instanzen. Das führt zu Bus-Kollisionen und +
-instabilen Expander-Reads. Dokumentiert im Arduino-Forum (November 2025): +
-https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099 +
- +
-**Fix:**   +
-''M5Unified'' übernimmt Button-Handling und Display-Init koordiniert. +
-''M5.begin()'' initialisiert Wire, M5GFX und GPIO-Expander in der richtigen +
-Reihenfolge — kein Wire-Konflikt mehr. +
- +
-<code>cpp +
-// NessoDisplayDriver.cpp — begin(): +
-M5.begin(cfg);              // statt: _gfx->begin() +
-_gfx = &M5.Display;        // statt: static M5GFX gfx_instance +
- +
-// checkButtons(): +
-M5.update(); +
-if (M5.BtnA.wasPressed()) return 1;  // KEY1 +
-if (M5.BtnB.wasPressed()) return 2;  // KEY2 +
-</code> +
- +
-<code>ini +
-; platformio.ini — nesso_n1_base: +
-lib_deps = +
-  m5stack/M5GFX +
-  m5stack/M5Unified   ; NEU: Fix 8 +
-</code>+
  
-Entfernt: ''_prevBtnState''''_btnReadyAt'', ''_lastBtnCheck'' (manueller +> **Hinweis Akku-Betrieb:** Sinnvoller Wert z.B. ''-D SCREEN_TIMEOUT=30000''. Der Button-Wakeup ist über ''nesso_ui_tick()'' bereits integriert (siehe Fix 7).
-Debounce entfällt — M5Unified macht Flanken-Erkennung intern).+
  
 ==== Fix 2 — Display im Portrait-Modus (135×240 statt 240×135) ==== ==== Fix 2 — Display im Portrait-Modus (135×240 statt 240×135) ====
  
-**Datum:** April 2026  +**Datum:** April 2026\\
 **Betroffene Datei:** ''NessoDisplayDriver.cpp'' **Betroffene Datei:** ''NessoDisplayDriver.cpp''
  
-**Symptom:** Serial meldet ''M5GFX meldet Display: 135 x 240 px''. +**Symptom:** Serial meldet ''M5GFX meldet Display: 135 x 240 px''. UITask-Texte werden mit negativem x-Offset abgeschnitten und sind nicht lesbar.
-UITask-Texte werden mit negativem x-Offset abgeschnitten und sind nicht +
-lesbar (Versionszeile bei x=−11, Node-Name bei x=−29).+
  
-**Ursache — präzise:** +**Ursache:** ''setRotation(1)'' wurde in ''begin()'' **nach** ''_gfx->width()'' / ''_gfx->height()'' aufgerufen. M5GFX tauscht die Dimensionen erst nach ''setRotation()'' intern um. Zusätzlich trat das Problem aufwenn ''display.begin()'' in ''main.cpp'' vor ''radio_init()'' aufgerufen wurde: Der idempotente Guard beim zweiten ''begin()''-Aufruf hat ''setRotation(1)'' dann gar nicht mehr ausgeführt.
-''setRotation(1)'' wurde in ''begin()'' **nach** ''_gfx->width()'' / ''_gfx->height()'' +
-aufgerufen. M5GFX tauscht die Dimensionen erst nach ''setRotation()'' intern um. +
-Die Abfrage vor ''setRotation()'' lieferte daher immer die Portrait-Werte 135×240. +
-Zusätzlich trat das Problem auf wenn ''display.begin()'' in ''main.cpp'' vor +
-''radio_init()'' aufgerufen wurde: Der idempotente Guard beim zweiten ''begin()''-Aufruf +
-aus ''radio_init()'' hat ''setRotation(1)'' dann gar nicht mehr ausgeführt — der +
-Controller lief weiter im Portrait-Modus obwohl ''DisplayDriver(240, 135)'' +
-im Konstruktor richtig gesetzt war.+
  
 **Fix in ''NessoDisplayDriver.cpp'':** **Fix in ''NessoDisplayDriver.cpp'':**
-<code>cpp+<code cpp>
 // setRotation ZUERST — M5GFX tauscht Dimensionen erst danach: // setRotation ZUERST — M5GFX tauscht Dimensionen erst danach:
 _gfx->setRotation(1); _gfx->setRotation(1);
Zeile 284: Zeile 125:
 // Ausgabe: 240 x 135 px ✓ // Ausgabe: 240 x 135 px ✓
 </code> </code>
- 
----- 
  
 ==== Fix 3 — ''radio init failed: -2'' durch doppelten board.begin()-Aufruf ==== ==== Fix 3 — ''radio init failed: -2'' durch doppelten board.begin()-Aufruf ====
  
-**Datum:** April 2026  +**Datum:** April 2026\\
 **Betroffene Datei:** ''NessoN1Board.cpp'' **Betroffene Datei:** ''NessoN1Board.cpp''
  
 **Symptom:** ''ERROR: radio init failed: -2'', Serial zeigt ''[loraReset] TIMEOUT!''. **Symptom:** ''ERROR: radio init failed: -2'', Serial zeigt ''[loraReset] TIMEOUT!''.
  
-**Ursache — präzise:** +**Ursache:** ''examples/simple_repeater/main.cpp'' ruft unter ''#ifdef DISPLAY_CLASS'' in ''setup()'' explizit ''board.begin()'' auf — **vor** ''radio_init()''. Auf dem Nesso N1 führt ''board.begin()'' intern ''loraReset()'' aus: der SX1262 bootet, BUSY geht HIGH. Anschließend ruft ''radio_init()'' erneut ''board.begin()'' auf → zweites ''loraReset()'' → SX1262 bootet erneut, BUSY wieder HIGH → ''radio.std_init()'' trifft Chip mitten im Bootvorgang → ''RADIOLIB_ERR_CHIP_NOT_FOUND'' = ''-2''.
-''examples/simple_repeater/main.cpp'' (MeshCore-eigener Code) ruft unter +
-''#ifdef DISPLAY_CLASS'' in ''setup()'' explizit ''board.begin()'' auf — **vor** +
-''radio_init()''. Das generische MeshCore-Muster funktioniert auf anderen Boards +
-problemlos, weil dort Board-Init und Radio-Init unabhängig sind. Auf dem Nesso N1 +
-führt ''board.begin()'' intern ''loraReset()'' aus: der SX1262 bootet, BUSY geht HIGH. +
-Anschließend ruft ''radio_init()'' erneut ''board.begin()'' auf → zweites ''loraReset()'' +
-SX1262 bootet erneut, BUSY wieder HIGH → ''radio.std_init()'' trifft Chip mitten im +
-Bootvorgang → ''RADIOLIB_ERR_CHIP_NOT_FOUND'' = ''-2''.+
  
 **Fix in ''NessoN1Board::begin()'':** **Fix in ''NessoN1Board::begin()'':**
-<code>cpp+<code cpp>
 static bool s_boardBeginCalled = false; static bool s_boardBeginCalled = false;
 if (s_boardBeginCalled) { if (s_boardBeginCalled) {
Zeile 313: Zeile 144:
 s_boardBeginCalled = true; s_boardBeginCalled = true;
 </code> </code>
-Der Guard stellt sicher dass ''loraReset()'' und ''lora_spi.begin()'' genau einmal 
-laufen, unabhängig von der Aufruf-Reihenfolge in ''main.cpp''. 
  
-**Vollständige Lösung:** In ''main.cpp'' ''board.begin()'' und ''display.begin()'' +**Vollständige Lösung:** In ''main.cpp'' ''board.begin()'' und ''display.begin()'' aus ''setup()'' entfernen — beide werden intern durch ''radio_init()'' erledigt (siehe ''main_cpp_setup_hinweis.txt'').
-aus ''setup()'' entfernen — beide werden intern durch ''radio_init()'' erledigt+
-Da ''main.cpp'' MeshCore-eigener Code ist, ist der Guard die robustere Variante +
-ohne Repository-Fork. Hinweis: ''main_cpp_setup_hinweis.txt''. +
- +
-----+
  
 ==== Fix 4 — APB-Callback-Duplikat und Wire.setPins-Warnung ==== ==== Fix 4 — APB-Callback-Duplikat und Wire.setPins-Warnung ====
  
-**Datum:** April 2026  +**Datum:** April 2026\\
 **Betroffene Dateien:** ''NessoN1Board.cpp'', ''NessoDisplayDriver.cpp'' **Betroffene Dateien:** ''NessoN1Board.cpp'', ''NessoDisplayDriver.cpp''
  
Zeile 335: Zeile 159:
 </code> </code>
  
-**Ursache — präzise:** +**Ursache:** ''main.cpp'' ruft ''display.begin()'' vor ''radio_init()'' auf. M5GFX ruft intern ''spi_bus_initialize(SPI2_HOST)'' und ''Wire.begin()'' auf. Wenn anschließend ''radio_init()'' → ''board.begin()'' → ''lora_spi.begin()'' läuft, versucht der ESP-IDF SPI-Treiber denselben APB-Callback erneut zu registrieren → Duplikat.
-''main.cpp'' ruft ''display.begin()'' vor ''radio_init()'' auf. Beim ersten +
-''display.begin()''-Aufruf konstruiert ''NessoDisplayDriver'' M5GFX als +
-static-local. M5GFX ruft intern ''spi_bus_initialize(SPI2_HOST)'' und +
-''Wire.begin()'' auf. Wenn anschließend ''radio_init()'' → ''board.begin()'' +
-''lora_spi.begin()'' läuft, versucht der ESP-IDF SPI-Treiber denselben +
-APB-Callback erneut zu registrieren → ''duplicate''. ''Wire.begin()'' auf +
-bereits initialisierten Bus → ''setPins warning''+
- +
-**Fix:** +
-Der Board-Guard (Fix 3) verhindert den zweiten ''lora_spi.begin()''-Aufruf. +
-''BUSY'' bleibt LOW, ''std_init'' läuft durch. Die drei ''[E]''-Zeilen erscheinen +
-trotzdem solange ''main.cpp'' die falsche Reihenfolge hat — sie sind +
-**funktional harmlos** (System funktioniert korrekt), aber ein sichtbarer +
-Indikator für die unvollständig behobene Aufruf-Reihenfolge.+
  
-----+**Fix:** Der Board-Guard (Fix 3) verhindert den zweiten ''lora_spi.begin()''-Aufruf. Die drei ''[E]''-Zeilen sind **funktional harmlos**, aber ein sichtbarer Indikator für die unvollständig behobene Aufruf-Reihenfolge.
  
 ==== Fix 5 — BUSY-Puls-Timing nach loraReset() ==== ==== Fix 5 — BUSY-Puls-Timing nach loraReset() ====
  
-**Datum:** April 2026  +**Datum:** April 2026\\
 **Betroffene Datei:** ''NessoN1Board.cpp'' **Betroffene Datei:** ''NessoN1Board.cpp''
  
-**Symptom:** Log meldet ''BUSY direkt nach NRST HIGH: LOW (unerwartet — evtl. kein Reset angekommen)'' obwohl Reset korrekt funktioniert und ''std_init'' erfolgreich ist.+**Symptom:** Log meldet ''BUSY direkt nach NRST HIGH: LOW (unerwartet)'' obwohl Reset korrekt funktioniert und ''std_init'' erfolgreich ist.
  
-**Ursache — präzise:** +**Ursache:** Der ''delay(20)'' nach NRST HIGH war zu lang. Der SX1262 auf dem Nesso N1 hat einen BUSY-HIGH-Puls von unter 1 ms nach dem Reset — der Chip hatte BUSY längst wieder LOW gezogenwenn ''digitalRead()'' nach 20 ms lief.
-Der ''delay(20)'' nach NRST HIGH war zu lang. Der SX1262 auf dem Nesso N1 hat +
-einen BUSY-HIGH-Puls von unter 1 ms nach dem Reset — der Chip hatte BUSY längst +
-wieder LOW gezogen wenn ''digitalRead()'' nach 20 ms lief. Es handelte sich um +
-keinen echten Fehler, sondern um ein zu konservatives Timing kombiniert mit einer +
-zu alarmistischen Logmeldung.+
  
 **Fix:** **Fix:**
-<code>cpp+<code cpp>
 _exp0.digitalWrite(NESSO_EXP0_SX_NRST, true); _exp0.digitalWrite(NESSO_EXP0_SX_NRST, true);
 delay(2);   // war: delay(20) — 2 ms reicht, BUSY-Puls auf Nesso N1 < 1 ms delay(2);   // war: delay(20) — 2 ms reicht, BUSY-Puls auf Nesso N1 < 1 ms
 </code> </code>
 +
 Logmeldung geändert zu: Logmeldung geändert zu:
 <code> <code>
Zeile 377: Zeile 183:
 </code> </code>
  
-----+==== Fix 7 — Tasten ohne Funktion im Repeater-Display-Modus ====
  
-===== Verzeichnisstruktur =====+**Datum:** April 2026\\ 
 +**Betroffene Dateien:** ''simple_repeater/main.cpp'', ''simple_repeater/UITask.h'', ''simple_repeater/UITask.cpp'', ''simple_repeater/MyMesh.h'' 
 + 
 +**Symptom:** KEY1 und KEY2 reagieren scheinbar nicht. Im Serial-Log erscheint ''[ui] KEY1 erkannt'' — die Taste wird erkannt, aber es passiert nichts am Display. 
 + 
 +**Ursache:** ''nesso_ui_tick()'' gibt bei erkannter Taste ''-1'' (KEY1) oder ''-2'' (KEY2) zurück, wenn das Display bereits an ist. In ''main.cpp'' war die Auswertung dieser Werte vollständig **auskommentiert**. Zusätzlich hatte ''UITask'' keine navigierbaren Screens und keine Verbindung zu ''MyMesh''
 + 
 +**Fix — drei Ebenen:** 
 + 
 +**1. Neues Interface ''UIActions.h''** — entkoppelt UITask von MyMesh: 
 +<code cpp> 
 +class UIActions { 
 +public: 
 +  virtual void uiGetNeighborList(char* buf, int bufSize) 0; 
 +  virtual void uiSendDiscover() 0; 
 +}; 
 +</code> 
 + 
 +**2. ''MyMesh'' implementiert ''UIActions''** — in ''MyMesh.h'': 
 +<code cpp> 
 +class MyMesh : public mesh::Mesh, public CommonCLICallbacks, public UIActions { 
 +  void uiGetNeighborList(char* buf, int bufSize) override { formatNeighborsReply(buf);
 +  void uiSendDiscover() override { sendNodeDiscoverReq();
 +}; 
 +</code>
  
 +**3. ''UITask'' bekommt 3 Screens + Navigation**, verbunden via ''setActions()'':
 <code> <code>
-variants/arduino_nesso_n1/ +SCREEN_HOME       — Node-NameFrequenzSF/BW/CR 
-├── NessoN1Board.h             — Pin-KonstantenPI4IOE5V6408-TreiberBoard-Klasse +SCREEN_NEIGHBOURS — Nachbarliste (HEX-IDAlterSNR
-├── NessoN1Board.cpp           — begin() mit Guard (Fix 3), loraReset() (Fix 5) +SCREEN_POLL_SENT  — Feedback "Poll gesendet" für 2 Sek
-├── NessoDisplayDriver.h       — DisplayDriver-ErweiterungLazy Construction +</code>
-├── NessoDisplayDriver.cpp     — begin() mit setRotation-Fix (Fix 2) +
-├── target.h                   — Externe Deklarationennesso_check_buttons(+
-├── target.cpp                 — radio_init() Pflichtsequenz, globale Objekte +
-├── platformio.ini             — incl. SCREEN_TIMEOUT=0 (Fix 1) +
-├── credentials.ini.example    — Vorlage für lokale Zugangsdaten +
-└── main_cpp_setup_hinweis.txt — Hinweis zur korrekten main.cpp-Struktur (Fix 3/4)+
  
-src/helpers/ui+**4. ''main.cpp'' wertet ''btn'' aus** (vorher auskommentiert): 
-└── DisplayDriver.h            — Abstraktes Interface (Pure-Virtuals)+<code cpp> 
 +if (btn == -1) ui_task.nextScreen();   // KEY1: vorwärts Poll 
 +if (btn == -2ui_task.prevScreen();   // KEY2: zurück 
 +</code>
  
-src/helpers/radiolib/ +**Bedienung nach dem Patch:** 
-├── RfSwitchCallback.h         — Abstraktes Interface für externen RF-Switch + 
-└── CustomSX1262Wrapper.h      — SX1262-Wrapper mit RF-Switch-Callback+^ Taste ^ Display AUS ^ Display AN (Home) ^ Display AN (Nachbarn) ^ 
 +| KEY1 | Wakeup | → Nachbarn-Screen | → Poll senden | 
 +| KEY2 | Wakeup | bleibt Home | → Home-Screen | 
 + 
 +Nach dem Poll zeigt der Screen 2 Sekunden "Poll gesendet", dann wechselt er automatisch zurück zur aktualisierten Nachbarliste. 
 + 
 +==== Fix 8 — Tasten nicht erkannt: Wire-Konflikt zwischen M5GFX und Expander-Treiber ==== 
 + 
 +**Datum:** April 2026\\ 
 +**Betroffene Dateien:** ''NessoDisplayDriver.cpp'', ''NessoDisplayDriver.h'', ''platformio.ini'' 
 + 
 +**Symptom:** KEY1 und KEY2 werden trotz korrekter Flanken-Erkennung nicht oder unzuverlässig registriert. Im Serial-Log: 
 +<code> 
 +[E][Wire.cpp:131] setPins(): bus already initialized. change pins only when not. 
 +[E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=... 
 +</code> 
 + 
 +**Ursache:** M5GFX initialisiert den I²C-Bus intern über ''WireInternal.begin(SDA, SCL)''. Der eigene ''PI4IOE5V6408''-Treiber in ''NessoN1Board'' initialisiert ''Wire'' ebenfalls direkt. Beide greifen auf **denselben Bus** (SDA=GPIO10, SCL=GPIO8) zu mit unterschiedlichen ''TwoWire''-Instanzen → Bus-Kollisionen. Dokumentiert im [[https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099|Arduino Forum (November 2025)]]. 
 + 
 +**Fix:** ''M5Unified'' übernimmt Button-Handling und Display-Init koordiniert. ''M5.begin()'' initialisiert Wire, M5GFX und GPIO-Expander in der richtigen Reihenfolge. 
 + 
 +<code cpp> 
 +// NessoDisplayDriver.cpp — begin(): 
 +M5.begin(cfg);              // statt: _gfx->begin() 
 +_gfx = &M5.Display;        // statt: static M5GFX gfx_instance 
 + 
 +// checkButtons(): 
 +M5.update(); 
 +if (M5.BtnA.wasPressed()) return 1;  // KEY1 
 +if (M5.BtnB.wasPressed()) return 2;  // KEY2 
 +</code> 
 + 
 +<code ini> 
 +; platformio.ini — nesso_n1_base: 
 +lib_deps = 
 +  m5stack/M5GFX 
 +  m5stack/M5Unified   ; NEU: Fix 8
 </code> </code>
  
-----+Entfernt: ''_prevBtnState'', ''_btnReadyAt'', ''_lastBtnCheck'' — manueller Debounce entfällt, M5Unified macht Flanken-Erkennung intern.
  
 ===== Schnellstart ===== ===== Schnellstart =====
Zeile 407: Zeile 271:
 ==== 1. Voraussetzungen ==== ==== 1. Voraussetzungen ====
  
-  * [PlatformIO](https://platformio.org/(CLI oder VS Code Extension)+  * [[https://platformio.org/|PlatformIO]] (CLI oder VS Code Extension)
   * Arduino Nesso N1 per USB-C verbunden   * Arduino Nesso N1 per USB-C verbunden
  
 ==== 2. Zugangsdaten einrichten ==== ==== 2. Zugangsdaten einrichten ====
  
-<code>bash+<code bash>
 cd <projektwurzel> cd <projektwurzel>
 cp variants/arduino_nesso_n1/credentials.ini.example credentials.ini cp variants/arduino_nesso_n1/credentials.ini.example credentials.ini
Zeile 419: Zeile 283:
 ''credentials.ini'' anpassen: ''credentials.ini'' anpassen:
  
-<code>ini+<code ini>
 [credentials] [credentials]
 build_flags_repeater = build_flags_repeater =
Zeile 434: Zeile 298:
  
 **Repeater mit Display** (empfohlen als Einstieg): **Repeater mit Display** (empfohlen als Einstieg):
-<code>bash+<code bash>
 pio run -e NessoN1_repeater_display --target upload pio run -e NessoN1_repeater_display --target upload
 pio device monitor -b 115200 pio device monitor -b 115200
Zeile 440: Zeile 304:
  
 **Repeater ohne Display:** **Repeater ohne Display:**
-<code>bash+<code bash>
 pio run -e NessoN1_repeater --target upload pio run -e NessoN1_repeater --target upload
 </code> </code>
  
 **Companion Radio — BLE:** **Companion Radio — BLE:**
-<code>bash+<code bash>
 pio run -e NessoN1_companion_ble --target upload pio run -e NessoN1_companion_ble --target upload
 </code> </code>
  
 **Companion Radio — WiFi/TCP:** **Companion Radio — WiFi/TCP:**
-<code>bash+<code bash>
 pio run -e NessoN1_companion_wifi --target upload pio run -e NessoN1_companion_wifi --target upload
 </code> </code>
Zeile 474: Zeile 338:
 </code> </code>
  
-Drei ''[E]''-Zeilen (Wire.setPins, APB-Duplikat) erscheinen noch solange +Drei ''[E]''-Zeilen (Wire.setPins, APB-Duplikat) erscheinen noch solange ''main.cpp'' die falsche Aufruf-Reihenfolge hat — sie sind harmlos.
-''main.cpp'' die Reihenfolge aus Fix 3/4 hat — sie sind harmlos. +
- +
-----+
  
 ===== Pin-Referenz ===== ===== Pin-Referenz =====
Zeile 483: Zeile 344:
 ==== Direkte ESP32-C6 GPIOs ==== ==== Direkte ESP32-C6 GPIOs ====
  
-Funktion GPIO +Funktion GPIO ^
-|---|---|+
 | LoRa MOSI | G21 | | LoRa MOSI | G21 |
 | LoRa MISO | G22 | | LoRa MISO | G22 |
Zeile 499: Zeile 359:
 ==== Über I²C-Expander 0 (0x43) ==== ==== Über I²C-Expander 0 (0x43) ====
  
-Funktion Expander-Pin +Funktion Expander-Pin ^
-|---|---|+
 | Taste A (KEY1) | P0 | | Taste A (KEY1) | P0 |
 | Taste B (KEY2) | P1 | | Taste B (KEY2) | P1 |
Zeile 509: Zeile 368:
 ==== Über I²C-Expander 1 (0x44) ==== ==== Über I²C-Expander 1 (0x44) ====
  
-Funktion Expander-Pin +Funktion Expander-Pin ^
-|---|---|+
 | LCD Reset | P1 | | LCD Reset | P1 |
 | LCD Backlight | P6 | | LCD Backlight | P6 |
- 
----- 
  
 ===== RF-Switch-Schaltlogik ===== ===== RF-Switch-Schaltlogik =====
  
-Modus ANT_SW LNA_EN Beschreibung +Modus ANT_SW LNA_EN Beschreibung ^
-|---|---|---|---|+
 | TX | HIGH | LOW | Sende-Pfad aktiv, LNA geschützt | | TX | HIGH | LOW | Sende-Pfad aktiv, LNA geschützt |
 | RX | HIGH | HIGH | Empfangs-Pfad mit LNA aktiv | | RX | HIGH | HIGH | Empfangs-Pfad mit LNA aktiv |
 | IDLE | LOW | LOW | HF-Pfad getrennt, Stromsparmodus | | IDLE | LOW | LOW | HF-Pfad getrennt, Stromsparmodus |
- 
----- 
  
 ===== Architektur ===== ===== Architektur =====
Zeile 549: Zeile 402:
 </code> </code>
  
-----+===== Verzeichnisstruktur ===== 
 + 
 +<code> 
 +variants/arduino_nesso_n1/ 
 +├── NessoN1Board.h             — Pin-Konstanten, PI4IOE5V6408-Treiber, Board-Klasse 
 +├── NessoN1Board.cpp           — begin() mit Guard (Fix 3), loraReset() (Fix 5) 
 +├── NessoDisplayDriver.h       — DisplayDriver-Erweiterung, Lazy Construction 
 +├── NessoDisplayDriver.cpp     — begin() mit setRotation-Fix (Fix 2) 
 +├── target.h                   — Externe Deklarationen, nesso_check_buttons() 
 +├── target.cpp                 — radio_init() Pflichtsequenz, globale Objekte 
 +├── platformio.ini             — incl. SCREEN_TIMEOUT=0 (Fix 1) 
 +├── credentials.ini.example    — Vorlage für lokale Zugangsdaten 
 +└── main_cpp_setup_hinweis.txt — Hinweis zur korrekten main.cpp-Struktur (Fix 3/4) 
 + 
 +src/helpers/ui/ 
 +└── DisplayDriver.h            — Abstraktes Interface (Pure-Virtuals) 
 + 
 +src/helpers/radiolib/ 
 +├── RfSwitchCallback.h         — Abstraktes Interface für externen RF-Switch 
 +└── CustomSX1262Wrapper.h      — SX1262-Wrapper mit RF-Switch-Callback 
 +</code>
  
 ===== Offene Punkte ===== ===== Offene Punkte =====
  
-Thema Status +Thema Status ^ 
-|---|---|---| +| 1 | ''main.cpp'': ''board.begin()'' / ''display.begin()'' vor ''radio_init()'' entfernen | Workaround aktiv (Guard) |
-| 1 | ''main.cpp'': ''board.begin()''/''display.begin()'' vor ''radio_init()'' entfernen | Workaround aktiv (Guard) |+
 | 2 | KEY1/KEY2 als UITask Screen-Wakeup einhängen | offen | | 2 | KEY1/KEY2 als UITask Screen-Wakeup einhängen | offen |
 | 3 | Touch FT6336U (I²C 0x38) integrieren | offen | | 3 | Touch FT6336U (I²C 0x38) integrieren | offen |
 | 4 | IMU BMI270 (I²C 0x68) für Auto-Rotation | offen | | 4 | IMU BMI270 (I²C 0x68) für Auto-Rotation | offen |
 | 5 | Akku-Monitor (I²C 0x49) für Display-Anzeige | offen | | 5 | Akku-Monitor (I²C 0x49) für Display-Anzeige | offen |
- 
----- 
  
 ===== Lizenz ===== ===== Lizenz =====
  
-MIT-Lizenz, identisch mit MeshCore. Vollständiger Text im Wurzelverzeichnis. +MIT-Lizenz, identisch mit MeshCore. Vollständiger Text im Wurzelverzeichnis des Repositories.
  
weitere_hardware/nesso_n1.1776533086.txt.gz · Zuletzt geändert: von mellinux