diff --git a/variants/nrf52840/diy/moonshine_NRF52/readme.md b/variants/nrf52840/diy/moonshine_NRF52/readme.md index b2397b73f..2243ca8c7 100644 --- a/variants/nrf52840/diy/moonshine_NRF52/readme.md +++ b/variants/nrf52840/diy/moonshine_NRF52/readme.md @@ -8,7 +8,9 @@ DIY Meshtastic node variant based on the RF-BM-ND05 nRF52840 module. - **LF clock**: internal RC (`USE_LFRC`) - RF-BM-ND05 has no 32.768 kHz crystal; using `USE_LFXO` without a crystal makes SoftDevice hang in `RTC1_IRQHandler` waiting for LFCLK, causing LED-stuck-on and silent BLE failure. -- **LoRa**: multi-module compatible (SX1262 / SX1268 / RF95 / LLCC68 / LR1121 / LR2021) with TCXO +- **LoRa**: E22-400M33S (SX1268 + 33dBm PA, 2W, 433MHz) - `SX126X_MAX_POWER=8`, + `TX_GAIN_LORA=25` required (22dBm default overdrives PA to ~47dBm, causing current + spikes and system reset even at low tx_power settings) - **GPS**: u-blox (no EN pin) - **Battery ADC**: 0.5 voltage divider (equal resistors) diff --git a/variants/nrf52840/diy/moonshine_NRF52/variant.h b/variants/nrf52840/diy/moonshine_NRF52/variant.h index ab5e53e8a..43986e8f7 100644 --- a/variants/nrf52840/diy/moonshine_NRF52/variant.h +++ b/variants/nrf52840/diy/moonshine_NRF52/variant.h @@ -111,21 +111,13 @@ MOONSHINE NRF52 PIN ASSIGNMENT (RF-BM-ND05) #define LORA_CS (0 + 29) // P0.29 // LORA MODULES -#define USE_LLCC68 -#define USE_SX1262 -#define USE_RF95 -#define USE_SX1268 -#define USE_LR1121 -#define USE_LR2021 +#define USE_SX1268 // E22-400M33S uses SX1268 (433MHz) -// RF95 CONFIG -#define LORA_DIO0 (0 + 22) // P0.22 BUSY -#define LORA_DIO1 (0 + 21) // P0.21 IRQ -#define LORA_RESET (0 + 23) // P0.23 NRST - -// RX/TX for RFM95/SX127x -#define RF95_RXEN (0 + 11) // P0.11 -#define RF95_TXEN RADIOLIB_NC // Assuming that DIO2 is connected to TXEN pin. If not, TXEN must be connected. +// E22-400M33S: 33dBm/2W module with ~25dB PA gain +// SX1268 outputs 8dBm -> PA -> 33dBm (2W) +// 22dBm default would overdrive PA to ~47dBm, causing current spikes and system reset +#define SX126X_MAX_POWER 8 +#define TX_GAIN_LORA 25 // SX126X CONFIG #define SX126X_CS (0 + 29) // P0.29 FIXME - we really should define LORA_CS instead @@ -137,32 +129,6 @@ MOONSHINE NRF52 PIN ASSIGNMENT (RF-BM-ND05) #define SX126X_RXEN (0 + 11) // P0.11 #define SX126X_TXEN RADIOLIB_NC // Assuming that DIO2 is connected to TXEN pin. If not, TXEN must be connected. -// LR1121 -#ifdef USE_LR1121 -#define LR1121_IRQ_PIN (0 + 21) // P0.21 IRQ -#define LR1121_NRESET_PIN LORA_RESET // P0.23 NRST -#define LR1121_BUSY_PIN (0 + 22) // P0.22 BUSY -#define LR1121_SPI_NSS_PIN LORA_CS // P0.29 -#define LR1121_SPI_SCK_PIN LORA_SCK -#define LR1121_SPI_MOSI_PIN LORA_MOSI -#define LR1121_SPI_MISO_PIN LORA_MISO -#define LR11X0_DIO3_TCXO_VOLTAGE 1.8 -#define LR11X0_DIO_AS_RF_SWITCH -#endif - -// LR2021 -#ifdef USE_LR2021 -#define LR2021_IRQ_PIN (0 + 21) // P0.21 IRQ -#define LR2021_NRESET_PIN LORA_RESET // P0.23 NRST -#define LR2021_BUSY_PIN (0 + 22) // P0.22 BUSY -#define LR2021_SPI_NSS_PIN LORA_CS // P0.29 -#define LR2021_DIO3_TCXO_VOLTAGE 1.8 -#define LR2021_DIO_AS_RF_SWITCH -#define LR2021_IRQ_DIO_NUM 9 // DIO9 -> P0.21 -#endif - -// #define SX126X_MAX_POWER 8 set this if using a high-power board! - #define SX126X_DIO3_TCXO_VOLTAGE 1.8 #define TCXO_OPTIONAL // make it so that the firmware can try both TCXO and XTAL diff --git a/variants/nrf52840/diy/moonshine_NRF52_mini/platformio.ini b/variants/nrf52840/diy/moonshine_NRF52_mini/platformio.ini new file mode 100644 index 000000000..9c34e4bf4 --- /dev/null +++ b/variants/nrf52840/diy/moonshine_NRF52_mini/platformio.ini @@ -0,0 +1,17 @@ +; Moonshine NRF52 mini - minimal DIY variant (nRF52840 + RA-01S-P SX1262) +[env:moonshine_NRF52_node_mini] +extends = nrf52840_base +board = adafruit_feather_nrf52840 +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld +build_flags = ${nrf52840_base.build_flags} + -I variants/nrf52840/diy/moonshine_NRF52_mini + -D PRIVATE_HW + -D MESHTASTIC_EXCLUDE_I2C=1 + -D MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1 + -D MESHTASTIC_EXCLUDE_INPUTBROKER=1 + -D MESHTASTIC_EXCLUDE_ACCELEROMETER=1 + -D MESHTASTIC_EXCLUDE_MAGNETOMETER=1 + -D MESHTASTIC_EXCLUDE_GPS=1 + -D MESHTASTIC_EXCLUDE_SCREEN=1 +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/diy/moonshine_NRF52_mini> +debug_tool = jlink diff --git a/variants/nrf52840/diy/moonshine_NRF52_mini/readme.md b/variants/nrf52840/diy/moonshine_NRF52_mini/readme.md new file mode 100644 index 000000000..2b5bb9dfe --- /dev/null +++ b/variants/nrf52840/diy/moonshine_NRF52_mini/readme.md @@ -0,0 +1,100 @@ +# Moonshine NRF52 Mini + +Minimal DIY Meshtastic node variant: nRF52840 + RA-01S-P (SX1262) LoRa module +with a single status LED on P0.13. No display, GPS, button, or battery ADC - +LoRa-only minimal system. + +## Hardware + +- **MCU**: nRF52840 (512 KB flash / 128 KB RAM) +- **LF clock**: external 32.768 kHz crystal (`USE_LFXO`) +- **LoRa**: Ai-Thinker RA-01S-P (SX1262, no TCXO, internal RF switch, 22 dBm max) + - `SX126X_MAX_POWER=22` + - `TCXO_OPTIONAL` (no TCXO on module - firmware tries XTAL first) + - DIO2 drives TXEN internally; RXEN is controlled by `P0.17` +- **LED**: status LED on P0.13 (active high, `LED_STATE_ON = 1`) + +## Pin map + +| Function | Pin | Notes | +| ----------- | ----- | ------------------------------ | +| SPI_MISO | P0.02 | LORA_MISO | +| LORA_RESET | P0.09 | SX126X_RESET | +| LORA_DIO1 | P0.10 | SX126X_DIO1 (IRQ) | +| LED | P0.13 | Status LED (active high) | +| LORA_RXEN | P0.17 | SX126X_RXEN | +| LORA_BUSY | P0.29 | SX126X_BUSY | +| SPI_SCK | P1.11 | LORA_SCK | +| LORA_CS | P1.13 | SX126X_CS | +| SPI_MOSI | P1.15 | LORA_MOSI | + +Only the status LED on P0.13 is wired (no button, battery ADC, GPS, or display). +The board has no user button, so DFU entry is via the 1200 bps touch or SWD. + +## Build & Flash + +### Build + +```sh +pio run -e moonshine_NRF52_node_mini +``` + +Uses `PRIVATE_HW` (HardwareModel 255) - no protobuf or `architecture.h` changes +required. + +The build links against `nrf52840_s140_v7.ld`, so the application is linked to +start at `0x27000` and requires the S140 SoftDevice v7.x to be present on the +chip at `0x0`-`0x26FFF` (or the Adafruit nRF52 UF2 "bright-future" bootloader, +which bundles its own SoftDevice). The build output (`firmware-*.hex` / `.uf2`) +contains **only the application**, not the SoftDevice. + +### Flash (first time on a bare nRF52840) + +A factory-fresh nRF52840 has **no SoftDevice and no bootloader**. The SoftDevice +must be flashed once via SWD before the application; otherwise `Bluefruit.begin()` +fails, `sd_flash_*` calls (LittleFS, NodeDB, config persistence) return errors, +and the node appears dead. + +The S140 v7.3.0 SoftDevice hex is shipped in this repo at +`bin/s140_nrf52_7.3.0_softdevice.hex`. Flash via SWD with OpenOCD (CMSIS-DAP / +J-Link / ST-Link). The `nrf52_recover` command does a chip-wide ERASEALL through +the nRF52 CTRL-AP and clears APPROTECT, so it is the recommended first step on a +fresh module (ebyte/Raytac modules ship with APPROTECT engaged). + +```sh +# Full flow: recover (erase all + unlock) -> SoftDevice -> app -> reset +C:/openocd/bin/openocd.exe -s C:/openocd/share/openocd/scripts \ + -f interface/cmsis-dap.cfg -f target/nrf52.cfg \ + -c "init; nrf52_recover; \ + program bin/s140_nrf52_7.3.0_softdevice.hex verify; \ + program .pio/build/moonshine_NRF52_node_mini/firmware-moonshine_NRF52_node_mini-*.hex verify; \ + reset run; exit" +``` + +### Flash (app only, SoftDevice already present) + +When the SoftDevice is already on the chip and only the application changed +(e.g. after editing the variant and rebuilding), skip `nrf52_recover` and the +SoftDevice line: + +```sh +C:/openocd/bin/openocd.exe -s C:/openocd/share/openocd/scripts \ + -f interface/cmsis-dap.cfg -f target/nrf52.cfg \ + -c "init; \ + program .pio/build/moonshine_NRF52_node_mini/firmware-moonshine_NRF52_node_mini-*.hex verify; \ + reset run; exit" +``` + +### Notes + +- The firmware hex filename contains a commit hash (e.g. `2.8.0.421838f`); use + the actual file produced by `pio run` or a shell glob. +- The SoftDevice hex occupies `0x0`-`0x26498` (~156 KB) and does **not** write + UICR, so `nrf52_recover` is safe (UICR resets to defaults). +- Swap `interface/cmsis-dap.cfg` for `interface/jlink.cfg` or + `interface/stlink.cfg` if using a different SWD probe. +- No UF2 bootloader is installed in this flow, so subsequent updates must go + through BLE DFU (secure DFU service) or SWD again. To enable UF2 drag-and-drop + updates, flash an Adafruit nRF52 UF2 bootloader + (https://github.com/adafruit/Adafruit_nRF52_Bootloader) at `0x0` in place of + the bare SoftDevice - the bootloader bundles its own SoftDevice. diff --git a/variants/nrf52840/diy/moonshine_NRF52_mini/variant.cpp b/variants/nrf52840/diy/moonshine_NRF52_mini/variant.cpp new file mode 100644 index 000000000..dbd4effb7 --- /dev/null +++ b/variants/nrf52840/diy/moonshine_NRF52_mini/variant.cpp @@ -0,0 +1,36 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // No dedicated 3V3 enable pin on this board +} diff --git a/variants/nrf52840/diy/moonshine_NRF52_mini/variant.h b/variants/nrf52840/diy/moonshine_NRF52_mini/variant.h new file mode 100644 index 000000000..37a3f315f --- /dev/null +++ b/variants/nrf52840/diy/moonshine_NRF52_mini/variant.h @@ -0,0 +1,111 @@ +#ifndef _VARIANT_MOONSHINE_NRF52_MINI_ +#define _VARIANT_MOONSHINE_NRF52_MINI_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/* +MOONSHINE NRF52 MINI PIN ASSIGNMENT (minimal system: nRF52840 + RA-01S-P) + +| Pin | Function | Notes | +| ----- | ----------- | --------------------------- | +| P0.02 | SPI MISO | LORA_MISO | +| P0.09 | LORA RESET | SX126X_RESET | +| P0.10 | LORA DIO1 | SX126X_DIO1 (IRQ) | +| P0.13 | LED | Status LED (active high) | +| P0.17 | LORA RXEN | SX126X_RXEN | +| P0.29 | LORA BUSY | SX126X_BUSY | +| P1.11 | SPI SCK | LORA_SCK | +| P1.13 | LORA CS | SX126X_CS | +| P1.15 | SPI MOSI | LORA_MOSI | +*/ + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (0) +#define NUM_ANALOG_OUTPUTS (0) + +// No dedicated 3V3 enable pin on this board +#define PIN_3V3_EN (-1) + +// LED - status LED on P0.13 (active high) +#define PIN_LED1 (0 + 13) // P0.13 +#define LED_BLUE PIN_LED1 +#define LED_STATE_ON 1 // State when LED is lit (active high) + +// Analog pins - no ADC devices wired +#define PIN_A0 (-1) +#define PIN_AREF (-1) +#define ADC_RESOLUTION 14 + +// UART interfaces - no physical serial ports wired. The Adafruit nRF52 core +// always declares Serial1/Serial2 and requires these macros to exist; -1 means +// no pin assigned. SerialModule.cpp also references Serial2 unconditionally. +#define PIN_SERIAL1_RX (-1) +#define PIN_SERIAL1_TX (-1) +#define PIN_SERIAL2_RX (-1) +#define PIN_SERIAL2_TX (-1) + +// WIRE - no physical I2C devices, but WIRE_INTERFACES_COUNT must be >= 1 so the +// Adafruit core declares the Wire singleton (referenced by display lib deps). +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (32 + 4) // P1.04 - free pin, no I2C device wired +#define PIN_WIRE_SCL (0 + 11) // P0.11 - free pin, no I2C device wired + +// Serial interfaces +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (0 + 2) // P0.02 +#define PIN_SPI_MOSI (32 + 15) // P1.15 +#define PIN_SPI_SCK (32 + 11) // P1.11 + +#define LORA_MISO PIN_SPI_MISO +#define LORA_MOSI PIN_SPI_MOSI +#define LORA_SCK PIN_SPI_SCK +#define LORA_CS (32 + 13) // P1.13 + +// GPS - no GPS hardware; sentinels required by GPS code paths +#define GPS_RX_PIN (-1) +#define GPS_TX_PIN (-1) +#define PIN_GPS_EN (-1) +#define PIN_GPS_PPS (-1) + +// LORA MODULE - RA-01S-P (Ai-Thinker SX1262, no TCXO, internal RF switch, 22dBm) +#define USE_SX1262 + +// SX126X CONFIG +#define SX126X_CS (32 + 13) // P1.13 FIXME - we really should define LORA_CS instead +#define SX126X_DIO1 (0 + 10) // P0.10 IRQ +#define SX126X_DIO2_AS_RF_SWITCH // DIO2 drives TXEN for automatic TX/RX switching +#define SX126X_BUSY (0 + 29) // P0.29 +#define SX126X_RESET (0 + 9) // P0.09 +#define SX126X_RXEN (0 + 17) // P0.17 +#define SX126X_TXEN RADIOLIB_NC // Assuming that DIO2 is connected to TXEN pin. If not, TXEN must be connected. +#define SX126X_MAX_POWER 22 // RA-01S-P max is 22dBm + +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#define TCXO_OPTIONAL // RA-01S-P has no TCXO - firmware tries XTAL first, falls back to TCXO + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif