<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="FeedCreator 1.8" -->
<?xml-stylesheet href="http://meshcore-de.fyi/lib/exe/css.php?s=feed" type="text/css"?>
<rss version="2.0">
    <channel xmlns:g="http://base.google.com/ns/1.0">
        <title>MeshCore Wiki DE - weitere_hardware</title>
        <description></description>
        <link>http://meshcore-de.fyi/</link>
        <lastBuildDate>Wed, 03 Jun 2026 17:59:33 +0000</lastBuildDate>
        <generator>FeedCreator 1.8</generator>
        <image>
            <url>http://meshcore-de.fyi/_media/wiki:dokuwiki.svg</url>
            <title>MeshCore Wiki DE</title>
            <link>http://meshcore-de.fyi/</link>
        </image>
        <item>
            <title>nesso_n1</title>
            <link>http://meshcore-de.fyi/weitere_hardware:nesso_n1</link>
            <description>
&lt;p&gt;
&lt;strong&gt;HINWEIS:&lt;/strong&gt; Befindet sich in der Testphase!
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;HINWEIS:&lt;/strong&gt; team-nessoN1-meshcore muss aus Gesundheitlichen Gründen Pausieren. Wer mag kann Ihn wegen Details der Projektübergabe unter E-Mail — &lt;em&gt;&lt;a href=&quot;mailto:&amp;#64;&amp;#116;&amp;#101;&amp;#97;&amp;#109;&amp;#45;&amp;#110;&amp;#101;&amp;#115;&amp;#115;&amp;#111;&amp;#78;&amp;#49;&amp;#45;&amp;#109;&amp;#101;&amp;#115;&amp;#104;&amp;#99;&amp;#111;&amp;#114;&amp;#101;&amp;#64;&amp;#112;&amp;#111;&amp;#115;&amp;#116;&amp;#101;&amp;#111;&amp;#46;&amp;#100;&amp;#101;&amp;#64;&quot; class=&quot;mail&quot; title=&quot;&amp;#64;&amp;#116;&amp;#101;&amp;#97;&amp;#109;&amp;#45;&amp;#110;&amp;#101;&amp;#115;&amp;#115;&amp;#111;&amp;#78;&amp;#49;&amp;#45;&amp;#109;&amp;#101;&amp;#115;&amp;#104;&amp;#99;&amp;#111;&amp;#114;&amp;#101;&amp;#64;&amp;#112;&amp;#111;&amp;#115;&amp;#116;&amp;#101;&amp;#111;&amp;#46;&amp;#100;&amp;#101;&amp;#64;&quot;&gt;team-nessoN1-meshcore&lt;/a&gt;&lt;/em&gt; kontaktieren.
&lt;/p&gt;

&lt;h1 class=&quot;sectionedit1&quot; id=&quot;meshcore_arduino_nesso_n1_esp32-c6&quot;&gt;MeshCore — Arduino Nesso N1 (ESP32-C6)&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Autor:&lt;/strong&gt; team-nessoN1-meshcore — team-nessoN1-meshcore@posteo.de&lt;br/&gt;

&lt;strong&gt;Stand:&lt;/strong&gt; April 2026
&lt;/p&gt;

&lt;p&gt;
Diese Seite beschreibt die Hardware-Abstraktionsschicht (HAL) für den &lt;strong&gt;Arduino Nesso N1&lt;/strong&gt; 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.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;MeshCore \u2014 Arduino Nesso N1 (ESP32-C6)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;meshcore_arduino_nesso_n1_esp32-c6&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:1,&amp;quot;range&amp;quot;:&amp;quot;276-806&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit2&quot; id=&quot;hardware-ueberblick&quot;&gt;Hardware-Überblick&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;div class=&quot;table sectionedit3&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Komponente &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Details &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; MCU &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Espressif ESP32-C6 (RISC-V, 160 &lt;abbr title=&quot;Megahertz&quot;&gt;MHz&lt;/abbr&gt;) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Flash &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 16 &lt;abbr title=&quot;Megabyte&quot;&gt;MB&lt;/abbr&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; RAM &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 512 KB &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Semtech SX1262, 850–960 &lt;abbr title=&quot;Megahertz&quot;&gt;MHz&lt;/abbr&gt;, bis +22 dBm &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Antennenschalter / LNA &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Extern, gesteuert über I²C-GPIO-Expander &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row6&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; I²C-GPIO-Expander &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; PI4IOE5V6408 (2× Instanzen, Adressen 0x43 und 0x44) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row7&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Display &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; ST7789P3, 1,14″, 240×135 px, Touchscreen (FT6336U) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row8&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; IMU &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; BMI270 (6-Achsen) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row9&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Akku &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 250 mAh LiPo, USB-C Laden &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row10&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Konnektivität &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Wi-Fi 6, BT 5.3, Thread/Zigbee (802.15.4), LoRa &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;secid&amp;quot;:3,&amp;quot;range&amp;quot;:&amp;quot;840-1352&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Hardware-\u00dcberblick&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;hardware-ueberblick&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:2,&amp;quot;range&amp;quot;:&amp;quot;807-1353&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit4&quot; id=&quot;besonderheiten_dieser_portierung&quot;&gt;Besonderheiten dieser Portierung&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Besonderheiten dieser Portierung&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;besonderheiten_dieser_portierung&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:4,&amp;quot;range&amp;quot;:&amp;quot;1354-1399&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit5&quot; id=&quot;sx1262_reset_und_rf-switch_ueber_i_c-expander&quot;&gt;SX1262 Reset und RF-Switch über I²C-Expander&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
Anders als bei den meisten anderen MeshCore-Zielplattformen sind beim Nesso N1 die LoRa-Steuerleitungen &lt;strong&gt;nicht direkt&lt;/strong&gt; mit GPIO-Pins des ESP32-C6 verbunden, sondern laufen über einen &lt;strong&gt;PI4IOE5V6408 I²C-GPIO-Expander&lt;/strong&gt; (Adresse 0x43):
&lt;/p&gt;
&lt;div class=&quot;table sectionedit6&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Signal &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Expander-Pin &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; Funktion &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; SX_NRST &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P7 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Hardware-Reset des SX1262 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; SX_ANT_SW &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P6 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Antennen-RF-Schalter &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; SX_LNA_EN &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P5 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Low-Noise-Amplifier &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; KEY1 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P0 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Taste A (Input) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; KEY2 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P1 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Taste B (Input) &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table1&amp;quot;,&amp;quot;secid&amp;quot;:6,&amp;quot;range&amp;quot;:&amp;quot;1697-1925&amp;quot;} --&gt;
&lt;p&gt;
Konsequenz: RadioLib&amp;#039;s &lt;code&gt;setRfSwitchTable()&lt;/code&gt; funktioniert nicht (nur direkte GPIOs). &lt;code&gt;NessoN1Board&lt;/code&gt; implementiert stattdessen das &lt;code&gt;RfSwitchCallback&lt;/code&gt;-Interface, das &lt;code&gt;CustomSX1262Wrapper&lt;/code&gt; bei jedem TX/RX-Übergang aufruft.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;SX1262 Reset und RF-Switch \u00fcber I\u00b2C-Expander&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;sx1262_reset_und_rf-switch_ueber_i_c-expander&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:5,&amp;quot;range&amp;quot;:&amp;quot;1400-2155&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit7&quot; id=&quot;geteilter_spi-bus_sx1262_st7789&quot;&gt;Geteilter SPI-Bus (SX1262 + ST7789)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit8&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Signal &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; GPIO &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; MOSI &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G21 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; MISO &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G22 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; SCK &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G20 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa CS (NSS) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G23 (Software-CS) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD CS &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G17 (Software-CS) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row6&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD DC &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G16 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table2&amp;quot;,&amp;quot;secid&amp;quot;:8,&amp;quot;range&amp;quot;:&amp;quot;2203-2350&amp;quot;} --&gt;
&lt;p&gt;
&lt;code&gt;lora_spi.begin()&lt;/code&gt; wird &lt;strong&gt;ohne NSS-Argument&lt;/strong&gt; 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 &lt;code&gt;addApbChangeCallback: duplicate&lt;/code&gt; und SPI-Korruption.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Geteilter SPI-Bus (SX1262 + ST7789)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;geteilter_spi-bus_sx1262_st7789&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:7,&amp;quot;range&amp;quot;:&amp;quot;2156-2627&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit9&quot; id=&quot;fspi_statt_default-spi&quot;&gt;FSPI statt Default-SPI&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
Der ESP32-C6 hat keinen VSPI-Bus: &lt;code&gt;SPIClass lora_spi(FSPI)&lt;/code&gt;.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;FSPI statt Default-SPI&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fspi_statt_default-spi&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:9,&amp;quot;range&amp;quot;:&amp;quot;2628-2725&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit10&quot; id=&quot;usb-cdc_und_ble_schliessen_sich_aus&quot;&gt;USB-CDC und BLE schließen sich aus&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit11&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Firmware &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; &lt;code&gt;ARDUINO_USB_CDC_ON_BOOT&lt;/code&gt; &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; Debug-Output &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Repeater &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; &lt;code&gt;1&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; USB-Serial aktiv &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Companion BLE &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; &lt;code&gt;0&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; kein USB-Serial &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Companion WiFi &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; &lt;code&gt;0&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; kein USB-Serial &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table3&amp;quot;,&amp;quot;secid&amp;quot;:11,&amp;quot;range&amp;quot;:&amp;quot;2773-2959&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;USB-CDC und BLE schlie\u00dfen sich aus&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;usb-cdc_und_ble_schliessen_sich_aus&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:10,&amp;quot;range&amp;quot;:&amp;quot;2726-2960&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit12&quot; id=&quot;display-architektur&quot;&gt;Display-Architektur&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Display-Architektur&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;display-architektur&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:12,&amp;quot;range&amp;quot;:&amp;quot;2961-2993&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit13&quot; id=&quot;aufloesung_und_uitask-layoutpruefung&quot;&gt;Auflösung und UITask-Layoutprüfung&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
Das ST7789P3 hat &lt;strong&gt;240×135 Pixel&lt;/strong&gt; (Landscape, &lt;code&gt;setRotation(1)&lt;/code&gt;). Alle UITask-Standardlayouts passen ohne Überlauf:
&lt;/p&gt;
&lt;div class=&quot;table sectionedit14&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Element &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Breite &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; x (zentriert) &lt;/th&gt;&lt;th class=&quot;col3&quot;&gt; Rechte Kante &lt;/th&gt;&lt;th class=&quot;col4&quot;&gt; Passt &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; MeshCore-Logo (64×36 px XBM) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 64 px &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; 88 &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; 152 &lt;/td&gt;&lt;td class=&quot;col4&quot;&gt; ✅ &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Versionszeile (setTextSize 2) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 156 px &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; 42 &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; 198 &lt;/td&gt;&lt;td class=&quot;col4&quot;&gt; ✅ &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Node-Name „NessoN1 Repeater„ &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 192 px &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; 24 &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; 216 &lt;/td&gt;&lt;td class=&quot;col4&quot;&gt; ✅ &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Frequenzzeile „869.6 SF8 BW62.5“ &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 204 px &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; 18 &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; 222 &lt;/td&gt;&lt;td class=&quot;col4&quot;&gt; ✅ &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table4&amp;quot;,&amp;quot;secid&amp;quot;:14,&amp;quot;range&amp;quot;:&amp;quot;3163-3467&amp;quot;} --&gt;
&lt;p&gt;
Alle vier Elemente belegen zusammen ~100 px von 135 px Höhe — kein vertikaler Überlauf.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Aufl\u00f6sung und UITask-Layoutpr\u00fcfung&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;aufloesung_und_uitask-layoutpruefung&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:13,&amp;quot;range&amp;quot;:&amp;quot;2994-3561&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit15&quot; id=&quot;pflichtsequenz_der_initialisierung&quot;&gt;Pflichtsequenz der Initialisierung&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;code&quot;&gt;radio_init() in target.cpp:
  1. board.begin()           SPI2, Wire, Expander, loraReset()
  2. board.onRfRx()          RF-Switch für Kalibrierung
  3. radio.std_init(nullptr) RadioLib — nullptr: kein zweites spi-&amp;gt;begin()
  4. display.begin()         M5GFX Lazy Construction — zwingend nach std_init!&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Pflichtsequenz der Initialisierung&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;pflichtsequenz_der_initialisierung&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:15,&amp;quot;range&amp;quot;:&amp;quot;3562-3929&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit16&quot; id=&quot;bekannte_probleme_und_ihre_fixes&quot;&gt;Bekannte Probleme und ihre Fixes&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Bekannte Probleme und ihre Fixes&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;bekannte_probleme_und_ihre_fixes&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:1,&amp;quot;secid&amp;quot;:16,&amp;quot;range&amp;quot;:&amp;quot;3930-3975&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit17&quot; id=&quot;fix_1_display_schwarz_nach_wenigen_sekunden&quot;&gt;Fix 1 — Display schwarz nach wenigen Sekunden&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Datum:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Betroffene Datei:&lt;/strong&gt; &lt;code&gt;platformio.ini&lt;/code&gt;, &lt;code&gt;[env:NessoN1_repeater_display]&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; Display zeigt Boot-Screen (~4 Sek.) und Home-Screen (~10 Sek.), dann dauerhaft schwarz. Kein Wakeup durch Tastendruck.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Ursache:&lt;/strong&gt; &lt;code&gt;UITask.h&lt;/code&gt; (MeshCore, &lt;code&gt;examples/simple_repeater/UITask.h&lt;/code&gt;) definiert den Makro &lt;code&gt;SCREEN_TIMEOUT&lt;/code&gt; (Standardwert: 10 000 ms). Nach Ablauf wird intern &lt;code&gt;display.turnOff()&lt;/code&gt; aufgerufen. Der Wakeup-Pfad in UITask prüft &lt;code&gt;PIN_USER_BTN&lt;/code&gt; — einen direkten GPIO-Pin. Auf dem Nesso N1 hängen KEY1 und KEY2 &lt;strong&gt;über I²C-Expander 0&lt;/strong&gt; (Adresse 0x43, Pins P0/P1). UITask hat damit &lt;strong&gt;keinen Wakeup-Mechanismus&lt;/strong&gt; — das Display bleibt nach Timeout-Ablauf permanent schwarz.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code ini&quot;&gt;&lt;span class=&quot;co0&quot;&gt;; platformio.ini — [env:NessoN1_repeater_display]:&lt;/span&gt;
