Webseiten-Werkzeuge


weitere_hardware:nesso_n1

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Nächste Überarbeitung
Vorhergehende Überarbeitung
weitere_hardware:nesso_n1 [18.04.2026 18:06] – angelegt mellinuxweitere_hardware:nesso_n1 [18.04.2026 19:24] (aktuell) mellinux
Zeile 1: Zeile 1:
 **HINWEIS:** Befindet sich in der Testphase! **HINWEIS:** Befindet sich in der Testphase!
  
-MeshCore — Arduino Nesso N1 (ESP32-C6)+====== MeshCore — Arduino Nesso N1 (ESP32-C6) ======
  
 **Author:** team-nessoN1-meshcore — team-nessoN1-meshcore@posteo.de   **Author:** team-nessoN1-meshcore — team-nessoN1-meshcore@posteo.de  
Zeile 12: Zeile 12:
 einem 1,14″-Touchscreen in einem kompakten, batteriebetriebenen Gehäuse. einem 1,14″-Touchscreen in einem kompakten, batteriebetriebenen Gehäuse.
  
-## Aktueller Status April 2026:+===== Aktueller Status April 2026: =====
  
 Die Migration läuft (Repeater, Companion). Umfangreiche Tests stehen an. Das  Die Migration läuft (Repeater, Companion). Umfangreiche Tests stehen an. Das 
Zeile 18: Zeile 18:
 Der Source wurden noch nicht veröffentlicht, weil Alpha Versionstatus. Der Source wurden noch nicht veröffentlicht, weil Alpha Versionstatus.
  
 +----
  
---- +===== Hardware-Überblick =====
- +
-## Hardware-Überblick+
  
 | Komponente | Details | | Komponente | Details |
Zeile 36: Zeile 35:
 | 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 =====
  
-### 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
Zeile 54: Zeile 53:
 | KEY2 | P1 | Taste B (Input) | | KEY2 | P1 | Taste B (Input) |
  
-Konsequenz: RadioLib'`setRfSwitchTable()funktioniert nicht (nur direkte GPIOs). +Konsequenz: RadioLib'''setRfSwitchTable()'' funktioniert nicht (nur direkte GPIOs). 
-`NessoN1Boardimplementiert stattdessen das `RfSwitchCallback`-Interface, +''NessoN1Board'' implementiert stattdessen das ''RfSwitchCallback''-Interface, 
-das `CustomSX1262Wrapperbei jedem TX/RX-Übergang aufruft.+das ''CustomSX1262Wrapper'' bei jedem TX/RX-Übergang aufruft.
  
-### Geteilter SPI-Bus (SX1262 + ST7789)+==== Geteilter SPI-Bus (SX1262 + ST7789) ====
  
 | Signal | GPIO | | Signal | GPIO |
Zeile 69: Zeile 68:
 | 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 Arduino einen APB-Hardware-CS-Callback für GPIO23 registrieren; M5GFX tut
 dasselbe für GPIO17 — zwei Callbacks auf demselben Bus führen zu dasselbe für GPIO17 — zwei Callbacks auf demselben Bus führen zu
-`addApbChangeCallback: duplicateund SPI-Korruption.+''addApbChangeCallback: duplicate'' und SPI-Korruption.
  
-### FSPI statt Default-SPI+==== FSPI statt Default-SPI ====
  
-Der ESP32-C6 hat keinen VSPI-Bus: `SPIClass lora_spi(FSPI)`.+Der ESP32-C6 hat keinen VSPI-Bus: ''SPIClass lora_spi(FSPI)''.
  
-### 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 =====
  
-### 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:
  
Zeile 104: Zeile 103:
 Alle vier Elemente belegen zusammen ~100 px von 135 px Höhe — kein vertikaler Überlauf. Alle vier Elemente belegen zusammen ~100 px von 135 px Höhe — kein vertikaler Überlauf.
  
-### Pflichtsequenz der Initialisierung+==== Pflichtsequenz der Initialisierung ====
  
-```+<code>
 radio_init() in target.cpp: radio_init() in target.cpp:
   1. board.begin()           SPI2, Wire, Expander, loraReset()   1. board.begin()           SPI2, Wire, Expander, loraReset()
