Webseiten-Werkzeuge


weitere_hardware:nesso_n1

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
weitere_hardware:nesso_n1 [18.04.2026 19:22] mellinuxweitere_hardware:nesso_n1 [18.04.2026 19:24] (aktuell) mellinux
Zeile 567: Zeile 567:
 MIT-Lizenz, identisch mit MeshCore. Vollständiger Text im Wurzelverzeichnis. MIT-Lizenz, identisch mit MeshCore. Vollständiger Text im Wurzelverzeichnis.
  
- 
----- 
- 
-====== English version ====== 
- 
-**NOTE:** Currently in the testing phase! 
- 
-====== MeshCore — Arduino Nesso N1 (ESP32-C6) ====== 
- 
-**Author:** team-nessoN1-meshcore — team-nessoN1-meshcore@posteo.de   
-**Date:** April 2026 
- 
-This directory contains the Hardware Abstraction Layer (HAL) for the 
-**Arduino Nesso N1** 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\u2033 touchscreen 
-in a compact, battery-powered enclosure. 
- 
----- 
- 
-===== Hardware Overview ===== 
- 
-| Component | Details | 
-|---|---| 
-| MCU | Espressif ESP32-C6 (RISC-V, 160 MHz) | 
-| Flash | 16 MB | 
-| RAM | 512 KB | 
-| LoRa | Semtech SX1262, 850\u2013960 MHz, up to +22 dBm | 
-| RF Switch / LNA | External, controlled via I\u00b2C GPIO expander | 
-| I\u00b2C GPIO Expander | PI4IOE5V6408 (2\u00d7 instances, addresses 0x43 and 0x44) | 
-| Display | ST7789P3, 1.14\u2033, 240\u00d7135 px, touchscreen (FT6336U) | 
-| IMU | BMI270 (6-axis) | 
-| Battery | 250 mAh LiPo, USB-C charging | 
-| Connectivity | Wi-Fi 6, BT 5.3, Thread/Zigbee (802.15.4), LoRa | 
- 
----- 
- 
-===== Key Porting Decisions ===== 
- 
-==== SX1262 Reset and RF Switch via I\u00b2C Expander ==== 
- 
-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 
-**PI4IOE5V6408 I\u00b2C GPIO expander** (address 0x43): 
- 
-| Signal | Expander Pin | Function | 
-|---|---|---| 
-| SX_NRST | P7 | SX1262 hardware reset | 
-| SX_ANT_SW | P6 | Antenna RF switch | 
-| SX_LNA_EN | P5 | Low-noise amplifier enable | 
-| KEY1 | P0 | Button A (input) | 
-| KEY2 | P1 | Button B (input) | 
- 
-RadioLib's ''setRfSwitchTable()'' (direct GPIO only) cannot be used. 
-''NessoN1Board'' implements the ''RfSwitchCallback'' interface instead. 
- 
-==== Shared SPI Bus (SX1262 + ST7789) ==== 
- 
-| Signal | GPIO | 
-|---|---| 
-| MOSI | G21 | 
-| MISO | G22 | 
-| SCK | G20 | 
-| LoRa CS (NSS) | G23 (software CS) | 
-| LCD CS | G17 (software CS) | 
-| LCD DC | G16 | 
- 
-''lora_spi.begin()'' is called **without the NSS argument** to avoid registering 
-a duplicate APB hardware CS-callback (see Fix 4). 
- 
-==== FSPI instead of default SPI ==== 
- 
-The ESP32-C6 has no VSPI bus: ''SPIClass lora_spi(FSPI)''. 
- 
-==== USB-CDC and BLE are mutually exclusive ==== 
- 
-| Firmware | ''ARDUINO_USB_CDC_ON_BOOT'' | Debug output | 
-|---|---|---| 
-| Repeater | ''1'' | USB-Serial active | 
-| Companion BLE | ''0'' | no USB-Serial | 
-| Companion WiFi | ''0'' | no USB-Serial | 
- 
----- 
- 
-===== Display Architecture ===== 
- 
-==== Resolution and UITask Layout Verification ==== 
- 
-The ST7789P3 has **240\u00d7135 pixels** (Landscape, ''setRotation(1)''). 
-All UITask default layouts fit without overflow: 
- 
-| Element | Width | x (centred) | Right edge | Fits | 
-|---|---|---|---|---| 
-| MeshCore logo (64\u00d736 px XBM) | 64 px | 88 | 152 | \u2705 | 
-| Version line (setTextSize 2) | 156 px | 42 | 198 | \u2705 | 
-| Node name \"NessoN1 Repeater\" | 192 px | 24 | 216 | \u2705 | 
-| Frequency line \"869.6 SF8 BW62.5\" | 204 px | 18 | 222 | \u2705 | 
- 
-All four elements together occupy ~100 px of 135 px height \u2014 no vertical overflow. 
- 
-==== Mandatory Initialisation Order ==== 
- 
-<code> 
-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 \u2014 nullptr: no second spi->begin() 
-  4. display.begin()         M5GFX lazy construction \u2014 must follow std_init! 
-</code> 
- 
----- 
- 
-===== Known Issues and Their Fixes ===== 
- 
-==== Fix 1 \u2014 Display Goes Black After a Few Seconds ==== 
- 
-**Date:** April 2026   
-**Affected file:** ''platformio.ini'', ''[env:NessoN1_repeater_display]'' 
- 
-**Symptom:** Display shows boot screen (~4 s) and home screen (~10 s), 
-then stays permanently black. Button presses have no effect. 
- 
-**Root cause:** 
-''UITask.h'' (MeshCore, ''examples/simple_repeater/UITask.h'') defines 
-''SCREEN_TIMEOUT'' (default: 10 000 ms). After expiry it calls 
-''display.turnOff()''. The wakeup path in UITask polls ''PIN_USER_BTN'' \u2014 
-a direct GPIO pin. On the Nesso N1, KEY1 and KEY2 are connected **via I\u00b2C 
-expander 0** (address 0x43, pins P0/P1) and are **not direct GPIOs**. 
-UITask therefore has **no wakeup path** \u2014 once the timeout fires, the 
-display stays off permanently. 
- 
-**Fix:** 
-<code>ini 
-; platformio.ini \u2014 [env:NessoN1_repeater_display]: 
--D SCREEN_TIMEOUT=0 
--D DISPLAY_TIMEOUT=0 
-</code> 
-Both flags set to 0 disable the automatic timeout entirely. 
-''DISPLAY_TIMEOUT'' is also set because different UITask versions use different macro names. 
- 
-**Note for battery operation:** Use e.g. ''-D SCREEN_TIMEOUT=30000''. 
-Button wakeup is already integrated via ''nesso_ui_tick()'' (see Fix 7). 
- 
----- 
- 
-==== Fix 7 \u2014 Buttons Non-Functional in Repeater Display Mode ==== 
- 
-**Date:** April 2026   
-**Affected files:** ''simple_repeater/main.cpp'', ''simple_repeater/UITask.h'', 
-''simple_repeater/UITask.cpp'', ''simple_repeater/MyMesh.h'' 
- 
-**Symptom:** KEY1 and KEY2 appear to do nothing. Serial log shows 
-''[ui] KEY1 erkannt'' \u2014 the keypress is detected, but the display does not change. 
- 
-**Root cause:**   
-''nesso_ui_tick()'' correctly returns ''-1'' (KEY1) or ''-2'' (KEY2) when the display 
-is already on. In ''main.cpp'', evaluation of these return values was entirely 
-**commented out**. Additionally, ''UITask'' had no navigable screens and no 
-connection to ''MyMesh'' to fetch neighbour data or send a discover request. 
- 
-**Fix \u2014 three levels:** 
- 
-1. **New interface ''UIActions.h''** \u2014 decouples UITask from MyMesh: 
-<code>cpp 
-class UIActions { 
-public: 
-  virtual void uiGetNeighborList(char* buf, int bufSize) = 0; 
-  virtual void uiSendDiscover() = 0; 
-}; 
-</code> 
- 
-2. **''MyMesh'' implements ''UIActions''** \u2014 in ''MyMesh.h'': 
-<code>cpp 
-class MyMesh : public mesh::Mesh, public CommonCLICallbacks, public UIActions { 
-  void uiGetNeighborList(char* buf, int bufSize) override { formatNeighborsReply(buf); } 
-  void uiSendDiscover() override { sendNodeDiscoverReq(); } 
-}; 
-</code> 
- 
-3. **''UITask'' gains 3 screens + navigation**, connected via ''setActions()'': 
-<code> 
-SCREEN_HOME       \u2014 node name, frequency, SF/BW/CR 
-SCREEN_NEIGHBOURS \u2014 neighbour list (hex ID, age, SNR) 
-SCREEN_POLL_SENT  \u2014 "Poll sent" feedback for 2 seconds 
-</code> 
- 
-4. **''main.cpp'' evaluates ''btn''** (previously commented out): 
-<code>cpp 
-if (btn == -1) ui_task.nextScreen();   // KEY1: forward / poll 
-if (btn == -2) ui_task.prevScreen();   // KEY2: back 
-</code> 
- 
-**Button behaviour after patch:** 
- 
-| Button | Display OFF | Display ON (Home) | Display ON (Neighbours) | 
-|--------|-------------|-------------------|-------------------------| 
-| KEY1 | Wakeup | \u2192 Neighbours screen | \u2192 Send poll | 
-| KEY2 | Wakeup | stays Home | \u2192 Home screen | 
- 
-After sending a poll, the screen shows "Poll sent" for 2 seconds, 
-then automatically returns to the (refreshed) neighbour list. 
- 
----- 
- 
-==== Fix 8 \u2014 Buttons Not Recognised: Wire Conflict Between M5GFX and Expander Driver ==== 
- 
-**Date:** April 2026   
-**Affected files:** ''NessoDisplayDriver.cpp'', ''NessoDisplayDriver.h'', ''platformio.ini'' 
- 
-**Symptom:** KEY1 and KEY2 are not reliably registered despite correct edge detection 
-and boot lock. Serial log shows: 
-<code> 
-[E][Wire.cpp:131] setPins(): bus already initialized. change pins only when not. 
-[E][esp32-hal-cpu.c:123] addApbChangeCallback(): duplicate func=... 
-</code> 
- 
-**Root cause:**   
-M5GFX initialises the I\u00b2C bus internally via ''WireInternal.begin(SDA, SCL)''. 
-The custom ''PI4IOE5V6408'' driver in ''NessoN1Board'' also initialises ''Wire'' directly. 
-Both access the **same bus** (SDA=GPIO10, SCL=GPIO8) with different ''TwoWire'' instances, 
-causing bus collisions and unstable expander reads. Documented in the Arduino Forum 
-(November 2025): https://forum.arduino.cc/t/cant-use-buttons-and-graphics-at-the-same-time/1415099 
- 
-**Fix:**   
-''M5Unified'' takes over button handling and display initialisation in a coordinated way. 
-''M5.begin()'' initialises Wire, M5GFX and the GPIO expander in the correct order \u2014 
-no more Wire conflict. 
- 
-<code>cpp 
-// NessoDisplayDriver.cpp \u2014 begin(): 
-M5.begin(cfg);              // instead of: _gfx->begin() 
-_gfx = &M5.Display;        // instead of: static M5GFX gfx_instance 
- 
-// checkButtons(): 
-M5.update(); 
-if (M5.BtnA.wasPressed()) return 1;  // KEY1 
-if (M5.BtnB.wasPressed()) return 2;  // KEY2 
-</code> 
- 
-<code>ini 
-; platformio.ini \u2014 nesso_n1_base: 
-lib_deps = 
-  m5stack/M5GFX 
-  m5stack/M5Unified   ; NEW: Fix 8 
-</code> 
- 
-Removed: ''_prevBtnState'', ''_btnReadyAt'', ''_lastBtnCheck'' \u2014 manual debounce 
-is no longer needed; M5Unified handles edge detection internally. 
- 
----- 
- 
-==== Fix 2 \u2014 Display in Portrait Mode (135\u00d7240 Instead of 240\u00d7135) ==== 
- 
-**Date:** April 2026   
-**Affected file:** ''NessoDisplayDriver.cpp'' 
- 
-**Symptom:** Serial reports ''M5GFX reports display: 135 x 240 px''. 
-UITask text is clipped with a negative x-offset and is not readable. 
- 
-**Root cause:** 
-''setRotation(1)'' was called **after** querying ''width()'' and ''height()''. 
-M5GFX swaps dimensions only after ''setRotation()'', so the pre-rotation query 
-always returned 135\u00d7240. The problem also occurred when ''display.begin()'' ran 
-before ''radio_init()'' from ''main.cpp'': the idempotent guard on the second 
-''begin()'' call skipped ''setRotation(1)'' entirely. 
- 
-**Fix in ''NessoDisplayDriver.cpp'':** 
-<code>cpp 
-_gfx->setRotation(1);  // FIRST \u2014 M5GFX swaps dimensions only after this 
-Serial.printf("[display] M5GFX ready: %d x %d px\n", 
-    _gfx->width(), _gfx->height());  // now correctly 240 x 135 
-</code> 
- 
----- 
- 
-==== Fix 3 \u2014 ''radio init failed: -2'' from Double board.begin() Call ==== 
- 
-**Date:** April 2026   
-**Affected file:** ''NessoN1Board.cpp'' 
- 
-**Symptom:** ''ERROR: radio init failed: -2'', serial shows ''[loraReset] TIMEOUT!''. 
- 
-**Root cause:** 
-''examples/simple_repeater/main.cpp'' calls ''board.begin()'' in ''setup()'' under 
-''#ifdef DISPLAY_CLASS'' \u2014 **before** ''radio_init()''. On the Nesso N1, 
-''board.begin()'' calls ''loraReset()'': SX1262 boots, BUSY goes HIGH. Then 
-''radio_init()'' calls ''board.begin()'' again \u2014 second ''loraReset()'' \u2014 SX1262 
-boots again, BUSY HIGH again \u2014 ''radio.std_init()'' hits the chip during boot 
-\u2014 ''RADIOLIB_ERR_CHIP_NOT_FOUND'' = ''-2''. 
- 
-**Fix in ''NessoN1Board::begin()'':** 
-<code>cpp 
-static bool s_boardBeginCalled = false; 
-if (s_boardBeginCalled) { 
-    Serial.println("[board] begin() already initialised \u2014 guard active"); 
-    return;   // loraReset() is NOT called again 
-} 
-s_boardBeginCalled = true; 
-</code> 
- 
-**Complete solution:** Remove ''board.begin()'' and ''display.begin()'' from 
-''setup()'' in ''main.cpp'' (see ''main_cpp_setup_hinweis.txt''). 
- 
----- 
- 
-==== Fix 4 \u2014 APB Callback Duplicate and Wire.setPins Warning ==== 
- 
-**Date:** April 2026   
-**Affected files:** ''NessoN1Board.cpp'', ''NessoDisplayDriver.cpp'' 
- 
-**Symptom:** 
-<code> 
-[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=... 
-</code> 
- 
-**Root cause:** 
-''main.cpp'' calls ''display.begin()'' before ''radio_init()''. M5GFX (constructed 
-on first ''display.begin()'') calls ''spi_bus_initialize(SPI2_HOST)'' and 
-''Wire.begin()''. When ''radio_init()'' \u2192 ''board.begin()'' \u2192 ''lora_spi.begin()'' 
-runs afterwards, the ESP-IDF SPI driver tries to register the same APB 
-callback again \u2192 ''duplicate''. 
- 
-**Fix:** The board guard (Fix 3) prevents the second ''lora_spi.begin()'' call. 
-The three ''[E]'' lines are **functionally harmless** but remain visible while 
-''main.cpp'' retains the wrong call order. 
- 
----- 
- 
-==== Fix 5 \u2014 BUSY Pulse Timing After loraReset() ==== 
- 
-**Date:** April 2026   
-**Affected file:** ''NessoN1Board.cpp'' 
- 
-**Symptom:** Log reports ''BUSY immediately after NRST HIGH: LOW (unexpected)'' 
-even though ''std_init'' succeeds. 
- 
-**Root cause:** 
-''delay(20)'' after NRST HIGH was too long. The SX1262 on the Nesso N1 produces 
-a BUSY-HIGH pulse of less than 1 ms after reset \u2014 already LOW by the time 
-''digitalRead()'' ran after 20 ms. No hardware fault, just overly conservative timing. 
- 
-**Fix:** ''delay(20)'' \u2192 ''delay(2)'', updated log message: 
-<code> 
-[loraReset] BUSY 2 ms after NRST HIGH: LOW (pulse complete \u2014 normal on Nesso N1) 
-</code> 
- 
----- 
- 
-===== Directory Structure ===== 
- 
-<code> 
-variants/arduino_nesso_n1/ 
-\u251c\u2500\u2500 NessoN1Board.h             \u2014 pin constants, PI4IOE5V6408 driver, board class 
-\u251c\u2500\u2500 NessoN1Board.cpp           \u2014 begin() with guard (Fix 3), loraReset() (Fix 5) 
-\u251c\u2500\u2500 NessoDisplayDriver.h       \u2014 DisplayDriver extension, lazy construction 
-\u251c\u2500\u2500 NessoDisplayDriver.cpp     \u2014 begin() with setRotation fix (Fix 2) 
-\u251c\u2500\u2500 target.h                   \u2014 extern declarations, nesso_check_buttons() 
-\u251c\u2500\u2500 target.cpp                 \u2014 radio_init() mandatory sequence, global objects 
-\u251c\u2500\u2500 platformio.ini             \u2014 incl. SCREEN_TIMEOUT=0 (Fix 1) 
-\u251c\u2500\u2500 credentials.ini.example    \u2014 template for local credentials 
-\u2514\u2500\u2500 main_cpp_setup_hinweis.txt \u2014 correct main.cpp structure (Fix 3/4) 
-</code> 
- 
----- 
- 
-===== Quick Start ===== 
- 
-==== 1. Prerequisites ==== 
- 
-  * [PlatformIO](https://platformio.org/) (CLI or VS Code extension) 
-  * Arduino Nesso N1 connected via USB-C 
- 
-==== 2. Set up credentials ==== 
- 
-<code>bash 
-cd <project root> 
-cp variants/arduino_nesso_n1/credentials.ini.example credentials.ini 
-</code> 
- 
-Edit ''credentials.ini'': 
-<code>ini 
-[credentials] 
-build_flags_repeater = 
-  -D ADMIN_PASSWORD='"your_password"' 
-build_flags_wifi = 
-  -D WIFI_SSID='"your_network"' 
-  -D WIFI_PWD='"your_password"' 
-</code> 
- 
-==== 3. Build and flash ==== 
- 
-<code>bash 
-pio run -e NessoN1_repeater_display --target upload && pio device monitor -b 115200 
-</code> 
- 
-==== 4. Expected serial output (repeater with display) ==== 
- 
-<code> 
-[loraReset] BUSY 2 ms after NRST HIGH: LOW (normal on Nesso N1) 
-[loraReset] BUSY=LOW after 0 ms \u2014 SX1262 ready 
-[display] M5GFX ready: 240 x 135 px (after setRotation(1)) 
-[display] ST7789 ready, backlight on 
-[board] begin() already initialised \u2014 guard active 
-[radio] std_init OK 
-[init] === radio_init() complete \u2014 radio ready === 
-</code> 
- 
----- 
- 
-===== Pin Reference ===== 
- 
-==== Direct ESP32-C6 GPIOs ==== 
- 
-| Function | GPIO | 
-|---|---| 
-| LoRa MOSI | G21 | LoRa MISO | G22 | LoRa SCK | G20 | 
-| LoRa CS (NSS) | G23 | LoRa BUSY | G19 | LoRa IRQ (DIO1) | G15 | 
-| LCD CS | G17 | LCD DC | G16 | I\u00b2C SDA | G10 | I\u00b2C SCL | G8 | Touch INT | G3 | 
- 
-==== Via I\u00b2C Expander 0 (0x43) ==== 
- 
-KEY1=P0, KEY2=P1, LNA Enable=P5, Antenna Switch=P6, LoRa Reset (NRST)=P7 
- 
-==== Via I\u00b2C Expander 1 (0x44) ==== 
- 
-LCD Reset=P1, LCD Backlight=P6 
- 
----- 
- 
-===== RF Switch Logic ===== 
- 
-| Mode | ANT_SW | LNA_EN | Description | 
-|---|---|---|---| 
-| TX | HIGH | LOW | TX path active, LNA protected | 
-| RX | HIGH | HIGH | RX path active with LNA | 
-| IDLE | LOW | LOW | RF path disconnected, low power | 
- 
----- 
- 
-===== Open Items ===== 
- 
-| # | Topic | Status | 
-|---|---|---| 
-| 1 | Remove ''board.begin()''/''display.begin()'' from ''main.cpp'' ''setup()'' | workaround active (guard) | 
-| 2 | Hook KEY1/KEY2 into UITask screen wakeup | open | 
-| 3 | Touch FT6336U (I\u00b2C 0x38) | open | 
-| 4 | IMU BMI270 (I\u00b2C 0x68) for auto-rotation | open | 
-| 5 | Battery monitor (I\u00b2C 0x49) | open | 
- 
----- 
- 
-===== License ===== 
- 
-MIT License, identical to MeshCore. Full text in the repository root. 
  
weitere_hardware/nesso_n1.txt · Zuletzt geändert: von mellinux