-D SCREEN_TIMEOUT&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;re2&quot;&gt;0&lt;/span&gt;
-D DISPLAY_TIMEOUT&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;re2&quot;&gt;0&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
Beide Flags auf 0 deaktivieren den Timeout vollständig. &lt;code&gt;DISPLAY_TIMEOUT&lt;/code&gt; wird zusätzlich gesetzt, weil verschiedene UITask-Versionen unterschiedliche Makronamen verwenden.
&lt;/p&gt;
&lt;blockquote&gt;&lt;div class=&quot;no&quot;&gt;
 &lt;strong&gt;Hinweis Akku-Betrieb:&lt;/strong&gt; Sinnvoller Wert z.B. &lt;code&gt;-D SCREEN_TIMEOUT=30000&lt;/code&gt;. Der Button-Wakeup ist über &lt;code&gt;nesso_ui_tick()&lt;/code&gt; bereits integriert (siehe Fix 7).&lt;/div&gt;&lt;/blockquote&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 1 \u2014 Display schwarz nach wenigen Sekunden&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_1_display_schwarz_nach_wenigen_sekunden&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:1,&amp;quot;secid&amp;quot;:17,&amp;quot;range&amp;quot;:&amp;quot;3976-5213&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit18&quot; id=&quot;fix_2_display_im_portrait-modus_135_240_statt_240_135&quot;&gt;Fix 2 — Display im Portrait-Modus (135×240 statt 240×135)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Datum:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Betroffene Datei:&lt;/strong&gt; &lt;code&gt;NessoDisplayDriver.cpp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; Serial meldet &lt;code&gt;M5GFX meldet Display: 135 x 240 px&lt;/code&gt;. UITask-Texte werden mit negativem x-Offset abgeschnitten und sind nicht lesbar.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Ursache:&lt;/strong&gt; &lt;code&gt;setRotation(1)&lt;/code&gt; wurde in &lt;code&gt;begin()&lt;/code&gt; &lt;strong&gt;nach&lt;/strong&gt; &lt;code&gt;_gfx→width()&lt;/code&gt; / &lt;code&gt;_gfx→height()&lt;/code&gt; aufgerufen. M5GFX tauscht die Dimensionen erst nach &lt;code&gt;setRotation()&lt;/code&gt; intern um. Zusätzlich trat das Problem auf, wenn &lt;code&gt;display.begin()&lt;/code&gt; in &lt;code&gt;main.cpp&lt;/code&gt; vor &lt;code&gt;radio_init()&lt;/code&gt; aufgerufen wurde: Der idempotente Guard beim zweiten &lt;code&gt;begin()&lt;/code&gt;-Aufruf hat &lt;code&gt;setRotation(1)&lt;/code&gt; dann gar nicht mehr ausgeführt.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix in &lt;code&gt;NessoDisplayDriver.cpp&lt;/code&gt;:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// setRotation ZUERST — M5GFX tauscht Dimensionen erst danach:&lt;/span&gt;