Zeile 112: Zeile 111:
   3. radio.std_init(nullptr) RadioLib — nullptr: kein zweites spi->begin()   3. radio.std_init(nullptr) RadioLib — nullptr: kein zweites spi->begin()
   4. display.begin()         M5GFX Lazy Construction — zwingend nach std_init!   4. display.begin()         M5GFX Lazy Construction — zwingend nach std_init!
-```+</code>
  
----+----
  
-## Bekannte Probleme und ihre Fixes+===== Bekannte Probleme und ihre Fixes =====
  
---- +==== 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.),
Zeile 129: Zeile 126:
  
 **Ursache — präzise:** **Ursache — präzise:**
-`UITask.h(MeshCore, `examples/simple_repeater/UITask.h`) definiert den +''UITask.h'' (MeshCore, ''examples/simple_repeater/UITask.h'') definiert den 
-Makro `SCREEN_TIMEOUT(Standardwert: 10 000 ms). Nach Ablauf wird intern +Makro ''SCREEN_TIMEOUT'' (Standardwert: 10 000 ms). Nach Ablauf wird intern 
-`display.turnOff()aufgerufen. Der Wakeup-Pfad in UITask prüft `PIN_USER_BTN`+''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 — 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). hängen KEY1 und KEY2 **über I²C-Expander 0** (Adresse 0x43, Pins P0/P1).
-Ein direkter GPIO als `PIN_USER_BTNsteht nicht zur Verfügung. UITask hat+Ein direkter GPIO als ''PIN_USER_BTN'' steht nicht zur Verfügung. UITask hat
 damit **keinen Wakeup-Mechanismus** — das Display bleibt nach Timeout-Ablauf damit **keinen Wakeup-Mechanismus** — das Display bleibt nach Timeout-Ablauf
 permanent schwarz. permanent schwarz.
  
 **Fix:** **Fix:**
-```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> 
-Beide Flags auf 0 deaktivieren den Timeout vollständig. `DISPLAY_TIMEOUT`+Beide Flags auf 0 deaktivieren den Timeout vollständig. ''DISPLAY_TIMEOUT''
 wird zusätzlich gesetzt weil verschiedene UITask-Versionen im MeshCore-Repository wird zusätzlich gesetzt weil verschiedene UITask-Versionen im MeshCore-Repository
 unterschiedliche Makronamen verwenden. unterschiedliche Makronamen verwenden.
  
-**Hinweis Akku-Betrieb:** Sinnvoller Wert z.B. `-D SCREEN_TIMEOUT=30000`+**Hinweis Akku-Betrieb:** Sinnvoller Wert z.B. ''-D SCREEN_TIMEOUT=30000''
-Der Button-Wakeup ist über `nesso_ui_tick()bereits integriert (siehe Fix 7).+Der Button-Wakeup ist über ''nesso_ui_tick()'' bereits integriert (siehe Fix 7).
  
----+----
  
-### Fix 7 — Tasten ohne Funktion im Repeater-Display-Modus+==== Fix 7 — Tasten ohne Funktion im Repeater-Display-Modus ====
  
 **Datum:** April 2026   **Datum:** April 2026  
-**Betroffene Dateien:** `simple_repeater/main.cpp``simple_repeater/UITask.h`+**Betroffene Dateien:** ''simple_repeater/main.cpp''''simple_repeater/UITask.h''
-`simple_repeater/UITask.cpp``simple_repeater/MyMesh.h`+''simple_repeater/UITask.cpp''''simple_repeater/MyMesh.h''
  
 **Symptom:** KEY1 und KEY2 reagieren scheinbar nicht. Im Serial-Log erscheint **Symptom:** KEY1 und KEY2 reagieren scheinbar nicht. Im Serial-Log erscheint
-`[ui] KEY1 erkannt— die Taste wird erkannt, aber es passiert nichts am Display.+''[ui] KEY1 erkannt'' — die Taste wird erkannt, aber es passiert nichts am Display.
  
 **Ursache — präzise:**   **Ursache — präzise:**  
