Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen RevisionVorhergehende Überarbeitung | |||
| weitere_hardware:nesso_n1 [18.04.2026 19:22] – mellinux | weitere_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, | ||
| - | 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/ | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ===== 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' | ||
| - | '' | ||
| - | |||
| - | ==== 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 | | ||
| - | |||
| - | '' | ||
| - | a duplicate APB hardware CS-callback (see Fix 4). | ||
| - | |||
| - | ==== FSPI instead of default SPI ==== | ||
| - | |||
| - | The ESP32-C6 has no VSPI bus: '' | ||
| - | |||
| - | ==== USB-CDC and BLE are mutually exclusive ==== | ||
| - | |||
| - | | Firmware | '' | ||
| - | |---|---|---| | ||
| - | | Repeater | '' | ||
| - | | Companion BLE | '' | ||
| - | | Companion WiFi | '' | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ===== Display Architecture ===== | ||
| - | |||
| - | ==== Resolution and UITask Layout Verification ==== | ||
| - | |||
| - | The ST7789P3 has **240\u00d7135 pixels** (Landscape, '' | ||
| - | 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 \" | ||
| - | | Frequency line \" | ||
| - | |||
| - | All four elements together occupy ~100 px of 135 px height \u2014 no vertical overflow. | ||
| - | |||
| - | ==== Mandatory Initialisation Order ==== | ||
| - | |||
| - | < | ||
| - | radio_init() in target.cpp: | ||
| - | 1. board.begin() | ||
| - | 2. board.onRfRx() | ||
| - | 3. radio.std_init(nullptr) RadioLib \u2014 nullptr: no second spi-> | ||
| - | 4. display.begin() | ||
| - | </ | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ===== Known Issues and Their Fixes ===== | ||
| - | |||
| - | ==== Fix 1 \u2014 Display Goes Black After a Few Seconds ==== | ||
| - | |||
| - | **Date:** April 2026 | ||
| - | **Affected file:** '' | ||
| - | |||
| - | **Symptom: | ||
| - | then stays permanently black. Button presses have no effect. | ||
| - | |||
| - | **Root cause:** | ||
| - | '' | ||
| - | '' | ||
| - | '' | ||
| - | 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:** | ||
| - | < | ||
| - | ; platformio.ini \u2014 [env: | ||
| - | -D SCREEN_TIMEOUT=0 | ||
| - | -D DISPLAY_TIMEOUT=0 | ||
| - | </ | ||
| - | Both flags set to 0 disable the automatic timeout entirely. | ||
| - | '' | ||
| - | |||
| - | **Note for battery operation: | ||
| - | Button wakeup is already integrated via '' | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ==== Fix 7 \u2014 Buttons Non-Functional in Repeater Display Mode ==== | ||
| - | |||
| - | **Date:** April 2026 | ||
| - | **Affected files:** '' | ||
| - | '' | ||
| - | |||
| - | **Symptom: | ||
| - | '' | ||
| - | |||
| - | **Root cause: | ||
| - | '' | ||
| - | is already on. In '' | ||
| - | **commented out**. Additionally, | ||
| - | connection to '' | ||
| - | |||
| - | **Fix \u2014 three levels:** | ||
| - | |||
| - | 1. **New interface '' | ||
| - | < | ||
| - | class UIActions { | ||
| - | public: | ||
| - | virtual void uiGetNeighborList(char* buf, int bufSize) = 0; | ||
| - | virtual void uiSendDiscover() = 0; | ||
| - | }; | ||
| - | </ | ||
| - | |||
| - | 2. **'' | ||
| - | < | ||
| - | class MyMesh : public mesh::Mesh, public CommonCLICallbacks, | ||
| - | void uiGetNeighborList(char* buf, int bufSize) override { formatNeighborsReply(buf); | ||
| - | void uiSendDiscover() override { sendNodeDiscoverReq(); | ||
| - | }; | ||
| - | </ | ||
| - | |||
| - | 3. **'' | ||
| - | < | ||
| - | SCREEN_HOME | ||
| - | SCREEN_NEIGHBOURS \u2014 neighbour list (hex ID, age, SNR) | ||
| - | SCREEN_POLL_SENT | ||
| - | </ | ||
| - | |||
| - | 4. **'' | ||
| - | < | ||
| - | if (btn == -1) ui_task.nextScreen(); | ||
| - | if (btn == -2) ui_task.prevScreen(); | ||
| - | </ | ||
| - | |||
| - | **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:** '' | ||
| - | |||
| - | **Symptom: | ||
| - | and boot lock. Serial log shows: | ||
| - | < | ||
| - | [E][Wire.cpp: | ||
| - | [E][esp32-hal-cpu.c: | ||
| - | </ | ||
| - | |||
| - | **Root cause: | ||
| - | M5GFX initialises the I\u00b2C bus internally via '' | ||
| - | The custom '' | ||
| - | Both access the **same bus** (SDA=GPIO10, | ||
| - | causing bus collisions and unstable expander reads. Documented in the Arduino Forum | ||
| - | (November 2025): https:// | ||
| - | |||
| - | **Fix: | ||
| - | '' | ||
| - | '' | ||
| - | no more Wire conflict. | ||
| - | |||
| - | < | ||
| - | // NessoDisplayDriver.cpp \u2014 begin(): | ||
| - | M5.begin(cfg); | ||
| - | _gfx = & | ||
| - | |||
| - | // checkButtons(): | ||
| - | M5.update(); | ||
| - | if (M5.BtnA.wasPressed()) return 1; // KEY1 | ||
| - | if (M5.BtnB.wasPressed()) return 2; // KEY2 | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | ; platformio.ini \u2014 nesso_n1_base: | ||
| - | lib_deps = | ||
| - | m5stack/ | ||
| - | m5stack/ | ||
| - | </ | ||
| - | |||
| - | Removed: '' | ||
| - | 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:** '' | ||
| - | |||
| - | **Symptom: | ||
| - | UITask text is clipped with a negative x-offset and is not readable. | ||
| - | |||
| - | **Root cause:** | ||
| - | '' | ||
| - | M5GFX swaps dimensions only after '' | ||
| - | always returned 135\u00d7240. The problem also occurred when '' | ||
| - | before '' | ||
| - | '' | ||
| - | |||
| - | **Fix in '' | ||
| - | < | ||
| - | _gfx-> | ||
| - | Serial.printf(" | ||
| - | _gfx-> | ||
| - | </ | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ==== Fix 3 \u2014 '' | ||
| - | |||
| - | **Date:** April 2026 | ||
| - | **Affected file:** '' | ||
| - | |||
| - | **Symptom: | ||
| - | |||
| - | **Root cause:** | ||
| - | '' | ||
| - | ''# | ||
| - | '' | ||
| - | '' | ||
| - | boots again, BUSY HIGH again \u2014 '' | ||
| - | \u2014 '' | ||
| - | |||
| - | **Fix in '' | ||
| - | < | ||
| - | static bool s_boardBeginCalled = false; | ||
| - | if (s_boardBeginCalled) { | ||
| - | Serial.println(" | ||
| - | return; | ||
| - | } | ||
| - | s_boardBeginCalled = true; | ||
| - | </ | ||
| - | |||
| - | **Complete solution:** Remove '' | ||
| - | '' | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ==== Fix 4 \u2014 APB Callback Duplicate and Wire.setPins Warning ==== | ||
| - | |||
| - | **Date:** April 2026 | ||
| - | **Affected files:** '' | ||
| - | |||
| - | **Symptom: | ||
| - | < | ||
| - | [E][Wire.cpp: | ||
| - | [E][esp32-hal-cpu.c: | ||
| - | [E][esp32-hal-cpu.c: | ||
| - | </ | ||
| - | |||
| - | **Root cause:** | ||
| - | '' | ||
| - | on first '' | ||
| - | '' | ||
| - | runs afterwards, the ESP-IDF SPI driver tries to register the same APB | ||
| - | callback again \u2192 '' | ||
| - | |||
| - | **Fix:** The board guard (Fix 3) prevents the second '' | ||
| - | The three '' | ||
| - | '' | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ==== Fix 5 \u2014 BUSY Pulse Timing After loraReset() ==== | ||
| - | |||
| - | **Date:** April 2026 | ||
| - | **Affected file:** '' | ||
| - | |||
| - | **Symptom: | ||
| - | even though '' | ||
| - | |||
| - | **Root cause:** | ||
| - | '' | ||
| - | a BUSY-HIGH pulse of less than 1 ms after reset \u2014 already LOW by the time | ||
| - | '' | ||
| - | |||
| - | **Fix:** '' | ||
| - | < | ||
| - | [loraReset] BUSY 2 ms after NRST HIGH: LOW (pulse complete \u2014 normal on Nesso N1) | ||
| - | </ | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ===== Directory Structure ===== | ||
| - | |||
| - | < | ||
| - | variants/ | ||
| - | \u251c\u2500\u2500 NessoN1Board.h | ||
| - | \u251c\u2500\u2500 NessoN1Board.cpp | ||
| - | \u251c\u2500\u2500 NessoDisplayDriver.h | ||
| - | \u251c\u2500\u2500 NessoDisplayDriver.cpp | ||
| - | \u251c\u2500\u2500 target.h | ||
| - | \u251c\u2500\u2500 target.cpp | ||
| - | \u251c\u2500\u2500 platformio.ini | ||
| - | \u251c\u2500\u2500 credentials.ini.example | ||
| - | \u2514\u2500\u2500 main_cpp_setup_hinweis.txt \u2014 correct main.cpp structure (Fix 3/4) | ||
| - | </ | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ===== Quick Start ===== | ||
| - | |||
| - | ==== 1. Prerequisites ==== | ||
| - | |||
| - | * [PlatformIO](https:// | ||
| - | * Arduino Nesso N1 connected via USB-C | ||
| - | |||
| - | ==== 2. Set up credentials ==== | ||
| - | |||
| - | < | ||
| - | cd <project root> | ||
| - | cp variants/ | ||
| - | </ | ||
| - | |||
| - | Edit '' | ||
| - | < | ||
| - | [credentials] | ||
| - | build_flags_repeater = | ||
| - | -D ADMIN_PASSWORD='" | ||
| - | build_flags_wifi = | ||
| - | -D WIFI_SSID='" | ||
| - | -D WIFI_PWD='" | ||
| - | </ | ||
| - | |||
| - | ==== 3. Build and flash ==== | ||
| - | |||
| - | < | ||
| - | pio run -e NessoN1_repeater_display --target upload && pio device monitor -b 115200 | ||
| - | </ | ||
| - | |||
| - | ==== 4. Expected serial output (repeater with display) ==== | ||
| - | |||
| - | < | ||
| - | [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 === | ||
| - | </ | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ===== 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, | ||
| - | |||
| - | ---- | ||
| - | |||
| - | ===== Open Items ===== | ||
| - | |||
| - | | # | Topic | Status | | ||
| - | |---|---|---| | ||
| - | | 1 | Remove '' | ||
| - | | 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. | ||