_gfx&lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;&amp;gt;&lt;/span&gt;setRotation&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;// Jetzt korrekte Werte:&lt;/span&gt;
Serial.&lt;span class=&quot;kw3&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&amp;quot;[display] M5GFX bereit: %d x %d px&lt;span class=&quot;es1&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, _gfx&lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;&amp;gt;&lt;/span&gt;width&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;, _gfx&lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;&amp;gt;&lt;/span&gt;height&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;// Ausgabe: 240 x 135 px ✓&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 2 \u2014 Display im Portrait-Modus (135\u00d7240 statt 240\u00d7135)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_2_display_im_portrait-modus_135_240_statt_240_135&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:2,&amp;quot;secid&amp;quot;:18,&amp;quot;range&amp;quot;:&amp;quot;5214-6201&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit19&quot; id=&quot;fix_3_radio_init_failed2_durch_doppelten_boardbegin_-aufruf&quot;&gt;Fix 3 — &amp;#039;&amp;#039;radio init failed: -2&amp;#039;&amp;#039; durch doppelten board.begin()-Aufruf&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Datum:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Betroffene Datei:&lt;/strong&gt; &lt;code&gt;NessoN1Board.cpp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; &lt;code&gt;ERROR: radio init failed: -2&lt;/code&gt;, Serial zeigt &lt;code&gt;[loraReset] TIMEOUT!&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Ursache:&lt;/strong&gt; &lt;code&gt;examples/simple_repeater/main.cpp&lt;/code&gt; ruft unter &lt;code&gt;#ifdef DISPLAY_CLASS&lt;/code&gt; in &lt;code&gt;setup()&lt;/code&gt; explizit &lt;code&gt;board.begin()&lt;/code&gt; auf — &lt;strong&gt;vor&lt;/strong&gt; &lt;code&gt;radio_init()&lt;/code&gt;. Auf dem Nesso N1 führt &lt;code&gt;board.begin()&lt;/code&gt; intern &lt;code&gt;loraReset()&lt;/code&gt; aus: der SX1262 bootet, BUSY geht HIGH. Anschließend ruft &lt;code&gt;radio_init()&lt;/code&gt; erneut &lt;code&gt;board.begin()&lt;/code&gt; auf → zweites &lt;code&gt;loraReset()&lt;/code&gt; → SX1262 bootet erneut, BUSY wieder HIGH → &lt;code&gt;radio.std_init()&lt;/code&gt; trifft Chip mitten im Bootvorgang → &lt;code&gt;RADIOLIB_ERR_CHIP_NOT_FOUND&lt;/code&gt; = &lt;code&gt;-2&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix in &lt;code&gt;NessoN1Board::begin()&lt;/code&gt;:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;bool&lt;/span&gt; s_boardBeginCalled &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;s_boardBeginCalled&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    Serial.&lt;span class=&quot;me1&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&amp;quot;[board] begin() bereits initialisiert — Guard greift&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;co1&quot;&gt;// loraReset() wird NICHT nochmals ausgeführt&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
s_boardBeginCalled &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Vollständige Lösung:&lt;/strong&gt; In &lt;code&gt;main.cpp&lt;/code&gt; &lt;code&gt;board.begin()&lt;/code&gt; und &lt;code&gt;display.begin()&lt;/code&gt; aus &lt;code&gt;setup()&lt;/code&gt; entfernen — beide werden intern durch &lt;code&gt;radio_init()&lt;/code&gt; erledigt (siehe &lt;code&gt;main_cpp_setup_hinweis.txt&lt;/code&gt;).
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 3 \u2014 &amp;#039;&amp;#039;radio init failed: -2&amp;#039;&amp;#039; durch doppelten board.begin()-Aufruf&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_3_radio_init_failed2_durch_doppelten_boardbegin_-aufruf&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:3,&amp;quot;secid&amp;quot;:19,&amp;quot;range&amp;quot;:&amp;quot;6202-7450&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit20&quot; id=&quot;fix_4_apb-callback-duplikat_und_wiresetpins-warnung&quot;&gt;Fix 4 — APB-Callback-Duplikat und Wire.setPins-Warnung&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Datum:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Betroffene Dateien:&lt;/strong&gt; &lt;code&gt;NessoN1Board.cpp&lt;/code&gt;, &lt;code&gt;NessoDisplayDriver.cpp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;[E][Wire.cpp:131] setPins(): bus already initialized.
[E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=...
[E][esp32-hal-cpu.c:146] removeApbChangeCallback(): not found func=...&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Ursache:&lt;/strong&gt; &lt;code&gt;main.cpp&lt;/code&gt; ruft &lt;code&gt;display.begin()&lt;/code&gt; vor &lt;code&gt;radio_init()&lt;/code&gt; auf. M5GFX ruft intern &lt;code&gt;spi_bus_initialize(SPI2_HOST)&lt;/code&gt; und &lt;code&gt;Wire.begin()&lt;/code&gt; auf. Wenn anschließend &lt;code&gt;radio_init()&lt;/code&gt; → &lt;code&gt;board.begin()&lt;/code&gt; → &lt;code&gt;lora_spi.begin()&lt;/code&gt; läuft, versucht der ESP-IDF SPI-Treiber denselben APB-Callback erneut zu registrieren → Duplikat.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Der Board-Guard (Fix 3) verhindert den zweiten &lt;code&gt;lora_spi.begin()&lt;/code&gt;-Aufruf. Die drei &lt;code&gt;[E]&lt;/code&gt;-Zeilen sind &lt;strong&gt;funktional harmlos&lt;/strong&gt;, aber ein sichtbarer Indikator für die unvollständig behobene Aufruf-Reihenfolge.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 4 \u2014 APB-Callback-Duplikat und Wire.setPins-Warnung&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_4_apb-callback-duplikat_und_wiresetpins-warnung&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:4,&amp;quot;secid&amp;quot;:20,&amp;quot;range&amp;quot;:&amp;quot;7451-8400&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit21&quot; id=&quot;fix_5_busy-puls-timing_nach_lorareset&quot;&gt;Fix 5 — BUSY-Puls-Timing nach loraReset()&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Datum:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Betroffene Datei:&lt;/strong&gt; &lt;code&gt;NessoN1Board.cpp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; Log meldet &lt;code&gt;BUSY direkt nach NRST HIGH: LOW (unerwartet)&lt;/code&gt; obwohl Reset korrekt funktioniert und &lt;code&gt;std_init&lt;/code&gt; erfolgreich ist.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Ursache:&lt;/strong&gt; Der &lt;code&gt;delay(20)&lt;/code&gt; 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 &lt;code&gt;digitalRead()&lt;/code&gt; nach 20 ms lief.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;_exp0.&lt;span class=&quot;me1&quot;&gt;digitalWrite&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;NESSO_EXP0_SX_NRST, &lt;span class=&quot;kw2&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;co1&quot;&gt;// war: delay(20) — 2 ms reicht, BUSY-Puls auf Nesso N1 &amp;lt; 1 ms&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
Logmeldung geändert zu:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;[loraReset] BUSY 2 ms nach NRST HIGH: LOW (Chip hat BUSY-Puls bereits abgeschlossen — normal auf Nesso N1)&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 5 \u2014 BUSY-Puls-Timing nach loraReset()&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_5_busy-puls-timing_nach_lorareset&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:5,&amp;quot;secid&amp;quot;:21,&amp;quot;range&amp;quot;:&amp;quot;8401-9202&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit22&quot; id=&quot;fix_7_tasten_ohne_funktion_im_repeater-display-modus&quot;&gt;Fix 7 — Tasten ohne Funktion im Repeater-Display-Modus&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Datum:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Betroffene Dateien:&lt;/strong&gt; &lt;code&gt;simple_repeater/main.cpp&lt;/code&gt;, &lt;code&gt;simple_repeater/UITask.h&lt;/code&gt;, &lt;code&gt;simple_repeater/UITask.cpp&lt;/code&gt;, &lt;code&gt;simple_repeater/MyMesh.h&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; KEY1 und KEY2 reagieren scheinbar nicht. Im Serial-Log erscheint &lt;code&gt;[ui] KEY1 erkannt&lt;/code&gt; — die Taste wird erkannt, aber es passiert nichts am Display.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Ursache:&lt;/strong&gt; &lt;code&gt;nesso_ui_tick()&lt;/code&gt; gibt bei erkannter Taste &lt;code&gt;-1&lt;/code&gt; (KEY1) oder &lt;code&gt;-2&lt;/code&gt; (KEY2) zurück, wenn das Display bereits an ist. In &lt;code&gt;main.cpp&lt;/code&gt; war die Auswertung dieser Werte vollständig &lt;strong&gt;auskommentiert&lt;/strong&gt;. Zusätzlich hatte &lt;code&gt;UITask&lt;/code&gt; keine navigierbaren Screens und keine Verbindung zu &lt;code&gt;MyMesh&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix — drei Ebenen:&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;1. Neues Interface &lt;code&gt;UIActions.h&lt;/code&gt;&lt;/strong&gt; — entkoppelt UITask von MyMesh:
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;class&lt;/span&gt; UIActions &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;kw2&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; uiGetNeighborList&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;sy2&quot;&gt;*&lt;/span&gt; buf, &lt;span class=&quot;kw4&quot;&gt;int&lt;/span&gt; bufSize&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kw2&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; uiSendDiscover&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;2. &lt;code&gt;MyMesh&lt;/code&gt; implementiert &lt;code&gt;UIActions&lt;/code&gt;&lt;/strong&gt; — in &lt;code&gt;MyMesh.h&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;class&lt;/span&gt; MyMesh &lt;span class=&quot;sy4&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;public&lt;/span&gt; mesh&lt;span class=&quot;sy4&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;me2&quot;&gt;Mesh&lt;/span&gt;, &lt;span class=&quot;kw2&quot;&gt;public&lt;/span&gt; CommonCLICallbacks, &lt;span class=&quot;kw2&quot;&gt;public&lt;/span&gt; UIActions &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
  &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; uiGetNeighborList&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;sy2&quot;&gt;*&lt;/span&gt; buf, &lt;span class=&quot;kw4&quot;&gt;int&lt;/span&gt; bufSize&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; formatNeighborsReply&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;buf&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
  &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; uiSendDiscover&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; sendNodeDiscoverReq&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;3. &lt;code&gt;UITask&lt;/code&gt; bekommt 3 Screens + Navigation&lt;/strong&gt;, verbunden via &lt;code&gt;setActions()&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;SCREEN_HOME       — Node-Name, Frequenz, SF/BW/CR
SCREEN_NEIGHBOURS — Nachbarliste (HEX-ID, Alter, SNR)
SCREEN_POLL_SENT  — Feedback &amp;quot;Poll gesendet&amp;quot; für 2 Sek.&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;4. &lt;code&gt;main.cpp&lt;/code&gt; wertet &lt;code&gt;btn&lt;/code&gt; aus&lt;/strong&gt; (vorher auskommentiert):
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;btn &lt;span class=&quot;sy1&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; ui_task.&lt;span class=&quot;me1&quot;&gt;nextScreen&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;co1&quot;&gt;// KEY1: vorwärts / Poll&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;btn &lt;span class=&quot;sy1&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; ui_task.&lt;span class=&quot;me1&quot;&gt;prevScreen&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;co1&quot;&gt;// KEY2: zurück&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Bedienung nach dem Patch:&lt;/strong&gt;
&lt;/p&gt;
&lt;div class=&quot;table sectionedit23&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Taste &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Display AUS &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; Display AN (Home) &lt;/th&gt;&lt;th class=&quot;col3&quot;&gt; Display AN (Nachbarn) &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; KEY1 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Wakeup &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; → Nachbarn-Screen &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; → Poll senden &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; KEY2 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Wakeup &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; bleibt Home &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; → Home-Screen &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table5&amp;quot;,&amp;quot;secid&amp;quot;:23,&amp;quot;range&amp;quot;:&amp;quot;10981-11156&amp;quot;} --&gt;
&lt;p&gt;
Nach dem Poll zeigt der Screen 2 Sekunden „Poll gesendet“, dann wechselt er automatisch zurück zur aktualisierten Nachbarliste.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 7 \u2014 Tasten ohne Funktion im Repeater-Display-Modus&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_7_tasten_ohne_funktion_im_repeater-display-modus&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:7,&amp;quot;secid&amp;quot;:22,&amp;quot;range&amp;quot;:&amp;quot;9203-11287&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit24&quot; id=&quot;fix_8_tasten_nicht_erkanntwire-konflikt_zwischen_m5gfx_und_expander-treiber&quot;&gt;Fix 8 — Tasten nicht erkannt: Wire-Konflikt zwischen M5GFX und Expander-Treiber&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Datum:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Betroffene Dateien:&lt;/strong&gt; &lt;code&gt;NessoDisplayDriver.cpp&lt;/code&gt;, &lt;code&gt;NessoDisplayDriver.h&lt;/code&gt;, &lt;code&gt;platformio.ini&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; KEY1 und KEY2 werden trotz korrekter Flanken-Erkennung nicht oder unzuverlässig registriert. Im Serial-Log:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;[E][Wire.cpp:131] setPins(): bus already initialized. change pins only when not.
[E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=...&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Ursache:&lt;/strong&gt; M5GFX initialisiert den I²C-Bus intern über &lt;code&gt;WireInternal.begin(SDA, SCL)&lt;/code&gt;. Der eigene &lt;code&gt;PI4IOE5V6408&lt;/code&gt;-Treiber in &lt;code&gt;NessoN1Board&lt;/code&gt; initialisiert &lt;code&gt;Wire&lt;/code&gt; ebenfalls direkt. Beide greifen auf &lt;strong&gt;denselben Bus&lt;/strong&gt; (SDA=GPIO10, SCL=GPIO8) zu mit unterschiedlichen &lt;code&gt;TwoWire&lt;/code&gt;-Instanzen → Bus-Kollisionen. Dokumentiert im &lt;a href=&quot;https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099&quot; class=&quot;urlextern&quot; title=&quot;https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099&quot; rel=&quot;ugc nofollow&quot;&gt;Arduino Forum (November 2025)&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; &lt;code&gt;M5Unified&lt;/code&gt; übernimmt Button-Handling und Display-Init koordiniert. &lt;code&gt;M5.begin()&lt;/code&gt; initialisiert Wire, M5GFX und GPIO-Expander in der richtigen Reihenfolge.
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// NessoDisplayDriver.cpp — begin():&lt;/span&gt;
M5.&lt;span class=&quot;me1&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;cfg&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;              &lt;span class=&quot;co1&quot;&gt;// statt: _gfx-&amp;gt;begin()&lt;/span&gt;
_gfx &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt;M5.&lt;span class=&quot;me1&quot;&gt;Display&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;co1&quot;&gt;// statt: static M5GFX gfx_instance&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// checkButtons():&lt;/span&gt;
M5.&lt;span class=&quot;me1&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;M5.&lt;span class=&quot;me1&quot;&gt;BtnA&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;wasPressed&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;co1&quot;&gt;// KEY1&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;M5.&lt;span class=&quot;me1&quot;&gt;BtnB&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;wasPressed&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;co1&quot;&gt;// KEY2&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;code ini&quot;&gt;&lt;span class=&quot;co0&quot;&gt;; platformio.ini — nesso_n1_base:&lt;/span&gt;
&lt;span class=&quot;re1&quot;&gt;lib_deps&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;
  m5stack/M5GFX
  m5stack/M5Unified   ; NEU: Fix &lt;span class=&quot;nu0&quot;&gt;8&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
Entfernt: &lt;code&gt;_prevBtnState&lt;/code&gt;, &lt;code&gt;_btnReadyAt&lt;/code&gt;, &lt;code&gt;_lastBtnCheck&lt;/code&gt; — manueller Debounce entfällt, M5Unified macht Flanken-Erkennung intern.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 8 \u2014 Tasten nicht erkannt: Wire-Konflikt zwischen M5GFX und Expander-Treiber&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_8_tasten_nicht_erkanntwire-konflikt_zwischen_m5gfx_und_expander-treiber&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:11,&amp;quot;secid&amp;quot;:24,&amp;quot;range&amp;quot;:&amp;quot;11288-12967&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit25&quot; id=&quot;schnellstart&quot;&gt;Schnellstart&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Schnellstart&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;schnellstart&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:14,&amp;quot;secid&amp;quot;:25,&amp;quot;range&amp;quot;:&amp;quot;12968-12993&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit26&quot; id=&quot;voraussetzungen&quot;&gt;1. Voraussetzungen&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;a href=&quot;https://platformio.org/&quot; class=&quot;urlextern&quot; title=&quot;https://platformio.org/&quot; rel=&quot;ugc nofollow&quot;&gt;PlatformIO&lt;/a&gt; (CLI oder VS Code Extension)&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Arduino Nesso N1 per USB-C verbunden&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;1. Voraussetzungen&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;voraussetzungen&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:14,&amp;quot;secid&amp;quot;:26,&amp;quot;range&amp;quot;:&amp;quot;12994-13137&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit27&quot; id=&quot;zugangsdaten_einrichten&quot;&gt;2. Zugangsdaten einrichten&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;code bash&quot;&gt;&lt;span class=&quot;kw3&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;lt;&lt;/span&gt;projektwurzel&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;cp&lt;/span&gt; variants&lt;span class=&quot;sy0&quot;&gt;/&lt;/span&gt;arduino_nesso_n1&lt;span class=&quot;sy0&quot;&gt;/&lt;/span&gt;credentials.ini.example credentials.ini&lt;/pre&gt;

&lt;p&gt;
&lt;code&gt;credentials.ini&lt;/code&gt; anpassen:
&lt;/p&gt;
&lt;pre class=&quot;code ini&quot;&gt;&lt;span class=&quot;re0&quot;&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;credentials&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;re1&quot;&gt;build_flags_repeater&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;
  -D ADMIN_PASSWORD&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;&amp;quot;dein_passwort&amp;quot;&#039;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;re1&quot;&gt;build_flags_wifi&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;
  -D WIFI_SSID&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;&amp;quot;dein_wlan&amp;quot;&#039;&lt;/span&gt;
  -D WIFI_PWD&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;&amp;quot;dein_passwort&amp;quot;&#039;&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;div class=&quot;no&quot;&gt;
 &lt;code&gt;credentials.ini&lt;/code&gt; ist in &lt;code&gt;.gitignore&lt;/code&gt; und wird &lt;strong&gt;nicht&lt;/strong&gt; ins Repository eingecheckt.&lt;/div&gt;&lt;/blockquote&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;2. Zugangsdaten einrichten&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;zugangsdaten_einrichten&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:14,&amp;quot;secid&amp;quot;:27,&amp;quot;range&amp;quot;:&amp;quot;13138-13583&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit28&quot; id=&quot;firmware_bauen_und_flashen&quot;&gt;3. Firmware bauen und flashen&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Repeater mit Display&lt;/strong&gt; (empfohlen als Einstieg):
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;pio run &lt;span class=&quot;re5&quot;&gt;-e&lt;/span&gt; NessoN1_repeater_display &lt;span class=&quot;re5&quot;&gt;--target&lt;/span&gt; upload
pio device monitor &lt;span class=&quot;re5&quot;&gt;-b&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;115200&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Repeater ohne Display:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;pio run &lt;span class=&quot;re5&quot;&gt;-e&lt;/span&gt; NessoN1_repeater &lt;span class=&quot;re5&quot;&gt;--target&lt;/span&gt; upload&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Companion Radio — BLE:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;pio run &lt;span class=&quot;re5&quot;&gt;-e&lt;/span&gt; NessoN1_companion_ble &lt;span class=&quot;re5&quot;&gt;--target&lt;/span&gt; upload&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Companion Radio — WiFi/TCP:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;pio run &lt;span class=&quot;re5&quot;&gt;-e&lt;/span&gt; NessoN1_companion_wifi &lt;span class=&quot;re5&quot;&gt;--target&lt;/span&gt; upload&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;3. Firmware bauen und flashen&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;firmware_bauen_und_flashen&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:16,&amp;quot;secid&amp;quot;:28,&amp;quot;range&amp;quot;:&amp;quot;13584-14073&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit29&quot; id=&quot;erwartete_serial-ausgabe_beim_boot_repeater_mit_display&quot;&gt;4. Erwartete Serial-Ausgabe beim Boot (Repeater mit Display)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;code&quot;&gt;[board] begin() gestartet
[board]      I2C-Scan:
[board]        0x43  ← Expander 0 (LoRa/Keys) GEFUNDEN
[board]        0x44  ← Expander 1 (Display)   GEFUNDEN
[loraReset] BUSY 2 ms nach NRST HIGH: LOW (normal auf Nesso N1)
[loraReset] BUSY=LOW nach 0 ms — SX1262 bereit
[board] begin() abgeschlossen
[display] M5GFX bereit: 240 x 135 px (nach setRotation(1))
[display] ST7789 bereit, Backlight ein
[init] === radio_init() START ===
[init] 3/8: board.begin()
[board] begin() bereits initialisiert — Guard greift
[radio] std_init OK
[init] === radio_init() abgeschlossen — Radio bereit ===
Repeater ID: ...&lt;/pre&gt;

&lt;p&gt;
Drei &lt;code&gt;[E]&lt;/code&gt;-Zeilen (Wire.setPins, APB-Duplikat) erscheinen noch solange &lt;code&gt;main.cpp&lt;/code&gt; die falsche Aufruf-Reihenfolge hat — sie sind harmlos.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;4. Erwartete Serial-Ausgabe beim Boot (Repeater mit Display)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;erwartete_serial-ausgabe_beim_boot_repeater_mit_display&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:20,&amp;quot;secid&amp;quot;:29,&amp;quot;range&amp;quot;:&amp;quot;14074-14920&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit30&quot; id=&quot;pin-referenz&quot;&gt;Pin-Referenz&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Pin-Referenz&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;pin-referenz&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:30,&amp;quot;range&amp;quot;:&amp;quot;14921-14946&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit31&quot; id=&quot;direkte_esp32-c6_gpios&quot;&gt;Direkte ESP32-C6 GPIOs&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit32&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Funktion &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; GPIO &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa MOSI &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G21 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa MISO &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G22 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa SCK &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G20 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa CS (NSS) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G23 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa BUSY &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G19 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row6&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa IRQ (DIO1) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G15 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row7&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD CS &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G17 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row8&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD DC &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G16 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row9&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; I²C SDA &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G10 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row10&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; I²C SCL &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G8 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row11&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Touch INT &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G3 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table6&amp;quot;,&amp;quot;secid&amp;quot;:32,&amp;quot;range&amp;quot;:&amp;quot;14981-15219&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Direkte ESP32-C6 GPIOs&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;direkte_esp32-c6_gpios&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:31,&amp;quot;range&amp;quot;:&amp;quot;14947-15220&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit33&quot; id=&quot;ueber_i_c-expander_0_0x43&quot;&gt;Über I²C-Expander 0 (0x43)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit34&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Funktion &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Expander-Pin &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Taste A (KEY1) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P0 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Taste B (KEY2) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LNA Enable &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P5 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Antennen-Switch &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P6 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa Reset (NRST) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P7 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table7&amp;quot;,&amp;quot;secid&amp;quot;:34,&amp;quot;range&amp;quot;:&amp;quot;15261-15408&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;\u00dcber I\u00b2C-Expander 0 (0x43)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;ueber_i_c-expander_0_0x43&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:33,&amp;quot;range&amp;quot;:&amp;quot;15221-15409&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit35&quot; id=&quot;ueber_i_c-expander_1_0x44&quot;&gt;Über I²C-Expander 1 (0x44)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit36&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Funktion &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Expander-Pin &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD Reset &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD Backlight &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P6 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table8&amp;quot;,&amp;quot;secid&amp;quot;:36,&amp;quot;range&amp;quot;:&amp;quot;15450-15519&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;\u00dcber I\u00b2C-Expander 1 (0x44)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;ueber_i_c-expander_1_0x44&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:35,&amp;quot;range&amp;quot;:&amp;quot;15410-15520&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit37&quot; id=&quot;rf-switch-schaltlogik&quot;&gt;RF-Switch-Schaltlogik&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;div class=&quot;table sectionedit38&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Modus &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; ANT_SW &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; LNA_EN &lt;/th&gt;&lt;th class=&quot;col3&quot;&gt; Beschreibung &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; TX &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; HIGH &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; LOW &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; Sende-Pfad aktiv, LNA geschützt &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; RX &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; HIGH &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; HIGH &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; Empfangs-Pfad mit LNA aktiv &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; IDLE &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; LOW &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; LOW &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; HF-Pfad getrennt, Stromsparmodus &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table9&amp;quot;,&amp;quot;secid&amp;quot;:38,&amp;quot;range&amp;quot;:&amp;quot;15556-15760&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;RF-Switch-Schaltlogik&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;rf-switch-schaltlogik&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:37,&amp;quot;range&amp;quot;:&amp;quot;15521-15761&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit39&quot; id=&quot;architektur&quot;&gt;Architektur&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;pre class=&quot;code&quot;&gt;target.cpp
  └─ radio_init()
       ├─ board.begin()               SPI2, Wire, I²C-Scan, Expander, loraReset()
       ├─ rtc_clock.begin(Wire)
       ├─ board.onRfRx()              RF-Switch für Kalibrierung
       ├─ radio.std_init(nullptr)     kein zweites spi-&amp;gt;begin()
       ├─ radio_driver.setRfSwitchCallback(&amp;amp;board)
       └─ display.begin()             M5GFX Lazy Construction — nach std_init

NessoDisplayDriver
  ├─ begin()         static M5GFX; setRotation(1) vor width()/height()
  └─ checkButtons()  Polling KEY1/KEY2 via I²C-Expander 0 (50ms Debounce)

NessoN1Board (RfSwitchCallback)
  ├─ begin()      Guard (einmaliger Aufruf) + loraReset()
  ├─ onRfTx()     ANT_SW=HIGH, LNA_EN=LOW
  ├─ onRfRx()     ANT_SW=HIGH, LNA_EN=HIGH
  └─ onRfIdle()   ANT_SW=LOW,  LNA_EN=LOW&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Architektur&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;architektur&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:39,&amp;quot;range&amp;quot;:&amp;quot;15762-16643&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit40&quot; id=&quot;verzeichnisstruktur&quot;&gt;Verzeichnisstruktur&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;pre class=&quot;code&quot;&gt;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&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Verzeichnisstruktur&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;verzeichnisstruktur&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:22,&amp;quot;secid&amp;quot;:40,&amp;quot;range&amp;quot;:&amp;quot;16644-17754&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit41&quot; id=&quot;offene_punkte&quot;&gt;Offene Punkte&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;div class=&quot;table sectionedit42&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; # &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Thema &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; Status &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 1 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; &lt;code&gt;main.cpp&lt;/code&gt;: &lt;code&gt;board.begin()&lt;/code&gt; / &lt;code&gt;display.begin()&lt;/code&gt; vor &lt;code&gt;radio_init()&lt;/code&gt; entfernen &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Workaround aktiv (Guard) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 2 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; KEY1/KEY2 als UITask Screen-Wakeup einhängen &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; offen &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 3 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Touch FT6336U (I²C 0x38) integrieren &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; offen &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 4 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; IMU BMI270 (I²C 0x68) für Auto-Rotation &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; offen &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 5 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Akku-Monitor (I²C 0x49) für Display-Anzeige &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; offen &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table10&amp;quot;,&amp;quot;secid&amp;quot;:42,&amp;quot;range&amp;quot;:&amp;quot;17782-18160&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Offene Punkte&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;offene_punkte&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:23,&amp;quot;secid&amp;quot;:41,&amp;quot;range&amp;quot;:&amp;quot;17755-18161&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit43&quot; id=&quot;lizenz&quot;&gt;Lizenz&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
MIT-Lizenz, identisch mit MeshCore. Vollständiger Text im Wurzelverzeichnis des Repositories.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Lizenz&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;lizenz&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:23,&amp;quot;secid&amp;quot;:43,&amp;quot;range&amp;quot;:&amp;quot;18162-&amp;quot;} --&gt;
&lt;!-- cachefile /app/www/public/data/cache/3/391c1efc41692319643c43d2f641f021.xhtml used --&gt;
</description>
            <author>anonymous@undisclosed.example.com (Anonymous)</author>
            <pubDate>Tue, 21 Apr 2026 12:55:48 +0000</pubDate>
        </item>
        <item>
            <title>nesso_n1_en</title>
            <link>http://meshcore-de.fyi/weitere_hardware:nesso_n1_en</link>
            <description>
&lt;p&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; Currently in the testing phase!
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; team-nessoN1-meshcore is taking a break for health reasons. If you’d like, you can contact him via email at — &lt;em&gt;&lt;a href=&quot;mailto:&amp;#64;&amp;#116;&amp;#101;&amp;#97;&amp;#109;&amp;#45;&amp;#110;&amp;#101;&amp;#115;&amp;#115;&amp;#111;&amp;#78;&amp;#49;&amp;#45;&amp;#109;&amp;#101;&amp;#115;&amp;#104;&amp;#99;&amp;#111;&amp;#114;&amp;#101;&amp;#64;&amp;#112;&amp;#111;&amp;#115;&amp;#116;&amp;#101;&amp;#111;&amp;#46;&amp;#100;&amp;#101;&amp;#64;&quot; class=&quot;mail&quot; title=&quot;&amp;#64;&amp;#116;&amp;#101;&amp;#97;&amp;#109;&amp;#45;&amp;#110;&amp;#101;&amp;#115;&amp;#115;&amp;#111;&amp;#78;&amp;#49;&amp;#45;&amp;#109;&amp;#101;&amp;#115;&amp;#104;&amp;#99;&amp;#111;&amp;#114;&amp;#101;&amp;#64;&amp;#112;&amp;#111;&amp;#115;&amp;#116;&amp;#101;&amp;#111;&amp;#46;&amp;#100;&amp;#101;&amp;#64;&quot;&gt;team-nessoN1-meshcore&lt;/a&gt;&lt;/em&gt; for details on handing over the project.
&lt;/p&gt;