-`nesso_ui_tick()gibt bei erkannter Taste `-1(KEY1) oder `-2(KEY2) zurück, +''nesso_ui_tick()'' gibt bei erkannter Taste ''-1'' (KEY1) oder ''-2'' (KEY2) zurück, 
-wenn das Display bereits an ist. In `main.cppwar die Auswertung dieser Werte +wenn das Display bereits an ist. In ''main.cpp'' war die Auswertung dieser Werte 
-vollständig **auskommentiert**. Zusätzlich hatte `UITaskkeine navigierbaren +vollständig **auskommentiert**. Zusätzlich hatte ''UITask'' keine navigierbaren 
-Screens und keine Verbindung zu `MyMesh`, um Nachbardaten oder einen+Screens und keine Verbindung zu ''MyMesh'', um Nachbardaten oder einen
 Discover-Request abrufen zu können. Discover-Request abrufen zu können.
  
 **Fix — drei Ebenen:** **Fix — drei Ebenen:**
  
-1. **Neues Interface `UIActions.h`** — entkoppelt UITask von MyMesh: +1. **Neues Interface ''UIActions.h''** — entkoppelt UITask von MyMesh: 
-```cpp+<code>cpp
 class UIActions { class UIActions {
 public: public:
Zeile 178: Zeile 175:
   virtual void uiSendDiscover() = 0;   virtual void uiSendDiscover() = 0;
 }; };
-```+</code>
  
-2. **`MyMeshimplementiert `UIActions`** — in `MyMesh.h`+2. **''MyMesh'' implementiert ''UIActions''** — in ''MyMesh.h''
-```cpp+<code>cpp
 class MyMesh : public mesh::Mesh, public CommonCLICallbacks, public UIActions { class MyMesh : public mesh::Mesh, public CommonCLICallbacks, public UIActions {
   ...   ...
Zeile 187: Zeile 184:
   void uiSendDiscover() override { sendNodeDiscoverReq(); }   void uiSendDiscover() override { sendNodeDiscoverReq(); }
 }; };
-```+</code>
  
-3. **`UITaskbekommt 3 Screens + Navigation**, verbunden via `setActions()`+3. **''UITask'' bekommt 3 Screens + Navigation**, verbunden via ''setActions()''
-```+<code>
 SCREEN_HOME       — Node-Name, Frequenz, SF/BW/CR SCREEN_HOME       — Node-Name, Frequenz, SF/BW/CR
 SCREEN_NEIGHBOURS — Nachbarliste (HEX-ID, Alter, SNR) SCREEN_NEIGHBOURS — Nachbarliste (HEX-ID, Alter, SNR)
 SCREEN_POLL_SENT  — Feedback "Poll gesendet" für 2 Sek. SCREEN_POLL_SENT  — Feedback "Poll gesendet" für 2 Sek.
-```+</code>
  
-4. **`main.cppwertet `btnaus** (vorher auskommentiert): +4. **''main.cpp'' wertet ''btn'' aus** (vorher auskommentiert): 
-```cpp+<code>cpp
 if (btn == -1) ui_task.nextScreen();   // KEY1: vorwärts / Poll if (btn == -1) ui_task.nextScreen();   // KEY1: vorwärts / Poll
 if (btn == -2) ui_task.prevScreen();   // KEY2: zurück if (btn == -2) ui_task.prevScreen();   // KEY2: zurück
