mirror of https://github.com/meshcore-dev/MeshCore
committed by
GitHub
5 changed files with 276 additions and 0 deletions
@ -0,0 +1,24 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <Arduino.h> |
||||
|
#include <helpers/ESP32Board.h> |
||||
|
|
||||
|
// Lierda AM36 Pico dev board (L-LRMAM36-FANN4-PK02).
|
||||
|
// The L-LRMAM36-FANN4 module pairs an ESP32-S3 with a Semtech LR2021.
|
||||
|
// Nothing exotic at the board level: USB-C power, no battery divider on the
|
||||
|
// dev board. The only LED is a hardwired 3V3 power indicator (no status LED).
|
||||
|
class LierdaAM36Board : public ESP32Board { |
||||
|
public: |
||||
|
LierdaAM36Board() { } |
||||
|
|
||||
|
void begin() { |
||||
|
ESP32Board::begin(); |
||||
|
#ifdef PIN_USER_BTN |
||||
|
pinMode(PIN_USER_BTN, INPUT_PULLUP); // KEY, pressed = LOW
|
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
const char* getManufacturerName() const override { |
||||
|
return "Lierda AM36 Pico"; |
||||
|
} |
||||
|
}; |
||||
@ -0,0 +1,94 @@ |
|||||
|
# MeshCore on the Lierda AM36 Pico (L-LRMAM36-FANN4-PK02) |
||||
|
|
||||
|
Community variant for the Lierda AM36 Pico evaluation board. The on-board |
||||
|
L-LRMAM36-FANN4 module is an **ESP32-S3** (8MB flash / 8MB PSRAM) paired with a |
||||
|
**Semtech LR2021** Generation-4 LoRa transceiver. |
||||
|
|
||||
|
> Status: **hardware-validated** (Jul 2026) on a live mesh: radio init, noise |
||||
|
> floor sampling (~-119 dBm), BLE pairing with the iOS companion app, flood + |
||||
|
> direct TX with interrupt-driven send-complete, and two-way messaging with a |
||||
|
> Heltec Tracker v2 (SX1262) peer - i.e. confirmed LR2021 <-> SX1262 interop - |
||||
|
> at 927.875 MHz / BW 62.5 / SF9 / CR7, both nodes using muzi works 17 cm whip |
||||
|
> antennas (replies at SNR 3.25 dB). Also received channel messages from six |
||||
|
> third-party senders at 3-9 hops with full path reconstruction, and measured a |
||||
|
> third-party repeater (not operated by the author) at |
||||
|
> up 11.5 dB / down 13.0 dB. |
||||
|
> Requires the `CustomLR2021` radio classes from MeshCore PR #2944. |
||||
|
|
||||
|
## Hardware facts used by this variant |
||||
|
|
||||
|
| Signal | ESP32-S3 GPIO | Source | Verified | |
||||
|
|---|---|---|---| |
||||
|
| LR2021 SPI SCK | 40 | `esp32_lora_driver` Kconfig (`LIERDA_BOARD_LRMAM36_FANN4`) | yes (on air) | |
||||
|
| LR2021 SPI MOSI | 41 | same | yes | |
||||
|
| LR2021 SPI MISO | 42 | same | yes | |
||||
|
| LR2021 NSS | 39 | same | yes | |
||||
|
| LR2021 NRST | 38 | same | yes | |
||||
|
| LR2021 BUSY | 17 | same | yes | |
||||
|
| LR2021 IRQ | 21 - **wired to LR2021 DIO7** | Kconfig `LR20XX_DIO7_GPIO` | yes (TX-done + RX interrupts) | |
||||
|
| KEY button | 4 (schematic net `GPIO4/KEY1`) | schematic | **not yet** - left disabled | |
||||
|
|
||||
|
The IRQ DIO matters: the Seeed Wio-LR2021 (which PR #2944 targets) uses DIO8, |
||||
|
so this variant sets `-D LR2021_IRQ_DIO=7`. No external TCXO or RF-switch |
||||
|
GPIOs exist on the MCU side - the module handles RF internally. The board's |
||||
|
only LED is a hardwired 3V3 power indicator, so no `PIN_STATUS_LED` is defined. |
||||
|
|
||||
|
## Build |
||||
|
|
||||
|
1. Install VS Code + the PlatformIO extension. |
||||
|
2. Get the source with the LR2021 driver: |
||||
|
```bash |
||||
|
git clone https://github.com/meshcore-dev/MeshCore |
||||
|
cd MeshCore |
||||
|
git fetch origin pull/2944/head:lr2021 |
||||
|
git checkout lr2021 |
||||
|
``` |
||||
|
(Once PR #2944 is merged, plain `dev` works.) |
||||
|
3. Copy this `lierda_am36_pico/` folder into `variants/`. |
||||
|
(PlatformIO auto-discovers `variants/*/platformio.ini`.) |
||||
|
4. Radio parameters: builds inherit MeshCore's defaults; set your region's |
||||
|
frequency/BW/SF/CR from the companion app after first boot (settings are |
||||
|
persisted on the device), or override `LORA_*` flags in a |
||||
|
`platformio.local.ini` for your own builds. The module covers 863-930 MHz. |
||||
|
5. Build: |
||||
|
```bash |
||||
|
pio run -e Lierda_AM36_Pico_companion_radio_ble |
||||
|
``` |
||||
|
Other envs: `..._companion_radio_usb`, `..._repeater`. |
||||
|
Note: the iOS companion app connects over BLE only, so iPhone users want |
||||
|
the `_ble` build. |
||||
|
|
||||
|
## Flash |
||||
|
|
||||
|
1. Connect the Type-C port labelled **USB** (NOT the one labelled UART - that |
||||
|
goes to the CP2105 bridge). The USB port is the ESP32-S3's native |
||||
|
USB-JTAG/CDC and is what esptool talks to. |
||||
|
2. ```bash |
||||
|
pio run -e Lierda_AM36_Pico_companion_radio_ble -t upload |
||||
|
``` |
||||
|
3. If the port doesn't enumerate or upload fails to sync: hold **BOOT**, tap |
||||
|
**RST**, release **BOOT** (forces download mode), then retry the upload. |
||||
|
4. Tap **RST** after flashing completes. |
||||
|
|
||||
|
## Verify |
||||
|
|
||||
|
- Serial console is on the same USB port |
||||
|
(`pio device monitor -e Lierda_AM36_Pico_companion_radio_ble`). Note the |
||||
|
ESP32-S3 re-enumerates USB on reset, so the monitor may need a restart after |
||||
|
tapping RST. A failed radio bring-up prints |
||||
|
`ERROR: LR2021 init failed: <code>` and halts (no BLE advertising). |
||||
|
- **Attach the LoRa antenna before any TX.** |
||||
|
- Pair from the MeshCore app over Bluetooth (default PIN `123456`, set via |
||||
|
`BLE_PIN_CODE`), set your region's radio parameters in the app, and send a |
||||
|
channel message or advert. |
||||
|
|
||||
|
## Known quirks / notes |
||||
|
|
||||
|
- SPI to the LR2021 sits on GPIO39-42, which are the S3's JTAG pins. That's |
||||
|
fine (flashing/debug uses USB-JTAG), just don't try external JTAG. |
||||
|
- PSRAM is present but left disabled - MeshCore doesn't need it, and octal |
||||
|
PSRAM misconfiguration is a classic S3 boot-loop source. |
||||
|
- The KEY button (schematic net `GPIO4/KEY1`) is left disabled until traced |
||||
|
on hardware; uncomment `PIN_USER_BTN` in `platformio.ini` once confirmed. |
||||
|
- PR #2944's wrapper drops the radio to standby before every `startReceive()` |
||||
|
(LR2021 wedges if re-armed mid-RX) - don't "optimize" that away. |
||||
@ -0,0 +1,100 @@ |
|||||
|
; Lierda AM36 Pico (L-LRMAM36-FANN4-PK02) |
||||
|
; Module: L-LRMAM36-FANN4 = ESP32-S3 (8MB flash / 8MB PSRAM) + Semtech LR2021 |
||||
|
; |
||||
|
; Pin map taken from lierda-iot/esp32_lora_driver Kconfig defaults for |
||||
|
; LIERDA_BOARD_LRMAM36_FANN4 and verified against the board schematic |
||||
|
; (L-LRMAM36-FANN4-PK02_SCH_V01.pdf): |
||||
|
; LR2021 SPI: SCK=40 MOSI=41 MISO=42 NSS=39 |
||||
|
; LR2021 ctrl: NRST=38 BUSY=17 IRQ=GPIO21 (wired to LR2021 DIO7!) |
||||
|
; KEY button: GPIO4 per schematic net label (not yet verified on hardware) |
||||
|
; LED1: hardwired 3V3 power indicator (not GPIO-controllable) |
||||
|
; |
||||
|
; Requires the CustomLR2021 radio classes from MeshCore PR #2944. |
||||
|
; Flash via the board's "USB" Type-C port (ESP32-S3 native USB), not "UART". |
||||
|
|
||||
|
[Lierda_AM36_Pico] |
||||
|
extends = esp32_base |
||||
|
board = esp32-s3-devkitc-1 |
||||
|
board_build.mcu = esp32s3 |
||||
|
board_build.flash_size = 8MB |
||||
|
board_upload.flash_size = 8MB |
||||
|
build_flags = ${esp32_base.build_flags} |
||||
|
-I variants/lierda_am36_pico |
||||
|
-D LIERDA_AM36_PICO |
||||
|
; --- native-USB serial console on the "USB" Type-C port --- |
||||
|
-D ARDUINO_USB_MODE=1 |
||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1 |
||||
|
; --- LR2021 wiring (ESP32-S3 GPIO numbers) --- |
||||
|
-D P_LORA_SCLK=40 |
||||
|
-D P_LORA_MOSI=41 |
||||
|
-D P_LORA_MISO=42 |
||||
|
-D P_LORA_NSS=39 |
||||
|
-D P_LORA_RESET=38 |
||||
|
-D P_LORA_BUSY=17 |
||||
|
-D P_LORA_DIO_1=21 |
||||
|
; host IRQ line is routed from the LR2021's DIO7 (PR default is DIO8 for |
||||
|
; the Seeed Wio-LR2021 - this override is essential on the Lierda module) |
||||
|
-D LR2021_IRQ_DIO=7 |
||||
|
; --- radio driver selection --- |
||||
|
-D RADIO_CLASS=CustomLR2021 |
||||
|
-D WRAPPER_CLASS=CustomLR2021Wrapper |
||||
|
-D LORA_TX_POWER=22 |
||||
|
; --- board UI --- |
||||
|
; KEY button is believed to be GPIO4 (schematic net GPIO4/KEY1) but has not |
||||
|
; been traced/verified on hardware yet; uncomment once confirmed: |
||||
|
; -D PIN_USER_BTN=4 |
||||
|
; The board's only LED (LED1) is a hardwired 3V3 power indicator - there is |
||||
|
; no GPIO-controllable status LED, so PIN_STATUS_LED is not defined. |
||||
|
build_src_filter = ${esp32_base.build_src_filter} |
||||
|
+<../variants/lierda_am36_pico> |
||||
|
+<helpers/ui/MomentaryButton.cpp> |
||||
|
lib_deps = |
||||
|
${esp32_base.lib_deps} |
||||
|
|
||||
|
; ---------------- Companion (phone app over the USB port) ---------------- |
||||
|
[env:Lierda_AM36_Pico_companion_radio_usb] |
||||
|
extends = Lierda_AM36_Pico |
||||
|
build_flags = |
||||
|
${Lierda_AM36_Pico.build_flags} |
||||
|
-D MAX_CONTACTS=350 |
||||
|
-D MAX_GROUP_CHANNELS=40 |
||||
|
-D OFFLINE_QUEUE_SIZE=256 |
||||
|
; -D MESH_PACKET_LOGGING=1 |
||||
|
; -D MESH_DEBUG=1 |
||||
|
build_src_filter = ${Lierda_AM36_Pico.build_src_filter} |
||||
|
+<../examples/companion_radio/*.cpp> |
||||
|
lib_deps = |
||||
|
${Lierda_AM36_Pico.lib_deps} |
||||
|
densaugeo/base64 @ ~1.4.0 |
||||
|
|
||||
|
; ---------------- Companion over BLE ---------------- |
||||
|
[env:Lierda_AM36_Pico_companion_radio_ble] |
||||
|
extends = Lierda_AM36_Pico |
||||
|
build_flags = |
||||
|
${Lierda_AM36_Pico.build_flags} |
||||
|
-D MAX_CONTACTS=350 |
||||
|
-D MAX_GROUP_CHANNELS=40 |
||||
|
-D BLE_PIN_CODE=123456 |
||||
|
-D OFFLINE_QUEUE_SIZE=256 |
||||
|
build_src_filter = ${Lierda_AM36_Pico.build_src_filter} |
||||
|
+<helpers/esp32/*.cpp> |
||||
|
+<../examples/companion_radio/*.cpp> |
||||
|
lib_deps = |
||||
|
${Lierda_AM36_Pico.lib_deps} |
||||
|
densaugeo/base64 @ ~1.4.0 |
||||
|
|
||||
|
; ---------------- Repeater ---------------- |
||||
|
[env:Lierda_AM36_Pico_repeater] |
||||
|
extends = Lierda_AM36_Pico |
||||
|
build_src_filter = ${Lierda_AM36_Pico.build_src_filter} |
||||
|
+<../examples/simple_repeater/*.cpp> |
||||
|
build_flags = |
||||
|
${Lierda_AM36_Pico.build_flags} |
||||
|
-D ADVERT_NAME='"AM36 Repeater"' |
||||
|
-D ADVERT_LAT=0.0 |
||||
|
-D ADVERT_LON=0.0 |
||||
|
-D ADMIN_PASSWORD='"password"' |
||||
|
-D MAX_NEIGHBOURS=50 |
||||
|
lib_deps = |
||||
|
${Lierda_AM36_Pico.lib_deps} |
||||
|
${esp32_ota.lib_deps} |
||||
@ -0,0 +1,34 @@ |
|||||
|
#include <Arduino.h> |
||||
|
#include "target.h" |
||||
|
|
||||
|
#include <helpers/ArduinoHelpers.h> |
||||
|
|
||||
|
LierdaAM36Board board; |
||||
|
|
||||
|
// LR2021 on dedicated SPI pins (module-internal wiring; see platformio.ini)
|
||||
|
static SPIClass spi; |
||||
|
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); |
||||
|
|
||||
|
WRAPPER_CLASS radio_driver(radio, board); |
||||
|
|
||||
|
ESP32RTCClock fallback_clock; |
||||
|
AutoDiscoverRTCClock rtc_clock(fallback_clock); |
||||
|
SensorManager sensors; // no-op stub - dev board has no on-board sensors
|
||||
|
|
||||
|
#ifdef PIN_USER_BTN |
||||
|
MomentaryButton user_btn(PIN_USER_BTN, 1000, true); // KEY, active low
|
||||
|
#endif |
||||
|
|
||||
|
bool radio_init() { |
||||
|
fallback_clock.begin(); |
||||
|
rtc_clock.begin(Wire); |
||||
|
|
||||
|
// CustomLR2021::std_init() routes the IRQ to DIO7 (LR2021_IRQ_DIO),
|
||||
|
// brings up SPI on P_LORA_SCLK/MISO/MOSI, and applies LORA_* defaults.
|
||||
|
return radio.std_init(&spi); |
||||
|
} |
||||
|
|
||||
|
mesh::LocalIdentity radio_new_identity() { |
||||
|
RadioNoiseListener rng(radio); |
||||
|
return mesh::LocalIdentity(&rng); // create new random identity
|
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#define RADIOLIB_STATIC_ONLY 1 |
||||
|
#include <RadioLib.h> |
||||
|
#include <helpers/radiolib/RadioLibWrappers.h> |
||||
|
#include <helpers/ESP32Board.h> |
||||
|
// CustomLR2021 / CustomLR2021Wrapper come from MeshCore PR #2944
|
||||
|
#include <helpers/radiolib/CustomLR2021Wrapper.h> |
||||
|
#include <helpers/AutoDiscoverRTCClock.h> |
||||
|
#include <helpers/SensorManager.h> |
||||
|
#include <helpers/ui/MomentaryButton.h> |
||||
|
#include "LierdaAM36Board.h" |
||||
|
|
||||
|
extern LierdaAM36Board board; |
||||
|
extern WRAPPER_CLASS radio_driver; |
||||
|
extern AutoDiscoverRTCClock rtc_clock; |
||||
|
extern SensorManager sensors; |
||||
|
|
||||
|
#ifdef PIN_USER_BTN |
||||
|
extern MomentaryButton user_btn; |
||||
|
#endif |
||||
|
|
||||
|
bool radio_init(); |
||||
|
mesh::LocalIdentity radio_new_identity(); |
||||
Loading…
Reference in new issue