&lt;h1 class=&quot;sectionedit1&quot; id=&quot;meshcore_arduino_nesso_n1_esp32-c6&quot;&gt;MeshCore — Arduino Nesso N1 (ESP32-C6)&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Author:&lt;/strong&gt; team-nessoN1-meshcore — team-nessoN1-meshcore@posteo.de&lt;br/&gt;

&lt;strong&gt;Date:&lt;/strong&gt; April 2026
&lt;/p&gt;

&lt;p&gt;
This page describes the Hardware Abstraction Layer (HAL) for the &lt;strong&gt;Arduino Nesso N1&lt;/strong&gt; as a MeshCore target platform. The board was co-developed by Arduino and M5Stack, combining an ESP32-C6 microcontroller with an SX1262 LoRa transceiver, Wi-Fi 6, Bluetooth 5.3, Thread/Zigbee, and a 1.14″ touchscreen in a compact, battery-powered enclosure.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;MeshCore \u2014 Arduino Nesso N1 (ESP32-C6)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;meshcore_arduino_nesso_n1_esp32-c6&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:1,&amp;quot;range&amp;quot;:&amp;quot;274-769&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit2&quot; id=&quot;hardware_overview&quot;&gt;Hardware Overview&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;div class=&quot;table sectionedit3&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Component &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Details &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; MCU &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Espressif ESP32-C6 (RISC-V, 160 &lt;abbr title=&quot;Megahertz&quot;&gt;MHz&lt;/abbr&gt;) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Flash &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 16 &lt;abbr title=&quot;Megabyte&quot;&gt;MB&lt;/abbr&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; RAM &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 512 KB &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Semtech SX1262, 850–960 &lt;abbr title=&quot;Megahertz&quot;&gt;MHz&lt;/abbr&gt;, up to +22 dBm &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; RF Switch / LNA &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; External, controlled via I²C GPIO expander &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row6&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; I²C GPIO Expander &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; PI4IOE5V6408 (2× instances, addresses 0x43 and 0x44) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row7&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Display &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; ST7789P3, 1.14″, 240×135 px, touchscreen (FT6336U) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row8&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; IMU &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; BMI270 (6-axis) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row9&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Battery &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 250 mAh LiPo, USB-C charging &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row10&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Connectivity &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Wi-Fi 6, BT 5.3, Thread/Zigbee (802.15.4), LoRa &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;secid&amp;quot;:3,&amp;quot;range&amp;quot;:&amp;quot;801-1311&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Hardware Overview&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;hardware_overview&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:2,&amp;quot;range&amp;quot;:&amp;quot;770-1312&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit4&quot; id=&quot;key_porting_decisions&quot;&gt;Key Porting Decisions&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Key Porting Decisions&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;key_porting_decisions&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:4,&amp;quot;range&amp;quot;:&amp;quot;1313-1347&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit5&quot; id=&quot;sx1262_reset_and_rf_switch_via_i_c_expander&quot;&gt;SX1262 Reset and RF Switch via I²C Expander&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
Unlike most other MeshCore targets, the LoRa control lines on the Nesso N1 are not connected directly to ESP32-C6 GPIO pins. They are routed through a &lt;strong&gt;PI4IOE5V6408 I²C GPIO expander&lt;/strong&gt; (address 0x43):
&lt;/p&gt;
&lt;div class=&quot;table sectionedit6&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Signal &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Expander Pin &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; Function &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; SX_NRST &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P7 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; SX1262 hardware reset &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; SX_ANT_SW &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P6 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Antenna RF switch &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; SX_LNA_EN &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P5 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Low-noise amplifier enable &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; KEY1 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P0 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Button A (input) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; KEY2 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P1 &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; Button B (input) &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table1&amp;quot;,&amp;quot;secid&amp;quot;:6,&amp;quot;range&amp;quot;:&amp;quot;1608-1838&amp;quot;} --&gt;
&lt;p&gt;
RadioLib&amp;#039;s &lt;code&gt;setRfSwitchTable()&lt;/code&gt; (direct GPIO only) cannot be used. &lt;code&gt;NessoN1Board&lt;/code&gt; implements the &lt;code&gt;RfSwitchCallback&lt;/code&gt; interface instead, which &lt;code&gt;CustomSX1262Wrapper&lt;/code&gt; calls on every TX/RX transition.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;SX1262 Reset and RF Switch via I\u00b2C Expander&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;sx1262_reset_and_rf_switch_via_i_c_expander&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:5,&amp;quot;range&amp;quot;:&amp;quot;1348-2044&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit7&quot; id=&quot;shared_spi_bus_sx1262_st7789&quot;&gt;Shared SPI Bus (SX1262 + ST7789)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit8&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Signal &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; GPIO &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; MOSI &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G21 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; MISO &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G22 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; SCK &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G20 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa CS (NSS) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G23 (software CS) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD CS &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G17 (software CS) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row6&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD DC &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G16 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table2&amp;quot;,&amp;quot;secid&amp;quot;:8,&amp;quot;range&amp;quot;:&amp;quot;2089-2236&amp;quot;} --&gt;
&lt;p&gt;
&lt;code&gt;lora_spi.begin()&lt;/code&gt; is called &lt;strong&gt;without the NSS argument&lt;/strong&gt; to avoid registering a duplicate APB hardware CS-callback (see Fix 4).
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Shared SPI Bus (SX1262 + ST7789)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;shared_spi_bus_sx1262_st7789&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:7,&amp;quot;range&amp;quot;:&amp;quot;2045-2369&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit9&quot; id=&quot;fspi_instead_of_default_spi&quot;&gt;FSPI instead of default SPI&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
The ESP32-C6 has no VSPI bus: &lt;code&gt;SPIClass lora_spi(FSPI)&lt;/code&gt;.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;FSPI instead of default SPI&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fspi_instead_of_default_spi&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:9,&amp;quot;range&amp;quot;:&amp;quot;2370-2468&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit10&quot; id=&quot;usb-cdc_and_ble_are_mutually_exclusive&quot;&gt;USB-CDC and BLE are mutually exclusive&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit11&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Firmware &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; &lt;code&gt;ARDUINO_USB_CDC_ON_BOOT&lt;/code&gt; &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; Debug output &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Repeater &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; &lt;code&gt;1&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; USB-Serial active &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Companion BLE &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; &lt;code&gt;0&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; no USB-Serial &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Companion WiFi &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; &lt;code&gt;0&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; no USB-Serial &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table3&amp;quot;,&amp;quot;secid&amp;quot;:11,&amp;quot;range&amp;quot;:&amp;quot;2519-2702&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;USB-CDC and BLE are mutually exclusive&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;usb-cdc_and_ble_are_mutually_exclusive&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:10,&amp;quot;range&amp;quot;:&amp;quot;2469-2703&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit12&quot; id=&quot;display_architecture&quot;&gt;Display Architecture&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Display Architecture&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;display_architecture&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:12,&amp;quot;range&amp;quot;:&amp;quot;2704-2737&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit13&quot; id=&quot;resolution_and_uitask_layout_verification&quot;&gt;Resolution and UITask Layout Verification&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
The ST7789P3 has &lt;strong&gt;240×135 pixels&lt;/strong&gt; (Landscape, &lt;code&gt;setRotation(1)&lt;/code&gt;). All UITask default layouts fit without overflow:
&lt;/p&gt;
&lt;div class=&quot;table sectionedit14&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Element &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Width &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; x (centred) &lt;/th&gt;&lt;th class=&quot;col3&quot;&gt; Right edge &lt;/th&gt;&lt;th class=&quot;col4&quot;&gt; Fits &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; MeshCore logo (64×36 px XBM) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 64 px &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; 88 &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; 152 &lt;/td&gt;&lt;td class=&quot;col4&quot;&gt; ✅ &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Version line (setTextSize 2) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 156 px &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; 42 &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; 198 &lt;/td&gt;&lt;td class=&quot;col4&quot;&gt; ✅ &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Node name „NessoN1 Repeater“ &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 192 px &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; 24 &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; 216 &lt;/td&gt;&lt;td class=&quot;col4&quot;&gt; ✅ &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Frequency line „869.6 SF8 BW62.5“ &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; 204 px &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; 18 &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; 222 &lt;/td&gt;&lt;td class=&quot;col4&quot;&gt; ✅ &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table4&amp;quot;,&amp;quot;secid&amp;quot;:14,&amp;quot;range&amp;quot;:&amp;quot;2911-3205&amp;quot;} --&gt;
&lt;p&gt;
All four elements together occupy ~100 px of 135 px height — no vertical overflow.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Resolution and UITask Layout Verification&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;resolution_and_uitask_layout_verification&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:13,&amp;quot;range&amp;quot;:&amp;quot;2738-3292&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit15&quot; id=&quot;mandatory_initialisation_order&quot;&gt;Mandatory Initialisation Order&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;code&quot;&gt;radio_init() in target.cpp:
  1. board.begin()           SPI2, Wire, expanders, loraReset()
  2. board.onRfRx()          RF switch active for calibration
  3. radio.std_init(nullptr) RadioLib — nullptr: no second spi-&amp;gt;begin()
  4. display.begin()         M5GFX lazy construction — must follow std_init!&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Mandatory Initialisation Order&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;mandatory_initialisation_order&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:15,&amp;quot;range&amp;quot;:&amp;quot;3293-3657&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit16&quot; id=&quot;known_issues_and_their_fixes&quot;&gt;Known Issues and Their Fixes&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Known Issues and Their Fixes&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;known_issues_and_their_fixes&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:1,&amp;quot;secid&amp;quot;:16,&amp;quot;range&amp;quot;:&amp;quot;3658-3699&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit17&quot; id=&quot;fix_1_display_goes_black_after_a_few_seconds&quot;&gt;Fix 1 — Display Goes Black After a Few Seconds&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Date:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Affected file:&lt;/strong&gt; &lt;code&gt;platformio.ini&lt;/code&gt;, &lt;code&gt;[env:NessoN1_repeater_display]&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; Display shows boot screen (~4 s) and home screen (~10 s), then stays permanently black. Button presses have no effect.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; &lt;code&gt;UITask.h&lt;/code&gt; (MeshCore, &lt;code&gt;examples/simple_repeater/UITask.h&lt;/code&gt;) defines &lt;code&gt;SCREEN_TIMEOUT&lt;/code&gt; (default: 10 000 ms). After expiry it calls &lt;code&gt;display.turnOff()&lt;/code&gt;. The wakeup path in UITask polls &lt;code&gt;PIN_USER_BTN&lt;/code&gt; — a direct GPIO pin. On the Nesso N1, KEY1 and KEY2 are connected &lt;strong&gt;via I²C expander 0&lt;/strong&gt; (address 0x43, pins P0/P1) and are &lt;strong&gt;not direct GPIOs&lt;/strong&gt;. UITask therefore has &lt;strong&gt;no wakeup path&lt;/strong&gt; — once the timeout fires, the display stays off permanently.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code ini&quot;&gt;&lt;span class=&quot;co0&quot;&gt;; platformio.ini — [env:NessoN1_repeater_display]:&lt;/span&gt;