-```+</code>
  
 **Bedienung nach dem Patch:** **Bedienung nach dem Patch:**
Zeile 212: Zeile 209:
 dann wechselt er automatisch zurück zur (aktualisierten) Nachbarliste. dann wechselt er automatisch zurück zur (aktualisierten) Nachbarliste.
  
----+----
  
---- +==== Fix 8 — Tasten nicht erkannt: Wire-Konflikt zwischen M5GFX und Expander-Treiber ====
- +
-### Fix 8 — Tasten nicht erkannt: Wire-Konflikt zwischen M5GFX und Expander-Treiber+
  
 **Datum:** April 2026   **Datum:** April 2026  
-**Betroffene Dateien:** `NessoDisplayDriver.cpp``NessoDisplayDriver.h``platformio.ini`+**Betroffene Dateien:** ''NessoDisplayDriver.cpp''''NessoDisplayDriver.h''''platformio.ini''
  
 **Symptom:** KEY1 und KEY2 werden trotz korrekter Flanken-Erkennung und Boot-Sperre **Symptom:** KEY1 und KEY2 werden trotz korrekter Flanken-Erkennung und Boot-Sperre
 nicht oder unzuverlässig registriert. Im Serial-Log erscheinen: nicht oder unzuverlässig registriert. Im Serial-Log erscheinen:
-```+<code>
 [E][Wire.cpp:131] setPins(): bus already initialized. change pins only when not. [E][Wire.cpp:131] setPins(): bus already initialized. change pins only when not.
 [E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=... [E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=...
-```+</code>
  
 **Ursache — präzise:**   **Ursache — präzise:**  
-M5GFX initialisiert den I²C-Bus intern über `WireInternal.begin(SDA, SCL)`+M5GFX initialisiert den I²C-Bus intern über ''WireInternal.begin(SDA, SCL)''
-Der eigene `PI4IOE5V6408`-Treiber in `NessoN1Boardinitialisiert `Wireebenfalls+Der eigene ''PI4IOE5V6408''-Treiber in ''NessoN1Board'' initialisiert ''Wire'' ebenfalls
 direkt. Beide greifen auf **denselben Bus** (SDA=GPIO10, SCL=GPIO8) zu — direkt. Beide greifen auf **denselben Bus** (SDA=GPIO10, SCL=GPIO8) zu —
-mit unterschiedlichen `TwoWire`-Instanzen. Das führt zu Bus-Kollisionen und+mit unterschiedlichen ''TwoWire''-Instanzen. Das führt zu Bus-Kollisionen und
 instabilen Expander-Reads. Dokumentiert im Arduino-Forum (November 2025): instabilen Expander-Reads. Dokumentiert im Arduino-Forum (November 2025):
 https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099 https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099
  
 **Fix:**   **Fix:**  
-`M5Unifiedübernimmt Button-Handling und Display-Init koordiniert. +''M5Unified'' übernimmt Button-Handling und Display-Init koordiniert. 
-`M5.begin()initialisiert Wire, M5GFX und GPIO-Expander in der richtigen+''M5.begin()'' initialisiert Wire, M5GFX und GPIO-Expander in der richtigen
 Reihenfolge — kein Wire-Konflikt mehr. Reihenfolge — kein Wire-Konflikt mehr.
  
-```cpp+<code>cpp
 // NessoDisplayDriver.cpp — begin(): // NessoDisplayDriver.cpp — begin():
 M5.begin(cfg);              // statt: _gfx->begin() M5.begin(cfg);              // statt: _gfx->begin()
Zeile 250: Zeile 245:
 if (M5.BtnA.wasPressed()) return 1;  // KEY1 if (M5.BtnA.wasPressed()) return 1;  // KEY1
 if (M5.BtnB.wasPressed()) return 2;  // KEY2 if (M5.BtnB.wasPressed()) return 2;  // KEY2
-```+</code>
  
-```ini+<code>ini
 ; platformio.ini — nesso_n1_base: ; platformio.ini — nesso_n1_base:
 lib_deps = lib_deps =
   m5stack/M5GFX   m5stack/M5GFX
   m5stack/M5Unified   ; NEU: Fix 8   m5stack/M5Unified   ; NEU: Fix 8
-```+</code>
  
-Entfernt: `_prevBtnState``_btnReadyAt``_lastBtnCheck(manueller+Entfernt: ''_prevBtnState''''_btnReadyAt''''_lastBtnCheck'' (manueller
 Debounce entfällt — M5Unified macht Flanken-Erkennung intern). 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 UITask-Texte werden mit negativem x-Offset abgeschnitten und sind nicht
 lesbar (Versionszeile bei x=−11, Node-Name bei x=−29). lesbar (Versionszeile bei x=−11, Node-Name bei x=−29).
  
 **Ursache — präzise:** **Ursache — präzise:**
-`setRotation(1)wurde in `begin()**nach** `_gfx->width()`_gfx->height()` +''setRotation(1)'' wurde in ''begin()'' **nach** ''_gfx->width()'' ''_gfx->height()'' 
-aufgerufen. M5GFX tauscht die Dimensionen erst nach `setRotation()intern um. +aufgerufen. M5GFX tauscht die Dimensionen erst nach ''setRotation()'' intern um. 
-Die Abfrage vor `setRotation()lieferte daher immer die Portrait-Werte 135×240. +Die Abfrage vor ''setRotation()'' lieferte daher immer die Portrait-Werte 135×240. 
-Zusätzlich trat das Problem auf wenn `display.begin()in `main.cppvor +Zusätzlich trat das Problem auf wenn ''display.begin()'' in ''main.cpp'' vor 
-`radio_init()aufgerufen wurde: Der idempotente Guard beim zweiten `begin()`-Aufruf +''radio_init()'' aufgerufen wurde: Der idempotente Guard beim zweiten ''begin()''-Aufruf 
-aus `radio_init()hat `setRotation(1)dann gar nicht mehr ausgeführt — der +aus ''radio_init()'' hat ''setRotation(1)'' dann gar nicht mehr ausgeführt — der 
-Controller lief weiter im Portrait-Modus obwohl `DisplayDriver(240, 135)`+Controller lief weiter im Portrait-Modus obwohl ''DisplayDriver(240, 135)''
 im Konstruktor richtig gesetzt war. im Konstruktor richtig gesetzt war.
  
-**Fix in `NessoDisplayDriver.cpp`:** +**Fix in ''NessoDisplayDriver.cpp'':** 
-```cpp+<code>cpp
 // setRotation ZUERST — M5GFX tauscht Dimensionen erst danach: // setRotation ZUERST — M5GFX tauscht Dimensionen erst danach:
 _gfx->setRotation(1); _gfx->setRotation(1);
Zeile 288: Zeile 283:
 Serial.printf("[display] M5GFX bereit: %d x %d px\n", _gfx->width(), _gfx->height()); Serial.printf("[display] M5GFX bereit: %d x %d px\n", _gfx->width(), _gfx->height());
 // Ausgabe: 240 x 135 px ✓ // Ausgabe: 240 x 135 px ✓
-```+</code>
  
----+----
  
-### Fix 3 — `radio init failed: -2durch 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 — präzise:**
-`examples/simple_repeater/main.cpp(MeshCore-eigener Code) ruft unter +''examples/simple_repeater/main.cpp'' (MeshCore-eigener Code) ruft unter 
-`#ifdef DISPLAY_CLASSin `setup()explizit `board.begin()auf — **vor** +''#ifdef DISPLAY_CLASS'' in ''setup()'' explizit ''board.begin()'' auf — **vor** 
-`radio_init()`. Das generische MeshCore-Muster funktioniert auf anderen Boards+''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 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. +führt ''board.begin()'' intern ''loraReset()'' aus: der SX1262 bootet, BUSY geht HIGH. 
-Anschließend ruft `radio_init()erneut `board.begin()auf → zweites `loraReset()→ +Anschließend ruft ''radio_init()'' erneut ''board.begin()'' auf → zweites ''loraReset()'' → 
-SX1262 bootet erneut, BUSY wieder HIGH → `radio.std_init()trifft Chip mitten im +SX1262 bootet erneut, BUSY wieder HIGH → ''radio.std_init()'' trifft Chip mitten im 
-Bootvorgang → `RADIOLIB_ERR_CHIP_NOT_FOUND`-2`.+Bootvorgang → ''RADIOLIB_ERR_CHIP_NOT_FOUND'' ''-2''.
  
-**Fix in `NessoN1Board::begin()`:** +**Fix in ''NessoN1Board::begin()'':** 
-```cpp+<code>cpp
 static bool s_boardBeginCalled = false; static bool s_boardBeginCalled = false;
 if (s_boardBeginCalled) { if (s_boardBeginCalled) {
Zeile 317: Zeile 312:
 } }
 s_boardBeginCalled = true; s_boardBeginCalled = true;
-``` +</code> 
-Der Guard stellt sicher dass `loraReset()und `lora_spi.begin()genau einmal +Der Guard stellt sicher dass ''loraReset()'' und ''lora_spi.begin()'' genau einmal 
-laufen, unabhängig von der Aufruf-Reihenfolge in `main.cpp`.+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. +aus ''setup()'' entfernen — beide werden intern durch ''radio_init()'' erledigt. 
-Da `main.cppMeshCore-eigener Code ist, ist der Guard die robustere Variante +Da ''main.cpp'' MeshCore-eigener Code ist, ist der Guard die robustere Variante 
-ohne Repository-Fork. Hinweis: `main_cpp_setup_hinweis.txt`.+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''
  
 **Symptom:** **Symptom:**
-```+<code>
 [E][Wire.cpp:131] setPins(): bus already initialized. [E][Wire.cpp:131] setPins(): bus already initialized.
 [E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=... [E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=...
 [E][esp32-hal-cpu.c:146] removeApbChangeCallback(): not found func=... [E][esp32-hal-cpu.c:146] removeApbChangeCallback(): not found func=...
-```+</code>
  
 **Ursache — präzise:** **Ursache — präzise:**
-`main.cppruft `display.begin()vor `radio_init()auf. Beim ersten +''main.cpp'' ruft ''display.begin()'' vor ''radio_init()'' auf. Beim ersten 
-`display.begin()`-Aufruf konstruiert `NessoDisplayDriverM5GFX als +''display.begin()''-Aufruf konstruiert ''NessoDisplayDriver'' M5GFX als 
-static-local. M5GFX ruft intern `spi_bus_initialize(SPI2_HOST)und +static-local. M5GFX ruft intern ''spi_bus_initialize(SPI2_HOST)'' und 
-`Wire.begin()auf. Wenn anschließend `radio_init()→ `board.begin()→ +''Wire.begin()'' auf. Wenn anschließend ''radio_init()'' → ''board.begin()'' → 
-`lora_spi.begin()läuft, versucht der ESP-IDF SPI-Treiber denselben +''lora_spi.begin()'' läuft, versucht der ESP-IDF SPI-Treiber denselben 
-APB-Callback erneut zu registrieren → `duplicate``Wire.begin()auf +APB-Callback erneut zu registrieren → ''duplicate''''Wire.begin()'' auf 
-bereits initialisierten Bus → `setPins warning`.+bereits initialisierten Bus → ''setPins warning''.
  
 **Fix:** **Fix:**
-Der Board-Guard (Fix 3) verhindert den zweiten `lora_spi.begin()`-Aufruf. +Der Board-Guard (Fix 3) verhindert den zweiten ''lora_spi.begin()''-Aufruf. 
-`BUSYbleibt LOW, `std_initläuft durch. Die drei `[E]`-Zeilen erscheinen +''BUSY'' bleibt LOW, ''std_init'' läuft durch. Die drei ''[E]''-Zeilen erscheinen 
-trotzdem solange `main.cppdie falsche Reihenfolge hat — sie sind+trotzdem solange ''main.cpp'' die falsche Reihenfolge hat — sie sind
 **funktional harmlos** (System funktioniert korrekt), aber ein sichtbarer **funktional harmlos** (System funktioniert korrekt), aber ein sichtbarer
 Indikator für die unvollständig behobene Aufruf-Reihenfolge. 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_initerfolgreich ist.+**Symptom:** Log meldet ''BUSY direkt nach NRST HIGH: LOW (unerwartet — evtl. kein Reset angekommen)'' obwohl Reset korrekt funktioniert und ''std_init'' erfolgreich ist.
  
 **Ursache — präzise:** **Ursache — präzise:**
-Der `delay(20)nach NRST HIGH war zu lang. Der SX1262 auf dem Nesso N1 hat+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 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+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 keinen echten Fehler, sondern um ein zu konservatives Timing kombiniert mit einer
 zu alarmistischen Logmeldung. zu alarmistischen Logmeldung.
  
 **Fix:** **Fix:**
-```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>
 Logmeldung geändert zu: Logmeldung geändert zu:
-```+<code>
 [loraReset] BUSY 2 ms nach NRST HIGH: LOW (Chip hat BUSY-Puls bereits abgeschlossen — normal auf Nesso N1) [loraReset] BUSY 2 ms nach NRST HIGH: LOW (Chip hat BUSY-Puls bereits abgeschlossen — normal auf Nesso N1)
-```+</code>
  
----+----
  
-## Verzeichnisstruktur+===== Verzeichnisstruktur =====
  
-```+<code>
 variants/arduino_nesso_n1/ variants/arduino_nesso_n1/
 ├── NessoN1Board.h             — Pin-Konstanten, PI4IOE5V6408-Treiber, Board-Klasse ├── NessoN1Board.h             — Pin-Konstanten, PI4IOE5V6408-Treiber, Board-Klasse
Zeile 404: Zeile 399:
 ├── RfSwitchCallback.h         — Abstraktes Interface für externen RF-Switch ├── RfSwitchCallback.h         — Abstraktes Interface für externen RF-Switch
 └── CustomSX1262Wrapper.h      — SX1262-Wrapper mit RF-Switch-Callback └── CustomSX1262Wrapper.h      — SX1262-Wrapper mit RF-Switch-Callback
-```+</code>
  
----+----
  
-## Schnellstart+===== Schnellstart =====
  
-### 1. Voraussetzungen+==== 1. Voraussetzungen ====
  
-[PlatformIO](https://platformio.org/) (CLI oder VS Code Extension) +  * [PlatformIO](https://platformio.org/) (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 ====
  
-```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
-```+</code>
  
-`credentials.inianpassen:+''credentials.ini'' anpassen:
  
-```ini+<code>ini
 [credentials] [credentials]
 build_flags_repeater = build_flags_repeater =
Zeile 432: Zeile 427:
   -D WIFI_SSID='"dein_wlan"'   -D WIFI_SSID='"dein_wlan"'
   -D WIFI_PWD='"dein_passwort"'   -D WIFI_PWD='"dein_passwort"'
-```+</code>
  
-`credentials.iniist in `.gitignoreund wird **nicht** ins Repository eingecheckt.+''credentials.ini'' ist in ''.gitignore'' und wird **nicht** ins Repository eingecheckt.
  
-### 3. Firmware bauen und flashen+==== 3. Firmware bauen und flashen ====
  
 **Repeater mit Display** (empfohlen als Einstieg): **Repeater mit Display** (empfohlen als Einstieg):
-```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
-```+</code>
  
 **Repeater ohne Display:** **Repeater ohne Display:**
-```bash+<code>bash
 pio run -e NessoN1_repeater --target upload pio run -e NessoN1_repeater --target upload
-```+</code>
  
 **Companion Radio — BLE:** **Companion Radio — BLE:**
-```bash+<code>bash
 pio run -e NessoN1_companion_ble --target upload pio run -e NessoN1_companion_ble --target upload
-```+</code>
  
 **Companion Radio — WiFi/TCP:** **Companion Radio — WiFi/TCP:**
-```bash+<code>bash
 pio run -e NessoN1_companion_wifi --target upload pio run -e NessoN1_companion_wifi --target upload
-```+</code>
  
-### 4. Erwartete Serial-Ausgabe beim Boot (Repeater mit Display)+==== 4. Erwartete Serial-Ausgabe beim Boot (Repeater mit Display) ====
  
-```+<code>
 [board] begin() gestartet [board] begin() gestartet
 [board]      I2C-Scan: [board]      I2C-Scan:
Zeile 477: Zeile 472:
 [init] === radio_init() abgeschlossen — Radio bereit === [init] === radio_init() abgeschlossen — Radio bereit ===
 Repeater ID: ... Repeater ID: ...
-```+</code>
  
-Drei `[E]`-Zeilen (Wire.setPins, APB-Duplikat) erscheinen noch solange +Drei ''[E]''-Zeilen (Wire.setPins, APB-Duplikat) erscheinen noch solange 
-`main.cppdie Reihenfolge aus Fix 3/4 hat — sie sind harmlos.+''main.cpp'' die Reihenfolge aus Fix 3/4 hat — sie sind harmlos.
  
----+----
  
-## Pin-Referenz+===== Pin-Referenz =====
  
-### Direkte ESP32-C6 GPIOs+==== Direkte ESP32-C6 GPIOs ====
  
 | Funktion | GPIO | | Funktion | GPIO |
Zeile 502: Zeile 497:
 | Touch INT | G3 | | Touch INT | G3 |
  
-### Über I²C-Expander 0 (0x43)+==== Über I²C-Expander 0 (0x43) ====
  
 | Funktion | Expander-Pin | | Funktion | Expander-Pin |
Zeile 512: Zeile 507:
 | LoRa Reset (NRST) | P7 | | LoRa Reset (NRST) | P7 |
  
-### Über I²C-Expander 1 (0x44)+==== Über I²C-Expander 1 (0x44) ====
  
 | Funktion | Expander-Pin | | Funktion | Expander-Pin |
Zeile 519: Zeile 514:
 | LCD Backlight | P6 | | LCD Backlight | P6 |
  
----+----
  
-## RF-Switch-Schaltlogik+===== RF-Switch-Schaltlogik =====
  
 | Modus | ANT_SW | LNA_EN | Beschreibung | | Modus | ANT_SW | LNA_EN | Beschreibung |
Zeile 529: Zeile 524:
 | IDLE | LOW | LOW | HF-Pfad getrennt, Stromsparmodus | | IDLE | LOW | LOW | HF-Pfad getrennt, Stromsparmodus |
  
----+----
  
-## Architektur+===== Architektur =====
  
-```+<code>
 target.cpp target.cpp
   └─ radio_init()   └─ radio_init()
Zeile 552: Zeile 547:
   ├─ onRfRx()     ANT_SW=HIGH, LNA_EN=HIGH   ├─ onRfRx()     ANT_SW=HIGH, LNA_EN=HIGH
   └─ onRfIdle()   ANT_SW=LOW,  LNA_EN=LOW   └─ onRfIdle()   ANT_SW=LOW,  LNA_EN=LOW
-```+</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 |
Zeile 566: Zeile 561:
 | 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.
 +
  
weitere_hardware/nesso_n1.1776528408.txt.gz · Zuletzt geändert: von mellinux