Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -691,23 +691,28 @@ You can get the epoch time on <https://www.epochconverter.com> and use it to set
### 6.6. Q: My Heltec V3 keeps disconnecting from my smartphone. It can't hold a solid Bluetooth connection.
**A:** Heltec V3 has a very small coil antenna on its PCB for Wi-Fi and Bluetooth connectivity. It has a very short range, only a few feet. It is possible to remove the coil antenna and replace it with a 31mm wire. The BT range is much improved with the modification.

### 6.7. Q: My RAK/T1000-E/xiao_nRF52 device seems to be corrupted, how do I wipe it clean to start fresh?
**A:**

1. Connect USB-C cable to your device, per your device's instruction, get it to flash mode:
- For RAK, click the reset button **TWICE**
- For T1000-e, quickly disconnect and reconnect the magnetic side of the cable from the device **TWICE**
- For Heltec T114, click the reset button **TWICE** (the bottom button)
- For Xiao nRF52, click the reset button once. If that doesn't work, quickly double-click the reset button twice. If that doesn't work, disconnect the board from your PC and reconnect again ([seeed studio wiki](https://wiki.seeedstudio.com/XIAO_BLE/#access-the-swd-pins-for-debugging-and-reflashing-bootloader))
2. A new folder will appear on your computer's desktop
3. Download the `flash_erase*.uf2` file for your device on <https://flasher.meshcore.io>
- RAK WisBlock and Heltec T114: `Flash_erase-nRF32_softdevice_v6.uf2`
- Seeed Studio Xiao nRF52 WIO: `Flash_erase-nRF52_softdevice_v7.uf2`
4. drag and drop the uf2 file for your device to the root of the new folder
5. Wait for the copy to complete. You might get an error dialog, you can ignore it
6. Go to <https://flasher.meshcore.io>, click `Console` and select the serial port for your connected device
7. In the console, press enter. Your flash should now be erased
8. You may now flash the latest MeshCore firmware onto your device
### 6.7. Q: My RAK/T1000-E/xiao_nRF52/... device seems to be corrupted, how do I wipe it clean to start fresh?
**A: If you're able to connect to the device from your MeshCore app**
1. Navigate to Gear icon(Settings) on the upper right corner
2. Click on `Export Settings` button, choose `Select All` and Confirm. This will save your Node configuration
3. Now choose `Factory Reset` option
4. Confirm that you want to reset your device
5. Go to Bluetooth System settings and remove pairing of the device, so you can connect again
6. Connect your device in the app and enter the PIN
7. Navigate to Gear icon(Settings) on the upper right corner
8. Click on `Import Settings` and choose the file from 2., click on `Select All` and Confirm
9. Find `Reboot` button on of the Settings list

**B: You're not able to connect to the App**
1. Connect USB cable to your device
2. Go to https://flasher.meshcore.io
3. Search for your device in the list
4. Choose `Companion Bluetooth`
5. Press `Enter DFU mode` button, choose your USB device
6. Press `Erase Flash` button, choose the device again and wait until it completes
7. Press `Flash!` button and choose the USB device last time
8. The device is erased and newest firmware is installed
9. You might need to remove the pairing in Bluetooth System Settings in order to re-pair the app again.

Separately, starting in firmware version 1.7.0, there is a CLI Rescue mode. If your device has a user button (e.g. some RAK, T114), you can activate the rescue mode by holding down the user button of the device within 8 seconds of boot. Then you can use the 'Console' on <https://flasher.meshcore.io>

Expand All @@ -716,9 +721,9 @@ Separately, starting in firmware version 1.7.0, there is a CLI Rescue mode. If y

`NetworkError: Failed to execute 'open' on 'SerialPort': Failed to open serial port.`

Allow the browser user on it:
Allow user access on your USB port:

`# setfacl -m u:YOUR_USER_HERE:rw /dev/ttyUSB0`
`sudo setfacl -m u:$USER:rw /dev/ttyUSB0`

---

Expand Down
16 changes: 8 additions & 8 deletions docs/kiss_modem_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ Standard KISS framing per the KA9Q/K3MC specification.
| `0xDD` | TFESC | Escaped FESC (FESC + TFESC = 0xDB) |

```
┌──────┬───────────┬──────────────┬──────┐
│ FEND │ Type Byte │ Data (escaped)│ FEND │
│ 0xC0 │ 1 byte │ 0-510 bytes │ 0xC0 │
└──────┴───────────┴──────────────┴──────┘
┌──────┬───────────┬────────────────┬──────┐
│ FEND │ Type Byte │ Data (escaped) │ FEND │
│ 0xC0 │ 1 byte │ 0-510 bytes │ 0xC0 │
└──────┴───────────┴────────────────┴──────┘
```

### Type Byte
Expand Down Expand Up @@ -82,10 +82,10 @@ MeshCore-specific functionality uses the standard KISS SetHardware command. The
### Frame Format

```
┌──────┬──────┬─────────────┬──────────────┬──────┐
│ FEND │ 0x06 │ Sub-command │ Data (escaped)│ FEND │
│ 0xC0 │ │ 1 byte │ variable │ 0xC0 │
└──────┴──────┴─────────────┴──────────────┴──────┘
┌──────┬──────┬─────────────┬────────────────┬──────┐
│ FEND │ 0x06 │ Sub-command │ Data (escaped) │ FEND │
│ 0xC0 │ │ 1 byte │ variable │ 0xC0 │
└──────┴──────┴─────────────┴────────────────┴──────┘
```

### Request Sub-commands (Host to TNC)
Expand Down
105 changes: 101 additions & 4 deletions docs/nrf52_power_management.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Shutdown reason codes (stored in GPREGRET2):
| RAK4631 (`rak4631`) | Yes | Yes | Yes |
| Heltec T114 (`heltec_t114`) | Yes | Yes | Yes |
| GAT562 Mesh Watch13 | Yes | Yes | Yes |
| Promicro nRF52840 | No | No | No |
| Promicro nRF52840 | Yes | Yes | Yes |
| RAK WisMesh Tag | No | No | No |
| Heltec Mesh Solar | No | No | No |
| LilyGo T-Echo / T-Echo Lite | No | No | No |
Expand All @@ -57,7 +57,20 @@ Shutdown reason codes (stored in GPREGRET2):
| Minewsemi ME25LS01 | No | No | No |

Notes:
- "Implemented" reflects Phase 1 (boot lockout + shutdown reason capture).
- Promicro also checks battery voltage every 5 seconds while running. Three
consecutive readings below 3100 mV trigger peripheral shutdown and SYSTEMOFF
with LPCOMP recovery enabled. USB power bypasses this runtime check.
- On Promicro, `PWRMGT_VOLTAGE_BOOTLOCK` and `PWRMGT_VOLTAGE_SHUTDOWN` are ADC
thresholds, not the LPCOMP wake threshold. The retained empirical setting
`PWRMGT_LPCOMP_REFSEL=4` selects 5/8 VDD; measure VDD and the battery divider
to determine the actual recovery voltage. SYSTEMOFF does not disconnect the
battery from the board's other loads.
- Promicro releases radio SPI, reset, RF-switch and status pins to inputs
without pulls before disabling external VCC, to avoid feeding the unpowered
module through GPIO signals. Runtime shutdown also stops SPI first; boot
lockout skips SPI uninitialization because SPI has not been started yet.
- "Implemented" reflects Phase 1 (boot lockout + shutdown reason capture),
with the additional runtime cutoff described above for Promicro.
- User power-off on Heltec T114 does not enable LPCOMP wake.
- VBUS detection is used to skip boot lockout on external power, and VBUS wake is configured alongside LPCOMP when supported hardware exposes VBUS to the nRF52.

Expand Down Expand Up @@ -138,7 +151,7 @@ The LPCOMP (Low Power Comparator) is configured to:
- Monitor the specified AIN channel (0-7 corresponding to P0.02-P0.05, P0.28-P0.31)
- Compare against VDD fraction reference (REFSEL: 0-6=1/8..7/8, 7=ARef, 8-15=1/16..15/16)
- Detect UP events (voltage rising above threshold)
- Use 50mV hysteresis for noise immunity
- Use no comparator hysteresis (as of firmware 1.18)
- Wake the device from SYSTEMOFF when triggered

VBUS wake is enabled via the POWER peripheral USBDETECTED event whenever `configureVoltageWake()` is used. This requires USB VBUS to be routed to the nRF52 (typical on nRF52840 boards with native USB).
Expand Down Expand Up @@ -199,6 +212,90 @@ does not override them reports `Not available` rather than an error. ESP32
boards override the reset half with `esp_reset_reason()`, so they return a real
reset reason and `Not available` for the shutdown reason.

## Promicro / Faketec hardware and configuration

The standard Promicro environments use the bench-tested battery divider below.
Replace both original `1002` (10 kOhm) resistors before using this configuration:

```text
BAT+ --- 160 kOhm ---+--- P0.31 / AIN7 (Arduino pin 17)
|
240 kOhm
|
GND
```

Confirm which resistor connects to BAT+ and which connects to GND before
replacement. This is a hardware-specific configuration, not a firmware-only
upgrade for an unchanged 10k/10k board. The divider draws approximately 8.25 uA
at 3.3 V, versus 165 uA for the original divider. Resistor tolerances and ADC
errors still require checking the reported voltage against a meter.

| Setting | Default |
| --- | --- |
| ADC multiplier | 1.46484375 mV/count = (3600 / 4096) x (160 + 240) / 240 |
| ADC resolution / acquisition | 12 bits / 40 us |
| Samples per voltage reading | 8 |
| Boot lock / runtime shutdown | 3100 mV / 3100 mV |
| Runtime monitoring | Every 5 s; three consecutive low readings |
| LPCOMP input / reference | AIN7 / REFSEL=4, 5/8 VDD |

Any saved `adc.multiplier` overrides the compiled default after preferences
are loaded, while the early boot check uses the compiled default. After the
hardware/firmware update, run `set adc.multiplier 0` to restore the board default
and compare the reading with a meter before testing shutdown. Only save a new
calibration after checking several voltages.

Runtime shutdown first stops peripherals. Before disabling external VCC via
P0.13, the board stops SPI and releases radio SPI, NSS, RESET, BUSY, DIO1 and
RXEN pins to inputs without pulls. GPIO state is retained in SYSTEMOFF; leaving
NSS/RESET driven high was consistent with backfeeding the unpowered radio.
Boot lockout applies the same pin isolation but skips SPI uninitialization,
because SPI has not been initialized at that point.

LPCOMP and VBUS recovery are armed for low-voltage and boot-protection shutdowns.
Manual `powerOff()` remains a user shutdown without LPCOMP recovery. USB power
bypasses the boot voltage check and runtime low-voltage shutdown.

### Bench validation (2026-11-13)

Results reported on one Promicro/Faketec assembly using a bench supply, with
battery disconnected. The final divider test used the repeater without debug
logging and with GPS disabled. Standard environments retain their existing GPS
configuration; GPS operation and additional peripheral loads were not validated
by these tests.

| Measurement / test | Observed result |
| --- | --- |
| Final 160k/240k divider, REFSEL=4, firmware threshold 3100 mV | Shutdown at 3.08 V actual supply voltage |
| Recovery with the same configuration | Wake at 3.41 V actual supply voltage |
| Margin between observed shutdown and recovery | Approximately 330 mV |
| Battery voltage indication | Approximately 10 mV difference from supply/meter |
| Radio VCC and RESET after shutdown pin isolation | Fell from approximately 2.56 V to 0.02 V |
| P0.13 after shutdown pin isolation | 0 V (previously approximately 0.52 V) |
| Total shutdown current | Supply displayed 0.000 A, below its approximately 1 mA resolution; not a measured zero-current result |
| Earlier shutdown current before pin isolation | Approximately 7 mA |

Diagnostic logs confirmed `Wake from LPCOMP` (RESETREAS 0x20000), previous
shutdown `Low Voltage` (0x4C), and successful radio initialization after wake.
VBUS wake was also reported working during the earlier diagnostic tests. Repeat
LPCOMP and VBUS tests after flashing the cleaned standard build; no hardware
validation of that rebuilt artifact is implied by successful compilation.

With the earlier 150k/240k divider, REFSEL=4 recovered at 3.11-3.15 V, leaving
only 40-60 mV of observed margin. REFSEL=13 (11/16 VDD) raised recovery to
3.6-3.7 V. The final 160k/240k divider with REFSEL=4 provided the preferred
observed margin. LPCOMP compares against a fraction of VDD, not an absolute
battery reference: measure recovery on each hardware revision rather than
assuming an exact threshold from indirect VDD measurements.

For repeat tests, remove board USB and the UART adapter, lower the supply slowly
and allow at least 20 s at each step, then raise it slowly without interrupting
power. Measure actual voltage, current and wake stability under load. When
checking VBUS wake, ensure USB charging cannot drive reverse current into the
bench supply. SYSTEMOFF reduces consumption but does not physically disconnect
the battery or replace hardware battery protection.

## Debug Output

When `MESH_DEBUG=1` is enabled, the power management module outputs:
Expand All @@ -210,7 +307,7 @@ DEBUG: PWRMGT: LPCOMP wake configured (AIN7, ref=3/8 VDD)

## Phase 2 (Planned)

- Runtime voltage monitoring
- General runtime voltage monitoring (Promicro already implements the fixed policy above)
- Voltage state machine (Normal -> Warning -> Critical -> Shutdown)
- Configurable thresholds
- Load shedding callbacks for power reduction
Expand Down
66 changes: 66 additions & 0 deletions docs/radio_presets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Radio Presets

The radio presets are currently stored on the MeshCore App API server.

This allows us to update the presets without releasing new application updates.

The presets can be fetched from [https://api.meshcore.nz/api/v1/config](https://api.meshcore.nz/api/v1/config)

If you'd like a new radio preset to be added, this will need to be brought up for discussion in the [MeshCore Discord](https://meshcore.gg) server, or via the [issues section](https://github.com/meshcore-dev/MeshCore/issues) in our GitHub repo.

Before a new preset will be considered for being added, local radio regulations must be researched by the person suggesting the preset, and investigation of the frequencies with an SDR is advised to ensure the least interference to provide a decent user experience.

Once a preset is added, it's unlikely to be changed. Adding too many presets can lead to user frustration, as new users won't know which preset to select during setup.

At this time, presets provided by the MeshCore App API are just suggestions, but you are free to configure any radio settings through the companion applications, provided they comply with local laws/regulations.

> Note: We are planning to implement deep linking such as meshcore:// URLs, and QR codes so local mesh networks can easily distribute their own settings, without relying on the internet, or all the companion applications to provide all the settings.

## JSON Response

See the example JSON response below, which shows the expected format provided by the API server.

Your application should be programmed to expect any of the JSON keys to be missing from the response, as the format could change at any time without any notification.

Please configure an appropriate User Agent header string when sending your request to the server. We should be able to reach out to you if needed.

> Note: Some presets contain an optional `network_settings` section which defines the `path_hash_size` to use for this mesh network.

```json
{
"config": {
"suggested_radio_settings": {
"info_message": "These presets are suggested by the community.",
"entries": [
{
"title": "Australia (Narrow)",
"description": "916.575MHz / SF7 / BW62.5 / CR7",
"frequency": "916.575",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "7"
},
{
"title": "New Zealand (Narrow)",
"description": "917.375MHz / SF7 / BW62.5 / CR5 / 2B",
"frequency": "917.375",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "5",
"network_settings": {
"path_hash_size": 2
}
},
{
"title": "Portugal 868",
"description": "869.618MHz / SF7 / BW62.5 / CR6",
"frequency": "869.618",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "6"
}
]
}
}
}
```
9 changes: 5 additions & 4 deletions src/helpers/NRF52Board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,14 @@ void NRF52Board::configureVoltageWake(uint8_t ain_channel, uint8_t lpcomp_refsel
NRF_LPCOMP->ENABLE = LPCOMP_ENABLE_ENABLE_Disabled;

// Select analog input (AIN0-7 maps to PSEL 0-7)
NRF_LPCOMP->PSEL = ((uint32_t)PWRMGT_LPCOMP_AIN << LPCOMP_PSEL_PSEL_Pos) & LPCOMP_PSEL_PSEL_Msk;
NRF_LPCOMP->PSEL = ((uint32_t)ain_channel << LPCOMP_PSEL_PSEL_Pos) & LPCOMP_PSEL_PSEL_Msk;

// Reference: REFSEL (0-6=1/8..7/8, 7=ARef, 8-15=1/16..15/16)
NRF_LPCOMP->REFSEL = ((uint32_t)lpcomp_refsel << LPCOMP_REFSEL_REFSEL_Pos) & LPCOMP_REFSEL_REFSEL_Msk;

// Detect UP events (voltage rises above threshold for battery recovery)
NRF_LPCOMP->ANADETECT = LPCOMP_ANADETECT_ANADETECT_Up;
NRF_LPCOMP->HYST = LPCOMP_HYST_HYST_NoHyst;

// Clear stale events/interrupts before enabling wake
NRF_LPCOMP->EVENTS_READY = 0;
Expand All @@ -219,12 +220,12 @@ void NRF52Board::configureVoltageWake(uint8_t ain_channel, uint8_t lpcomp_refsel
}

if (lpcomp_refsel == 7) {
MESH_DEBUG_PRINTLN("PWRMGT: LPCOMP wake armed (AIN%d, ref=ARef)", PWRMGT_LPCOMP_AIN);
MESH_DEBUG_PRINTLN("PWRMGT: LPCOMP wake armed (AIN%d, ref=ARef)", ain_channel);
} else if (lpcomp_refsel <= 6) {
MESH_DEBUG_PRINTLN("PWRMGT: LPCOMP wake armed (AIN%d, ref=%d/8 VDD)", PWRMGT_LPCOMP_AIN, lpcomp_refsel + 1);
MESH_DEBUG_PRINTLN("PWRMGT: LPCOMP wake armed (AIN%d, ref=%d/8 VDD)", ain_channel, lpcomp_refsel + 1);
} else {
uint8_t ref_num = (uint8_t)((lpcomp_refsel - 8) * 2 + 1);
MESH_DEBUG_PRINTLN("PWRMGT: LPCOMP wake armed (AIN%d, ref=%d/16 VDD)", PWRMGT_LPCOMP_AIN, ref_num);
MESH_DEBUG_PRINTLN("PWRMGT: LPCOMP wake armed (AIN%d, ref=%d/16 VDD)", ain_channel, ref_num);
}
}

Expand Down
Loading