-D SCREEN_TIMEOUT&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;re2&quot;&gt;0&lt;/span&gt;
-D DISPLAY_TIMEOUT&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;re2&quot;&gt;0&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
Both flags set to 0 disable the automatic timeout entirely. &lt;code&gt;DISPLAY_TIMEOUT&lt;/code&gt; is also set because different UITask versions use different macro names.
&lt;/p&gt;
&lt;blockquote&gt;&lt;div class=&quot;no&quot;&gt;
 &lt;strong&gt;Note for battery operation:&lt;/strong&gt; Use e.g. &lt;code&gt;-D SCREEN_TIMEOUT=30000&lt;/code&gt;. Button wakeup is already integrated via &lt;code&gt;nesso_ui_tick()&lt;/code&gt; (see Fix 7).&lt;/div&gt;&lt;/blockquote&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 1 \u2014 Display Goes Black After a Few Seconds&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_1_display_goes_black_after_a_few_seconds&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:1,&amp;quot;secid&amp;quot;:17,&amp;quot;range&amp;quot;:&amp;quot;3700-4888&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit18&quot; id=&quot;fix_2_display_in_portrait_mode_135_240_instead_of_240_135&quot;&gt;Fix 2 — Display in Portrait Mode (135×240 Instead of 240×135)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Date:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Affected file:&lt;/strong&gt; &lt;code&gt;NessoDisplayDriver.cpp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; Serial reports &lt;code&gt;M5GFX reports display: 135 x 240 px&lt;/code&gt;. UITask text is clipped with a negative x-offset and is not readable.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; &lt;code&gt;setRotation(1)&lt;/code&gt; was called &lt;strong&gt;after&lt;/strong&gt; querying &lt;code&gt;width()&lt;/code&gt; and &lt;code&gt;height()&lt;/code&gt;. M5GFX swaps dimensions only after &lt;code&gt;setRotation()&lt;/code&gt;, so the pre-rotation query always returned 135×240. The problem also occurred when &lt;code&gt;display.begin()&lt;/code&gt; ran before &lt;code&gt;radio_init()&lt;/code&gt; from &lt;code&gt;main.cpp&lt;/code&gt;: the idempotent guard on the second &lt;code&gt;begin()&lt;/code&gt; call skipped &lt;code&gt;setRotation(1)&lt;/code&gt; entirely.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix in &lt;code&gt;NessoDisplayDriver.cpp&lt;/code&gt;:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;_gfx&lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;&amp;gt;&lt;/span&gt;setRotation&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;co1&quot;&gt;// FIRST — M5GFX swaps dimensions only after this&lt;/span&gt;
Serial.&lt;span class=&quot;kw3&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&amp;quot;[display] M5GFX ready: %d x %d px&lt;span class=&quot;es1&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;,
    _gfx&lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;&amp;gt;&lt;/span&gt;width&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;, _gfx&lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;&amp;gt;&lt;/span&gt;height&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;co1&quot;&gt;// now correctly 240 x 135&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 2 \u2014 Display in Portrait Mode (135\u00d7240 Instead of 240\u00d7135)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_2_display_in_portrait_mode_135_240_instead_of_240_135&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:2,&amp;quot;secid&amp;quot;:18,&amp;quot;range&amp;quot;:&amp;quot;4889-5813&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit19&quot; id=&quot;fix_3_radio_init_failed2_from_double_boardbegin_call&quot;&gt;Fix 3 — &amp;#039;&amp;#039;radio init failed: -2&amp;#039;&amp;#039; from Double board.begin() Call&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Date:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Affected file:&lt;/strong&gt; &lt;code&gt;NessoN1Board.cpp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; &lt;code&gt;ERROR: radio init failed: -2&lt;/code&gt;, serial shows &lt;code&gt;[loraReset] TIMEOUT!&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; &lt;code&gt;examples/simple_repeater/main.cpp&lt;/code&gt; calls &lt;code&gt;board.begin()&lt;/code&gt; in &lt;code&gt;setup()&lt;/code&gt; under &lt;code&gt;#ifdef DISPLAY_CLASS&lt;/code&gt; — &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;radio_init()&lt;/code&gt;. On the Nesso N1, &lt;code&gt;board.begin()&lt;/code&gt; calls &lt;code&gt;loraReset()&lt;/code&gt;: SX1262 boots, BUSY goes HIGH. Then &lt;code&gt;radio_init()&lt;/code&gt; calls &lt;code&gt;board.begin()&lt;/code&gt; again — second &lt;code&gt;loraReset()&lt;/code&gt; — SX1262 boots again, BUSY HIGH again — &lt;code&gt;radio.std_init()&lt;/code&gt; hits the chip during boot — &lt;code&gt;RADIOLIB_ERR_CHIP_NOT_FOUND&lt;/code&gt; = &lt;code&gt;-2&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix in &lt;code&gt;NessoN1Board::begin()&lt;/code&gt;:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;bool&lt;/span&gt; s_boardBeginCalled &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;s_boardBeginCalled&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    Serial.&lt;span class=&quot;me1&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&amp;quot;[board] begin() already initialised — guard active&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;co1&quot;&gt;// loraReset() is NOT called again&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
s_boardBeginCalled &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Complete solution:&lt;/strong&gt; Remove &lt;code&gt;board.begin()&lt;/code&gt; and &lt;code&gt;display.begin()&lt;/code&gt; from &lt;code&gt;setup()&lt;/code&gt; in &lt;code&gt;main.cpp&lt;/code&gt; (see &lt;code&gt;main_cpp_setup_hinweis.txt&lt;/code&gt;).
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 3 \u2014 &amp;#039;&amp;#039;radio init failed: -2&amp;#039;&amp;#039; from Double board.begin() Call&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_3_radio_init_failed2_from_double_boardbegin_call&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:3,&amp;quot;secid&amp;quot;:19,&amp;quot;range&amp;quot;:&amp;quot;5814-6926&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit20&quot; id=&quot;fix_4_apb_callback_duplicate_and_wiresetpins_warning&quot;&gt;Fix 4 — APB Callback Duplicate and Wire.setPins Warning&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Date:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Affected files:&lt;/strong&gt; &lt;code&gt;NessoN1Board.cpp&lt;/code&gt;, &lt;code&gt;NessoDisplayDriver.cpp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;[E][Wire.cpp:131] setPins(): bus already initialized.
[E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=...
[E][esp32-hal-cpu.c:146] removeApbChangeCallback(): not found func=...&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; &lt;code&gt;main.cpp&lt;/code&gt; calls &lt;code&gt;display.begin()&lt;/code&gt; before &lt;code&gt;radio_init()&lt;/code&gt;. M5GFX calls &lt;code&gt;spi_bus_initialize(SPI2_HOST)&lt;/code&gt; and &lt;code&gt;Wire.begin()&lt;/code&gt; internally. When &lt;code&gt;radio_init()&lt;/code&gt; → &lt;code&gt;board.begin()&lt;/code&gt; → &lt;code&gt;lora_spi.begin()&lt;/code&gt; runs afterwards, the ESP-IDF SPI driver tries to register the same APB callback again → &lt;code&gt;duplicate&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; The board guard (Fix 3) prevents the second &lt;code&gt;lora_spi.begin()&lt;/code&gt; call. The three &lt;code&gt;[E]&lt;/code&gt; lines are &lt;strong&gt;functionally harmless&lt;/strong&gt; but remain visible while &lt;code&gt;main.cpp&lt;/code&gt; retains the wrong call order.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 4 \u2014 APB Callback Duplicate and Wire.setPins Warning&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_4_apb_callback_duplicate_and_wiresetpins_warning&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:4,&amp;quot;secid&amp;quot;:20,&amp;quot;range&amp;quot;:&amp;quot;6927-7847&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit21&quot; id=&quot;fix_5_busy_pulse_timing_after_lorareset&quot;&gt;Fix 5 — BUSY Pulse Timing After loraReset()&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Date:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Affected file:&lt;/strong&gt; &lt;code&gt;NessoN1Board.cpp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; Log reports &lt;code&gt;BUSY immediately after NRST HIGH: LOW (unexpected)&lt;/code&gt; even though &lt;code&gt;std_init&lt;/code&gt; succeeds.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; &lt;code&gt;delay(20)&lt;/code&gt; after NRST HIGH was too long. The SX1262 on the Nesso N1 produces a BUSY-HIGH pulse of less than 1 ms after reset — already LOW by the time &lt;code&gt;digitalRead()&lt;/code&gt; ran after 20 ms. No hardware fault, just overly conservative timing.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;_exp0.&lt;span class=&quot;me1&quot;&gt;digitalWrite&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;NESSO_EXP0_SX_NRST, &lt;span class=&quot;kw2&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;co1&quot;&gt;// was: delay(20) — 2 ms sufficient, BUSY pulse on Nesso N1 &amp;lt; 1 ms&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
Updated log message:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;[loraReset] BUSY 2 ms after NRST HIGH: LOW (pulse complete — normal on Nesso N1)&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 5 \u2014 BUSY Pulse Timing After loraReset()&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_5_busy_pulse_timing_after_lorareset&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:5,&amp;quot;secid&amp;quot;:21,&amp;quot;range&amp;quot;:&amp;quot;7848-8620&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit22&quot; id=&quot;fix_7_buttons_non-functional_in_repeater_display_mode&quot;&gt;Fix 7 — Buttons Non-Functional in Repeater Display Mode&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Date:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Affected files:&lt;/strong&gt; &lt;code&gt;simple_repeater/main.cpp&lt;/code&gt;, &lt;code&gt;simple_repeater/UITask.h&lt;/code&gt;, &lt;code&gt;simple_repeater/UITask.cpp&lt;/code&gt;, &lt;code&gt;simple_repeater/MyMesh.h&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; KEY1 and KEY2 appear to do nothing. Serial log shows &lt;code&gt;[ui] KEY1 erkannt&lt;/code&gt; — the keypress is detected, but the display does not change.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; &lt;code&gt;nesso_ui_tick()&lt;/code&gt; correctly returns &lt;code&gt;-1&lt;/code&gt; (KEY1) or &lt;code&gt;-2&lt;/code&gt; (KEY2) when the display is already on. In &lt;code&gt;main.cpp&lt;/code&gt;, evaluation of these return values was entirely &lt;strong&gt;commented out&lt;/strong&gt;. Additionally, &lt;code&gt;UITask&lt;/code&gt; had no navigable screens and no connection to &lt;code&gt;MyMesh&lt;/code&gt; to fetch neighbour data or send a discover request.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix — three levels:&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;1. New interface &lt;code&gt;UIActions.h&lt;/code&gt;&lt;/strong&gt; — decouples UITask from MyMesh:
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;class&lt;/span&gt; UIActions &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;kw2&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; uiGetNeighborList&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;sy2&quot;&gt;*&lt;/span&gt; buf, &lt;span class=&quot;kw4&quot;&gt;int&lt;/span&gt; bufSize&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kw2&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; uiSendDiscover&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;2. &lt;code&gt;MyMesh&lt;/code&gt; implements &lt;code&gt;UIActions&lt;/code&gt;&lt;/strong&gt; — in &lt;code&gt;MyMesh.h&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;class&lt;/span&gt; MyMesh &lt;span class=&quot;sy4&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;public&lt;/span&gt; mesh&lt;span class=&quot;sy4&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;me2&quot;&gt;Mesh&lt;/span&gt;, &lt;span class=&quot;kw2&quot;&gt;public&lt;/span&gt; CommonCLICallbacks, &lt;span class=&quot;kw2&quot;&gt;public&lt;/span&gt; UIActions &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
  &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; uiGetNeighborList&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;sy2&quot;&gt;*&lt;/span&gt; buf, &lt;span class=&quot;kw4&quot;&gt;int&lt;/span&gt; bufSize&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; formatNeighborsReply&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;buf&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
  &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; uiSendDiscover&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; sendNodeDiscoverReq&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;3. &lt;code&gt;UITask&lt;/code&gt; gains 3 screens + navigation&lt;/strong&gt;, connected via &lt;code&gt;setActions()&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;SCREEN_HOME       — node name, frequency, SF/BW/CR
SCREEN_NEIGHBOURS — neighbour list (hex ID, age, SNR)
SCREEN_POLL_SENT  — &amp;quot;Poll sent&amp;quot; feedback for 2 seconds&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;4. &lt;code&gt;main.cpp&lt;/code&gt; evaluates &lt;code&gt;btn&lt;/code&gt;&lt;/strong&gt; (previously commented out):
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;btn &lt;span class=&quot;sy1&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; ui_task.&lt;span class=&quot;me1&quot;&gt;nextScreen&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;co1&quot;&gt;// KEY1: forward / poll&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;btn &lt;span class=&quot;sy1&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sy2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; ui_task.&lt;span class=&quot;me1&quot;&gt;prevScreen&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;co1&quot;&gt;// KEY2: back&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Button behaviour after patch:&lt;/strong&gt;
&lt;/p&gt;
&lt;div class=&quot;table sectionedit23&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Button &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Display OFF &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; Display ON (Home) &lt;/th&gt;&lt;th class=&quot;col3&quot;&gt; Display ON (Neighbours) &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; KEY1 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Wakeup &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; → Neighbours screen &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; → Send poll &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; KEY2 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Wakeup &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; stays Home &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; → Home screen &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table5&amp;quot;,&amp;quot;secid&amp;quot;:23,&amp;quot;range&amp;quot;:&amp;quot;10403-10580&amp;quot;} --&gt;
&lt;p&gt;
After sending a poll, the screen shows „Poll sent“ for 2 seconds, then automatically returns to the refreshed neighbour list.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 7 \u2014 Buttons Non-Functional in Repeater Display Mode&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_7_buttons_non-functional_in_repeater_display_mode&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:7,&amp;quot;secid&amp;quot;:22,&amp;quot;range&amp;quot;:&amp;quot;8621-10708&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit24&quot; id=&quot;fix_8_buttons_not_recognisedwire_conflict_between_m5gfx_and_expander_driver&quot;&gt;Fix 8 — Buttons Not Recognised: Wire Conflict Between M5GFX and Expander Driver&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Date:&lt;/strong&gt; April 2026&lt;br/&gt;

&lt;strong&gt;Affected files:&lt;/strong&gt; &lt;code&gt;NessoDisplayDriver.cpp&lt;/code&gt;, &lt;code&gt;NessoDisplayDriver.h&lt;/code&gt;, &lt;code&gt;platformio.ini&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Symptom:&lt;/strong&gt; KEY1 and KEY2 are not reliably registered despite correct edge detection and boot lock. Serial log shows:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;[E][Wire.cpp:131] setPins(): bus already initialized. change pins only when not.
[E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=...&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; M5GFX initialises the I²C bus internally via &lt;code&gt;WireInternal.begin(SDA, SCL)&lt;/code&gt;. The custom &lt;code&gt;PI4IOE5V6408&lt;/code&gt; driver in &lt;code&gt;NessoN1Board&lt;/code&gt; also initialises &lt;code&gt;Wire&lt;/code&gt; directly. Both access the &lt;strong&gt;same bus&lt;/strong&gt; (SDA=GPIO10, SCL=GPIO8) with different &lt;code&gt;TwoWire&lt;/code&gt; instances, causing bus collisions and unstable expander reads. Documented in the &lt;a href=&quot;https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099&quot; class=&quot;urlextern&quot; title=&quot;https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099&quot; rel=&quot;ugc nofollow&quot;&gt;Arduino Forum (November 2025)&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; &lt;code&gt;M5Unified&lt;/code&gt; takes over button handling and display initialisation in a coordinated way. &lt;code&gt;M5.begin()&lt;/code&gt; initialises Wire, M5GFX and the GPIO expander in the correct order — no more Wire conflict.
&lt;/p&gt;
&lt;pre class=&quot;code cpp&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// NessoDisplayDriver.cpp — begin():&lt;/span&gt;
M5.&lt;span class=&quot;me1&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;cfg&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;              &lt;span class=&quot;co1&quot;&gt;// instead of: _gfx-&amp;gt;begin()&lt;/span&gt;
_gfx &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt;M5.&lt;span class=&quot;me1&quot;&gt;Display&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;co1&quot;&gt;// instead of: static M5GFX gfx_instance&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// checkButtons():&lt;/span&gt;
M5.&lt;span class=&quot;me1&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;M5.&lt;span class=&quot;me1&quot;&gt;BtnA&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;wasPressed&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;co1&quot;&gt;// KEY1&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;M5.&lt;span class=&quot;me1&quot;&gt;BtnB&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;wasPressed&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;sy4&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;co1&quot;&gt;// KEY2&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;code ini&quot;&gt;&lt;span class=&quot;co0&quot;&gt;; platformio.ini — nesso_n1_base:&lt;/span&gt;
&lt;span class=&quot;re1&quot;&gt;lib_deps&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;
  m5stack/M5GFX
  m5stack/M5Unified   ; NEW: Fix &lt;span class=&quot;nu0&quot;&gt;8&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
Removed: &lt;code&gt;_prevBtnState&lt;/code&gt;, &lt;code&gt;_btnReadyAt&lt;/code&gt;, &lt;code&gt;_lastBtnCheck&lt;/code&gt; — manual debounce is no longer needed; M5Unified handles edge detection internally.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Fix 8 \u2014 Buttons Not Recognised: Wire Conflict Between M5GFX and Expander Driver&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;fix_8_buttons_not_recognisedwire_conflict_between_m5gfx_and_expander_driver&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:11,&amp;quot;secid&amp;quot;:24,&amp;quot;range&amp;quot;:&amp;quot;10709-12452&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit25&quot; id=&quot;quick_start&quot;&gt;Quick Start&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Quick Start&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;quick_start&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:14,&amp;quot;secid&amp;quot;:25,&amp;quot;range&amp;quot;:&amp;quot;12453-12477&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit26&quot; id=&quot;prerequisites&quot;&gt;1. Prerequisites&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;a href=&quot;https://platformio.org/&quot; class=&quot;urlextern&quot; title=&quot;https://platformio.org/&quot; rel=&quot;ugc nofollow&quot;&gt;PlatformIO&lt;/a&gt; (CLI or VS Code extension)&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Arduino Nesso N1 connected via USB-C&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;1. Prerequisites&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;prerequisites&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:14,&amp;quot;secid&amp;quot;:26,&amp;quot;range&amp;quot;:&amp;quot;12478-12617&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit27&quot; id=&quot;set_up_credentials&quot;&gt;2. Set up credentials&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;code bash&quot;&gt;&lt;span class=&quot;kw3&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;lt;&lt;/span&gt;project root&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;cp&lt;/span&gt; variants&lt;span class=&quot;sy0&quot;&gt;/&lt;/span&gt;arduino_nesso_n1&lt;span class=&quot;sy0&quot;&gt;/&lt;/span&gt;credentials.ini.example credentials.ini&lt;/pre&gt;

&lt;p&gt;
Edit &lt;code&gt;credentials.ini&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;code ini&quot;&gt;&lt;span class=&quot;re0&quot;&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;credentials&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;re1&quot;&gt;build_flags_repeater&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;
  -D ADMIN_PASSWORD&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;&amp;quot;your_password&amp;quot;&#039;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;re1&quot;&gt;build_flags_wifi&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;
  -D WIFI_SSID&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;&amp;quot;your_network&amp;quot;&#039;&lt;/span&gt;
  -D WIFI_PWD&lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;&amp;quot;your_password&amp;quot;&#039;&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;div class=&quot;no&quot;&gt;
 &lt;code&gt;credentials.ini&lt;/code&gt; is listed in &lt;code&gt;.gitignore&lt;/code&gt; and will &lt;strong&gt;not&lt;/strong&gt; be committed to the repository.&lt;/div&gt;&lt;/blockquote&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;2. Set up credentials&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;set_up_credentials&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:14,&amp;quot;secid&amp;quot;:27,&amp;quot;range&amp;quot;:&amp;quot;12618-13064&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit28&quot; id=&quot;build_and_flash&quot;&gt;3. Build and flash&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
&lt;strong&gt;Repeater with display&lt;/strong&gt; (recommended starting point):
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;pio run &lt;span class=&quot;re5&quot;&gt;-e&lt;/span&gt; NessoN1_repeater_display &lt;span class=&quot;re5&quot;&gt;--target&lt;/span&gt; upload
pio device monitor &lt;span class=&quot;re5&quot;&gt;-b&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;115200&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Repeater without display:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;pio run &lt;span class=&quot;re5&quot;&gt;-e&lt;/span&gt; NessoN1_repeater &lt;span class=&quot;re5&quot;&gt;--target&lt;/span&gt; upload&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Companion Radio — BLE:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;pio run &lt;span class=&quot;re5&quot;&gt;-e&lt;/span&gt; NessoN1_companion_ble &lt;span class=&quot;re5&quot;&gt;--target&lt;/span&gt; upload&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Companion Radio — WiFi/TCP:&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;pio run &lt;span class=&quot;re5&quot;&gt;-e&lt;/span&gt; NessoN1_companion_wifi &lt;span class=&quot;re5&quot;&gt;--target&lt;/span&gt; upload&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;3. Build and flash&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;build_and_flash&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:16,&amp;quot;secid&amp;quot;:28,&amp;quot;range&amp;quot;:&amp;quot;13065-13551&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit29&quot; id=&quot;expected_serial_output_repeater_with_display&quot;&gt;4. Expected serial output (repeater with display)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;code&quot;&gt;[loraReset] BUSY 2 ms after NRST HIGH: LOW (normal on Nesso N1)
[loraReset] BUSY=LOW after 0 ms — SX1262 ready
[display] M5GFX ready: 240 x 135 px (after setRotation(1))
[display] ST7789 ready, backlight on
[board] begin() already initialised — guard active
[radio] std_init OK
[init] === radio_init() complete — radio ready ===&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;4. Expected serial output (repeater with display)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;expected_serial_output_repeater_with_display&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:20,&amp;quot;secid&amp;quot;:29,&amp;quot;range&amp;quot;:&amp;quot;13552-13963&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit30&quot; id=&quot;pin_reference&quot;&gt;Pin Reference&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Pin Reference&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;pin_reference&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:30,&amp;quot;range&amp;quot;:&amp;quot;13964-13990&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit31&quot; id=&quot;direct_esp32-c6_gpios&quot;&gt;Direct ESP32-C6 GPIOs&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit32&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Function &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; GPIO &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa MOSI &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G21 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa MISO &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G22 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa SCK &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G20 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa CS (NSS) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G23 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa BUSY &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G19 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row6&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa IRQ (DIO1) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G15 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row7&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD CS &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G17 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row8&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD DC &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G16 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row9&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; I²C SDA &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G10 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row10&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; I²C SCL &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G8 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row11&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Touch INT &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; G3 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table6&amp;quot;,&amp;quot;secid&amp;quot;:32,&amp;quot;range&amp;quot;:&amp;quot;14024-14262&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Direct ESP32-C6 GPIOs&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;direct_esp32-c6_gpios&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:31,&amp;quot;range&amp;quot;:&amp;quot;13991-14263&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit33&quot; id=&quot;via_i_c_expander_0_0x43&quot;&gt;Via I²C Expander 0 (0x43)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit34&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Function &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Expander Pin &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Button A (KEY1) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P0 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Button B (KEY2) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LNA Enable &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P5 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; Antenna Switch &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P6 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LoRa Reset (NRST) &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P7 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table7&amp;quot;,&amp;quot;secid&amp;quot;:34,&amp;quot;range&amp;quot;:&amp;quot;14302-14450&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Via I\u00b2C Expander 0 (0x43)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;via_i_c_expander_0_0x43&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:33,&amp;quot;range&amp;quot;:&amp;quot;14264-14451&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit35&quot; id=&quot;via_i_c_expander_1_0x44&quot;&gt;Via I²C Expander 1 (0x44)&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;div class=&quot;table sectionedit36&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Function &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Expander Pin &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD Reset &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; LCD Backlight &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; P6 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table8&amp;quot;,&amp;quot;secid&amp;quot;:36,&amp;quot;range&amp;quot;:&amp;quot;14490-14559&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Via I\u00b2C Expander 1 (0x44)&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;via_i_c_expander_1_0x44&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:35,&amp;quot;range&amp;quot;:&amp;quot;14452-14560&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit37&quot; id=&quot;rf_switch_logic&quot;&gt;RF Switch Logic&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;div class=&quot;table sectionedit38&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; Mode &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; ANT_SW &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; LNA_EN &lt;/th&gt;&lt;th class=&quot;col3&quot;&gt; Description &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; TX &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; HIGH &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; LOW &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; TX path active, LNA protected &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; RX &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; HIGH &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; HIGH &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; RX path active with LNA &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; IDLE &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; LOW &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; LOW &lt;/td&gt;&lt;td class=&quot;col3&quot;&gt; RF path disconnected, low power &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table9&amp;quot;,&amp;quot;secid&amp;quot;:38,&amp;quot;range&amp;quot;:&amp;quot;14590-14784&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;RF Switch Logic&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;rf_switch_logic&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:37,&amp;quot;range&amp;quot;:&amp;quot;14561-14785&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit39&quot; id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;pre class=&quot;code&quot;&gt;target.cpp
  └─ radio_init()
       ├─ board.begin()               SPI2, Wire, I²C-scan, expanders, loraReset()
       ├─ rtc_clock.begin(Wire)
       ├─ board.onRfRx()              RF switch active for calibration
       ├─ radio.std_init(nullptr)     no second spi-&amp;gt;begin()
       ├─ radio_driver.setRfSwitchCallback(&amp;amp;board)
       └─ display.begin()             M5GFX lazy construction — after std_init

NessoDisplayDriver
  ├─ begin()         static M5GFX; setRotation(1) before width()/height()
  └─ checkButtons()  polling KEY1/KEY2 via I²C expander 0 (50 ms debounce)

NessoN1Board (RfSwitchCallback)
  ├─ begin()      guard (single call) + loraReset()
  ├─ onRfTx()     ANT_SW=HIGH, LNA_EN=LOW
  ├─ onRfRx()     ANT_SW=HIGH, LNA_EN=HIGH
  └─ onRfIdle()   ANT_SW=LOW,  LNA_EN=LOW&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Architecture&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;architecture&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:21,&amp;quot;secid&amp;quot;:39,&amp;quot;range&amp;quot;:&amp;quot;14786-15670&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit40&quot; id=&quot;directory_structure&quot;&gt;Directory Structure&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;pre class=&quot;code&quot;&gt;variants/arduino_nesso_n1/
├── NessoN1Board.h             — pin constants, PI4IOE5V6408 driver, board class
├── NessoN1Board.cpp           — begin() with guard (Fix 3), loraReset() (Fix 5)
├── NessoDisplayDriver.h       — DisplayDriver extension, lazy construction
├── NessoDisplayDriver.cpp     — begin() with setRotation fix (Fix 2)
├── target.h                   — extern declarations, nesso_check_buttons()
├── target.cpp                 — radio_init() mandatory sequence, global objects
├── platformio.ini             — incl. SCREEN_TIMEOUT=0 (Fix 1)
├── credentials.ini.example    — template for local credentials
└── main_cpp_setup_hinweis.txt — correct main.cpp structure (Fix 3/4)

src/helpers/ui/
└── DisplayDriver.h            — abstract interface (pure virtuals)

src/helpers/radiolib/
├── RfSwitchCallback.h         — abstract interface for external RF switch
└── CustomSX1262Wrapper.h      — SX1262 wrapper with RF switch callback&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Directory Structure&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;directory_structure&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:22,&amp;quot;secid&amp;quot;:40,&amp;quot;range&amp;quot;:&amp;quot;15671-16760&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit41&quot; id=&quot;open_items&quot;&gt;Open Items&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;
&lt;div class=&quot;table sectionedit42&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; # &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; Topic &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; Status &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 1 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Remove &lt;code&gt;board.begin()&lt;/code&gt; / &lt;code&gt;display.begin()&lt;/code&gt; from &lt;code&gt;main.cpp&lt;/code&gt; &lt;code&gt;setup()&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; workaround active (guard) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 2 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Hook KEY1/KEY2 into UITask screen wakeup &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; open &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 3 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Touch FT6336U (I²C 0x38) &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; open &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 4 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; IMU BMI270 (I²C 0x68) for auto-rotation &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; open &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; 5 &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Battery monitor (I²C 0x49) &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; open &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table10&amp;quot;,&amp;quot;secid&amp;quot;:42,&amp;quot;range&amp;quot;:&amp;quot;16785-17116&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Open Items&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;open_items&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:23,&amp;quot;secid&amp;quot;:41,&amp;quot;range&amp;quot;:&amp;quot;16761-17117&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit43&quot; id=&quot;license&quot;&gt;License&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
MIT License, identical to MeshCore. Full text in the repository root.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;License&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;license&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:23,&amp;quot;secid&amp;quot;:43,&amp;quot;range&amp;quot;:&amp;quot;17118-&amp;quot;} --&gt;
&lt;!-- cachefile /app/www/public/data/cache/2/2e92b52f3dddfc24332195f2f5451c57.xhtml used --&gt;
</description>
            <author>anonymous@undisclosed.example.com (Anonymous)</author>
            <pubDate>Tue, 21 Apr 2026 12:58:08 +0000</pubDate>
        </item>
    </channel>
</rss>
