* LR11x0: try XTAL before TCXO when oscillator type is uncertain On boards with TCXO_OPTIONAL, a TCXO-first attempt either hangs RadioLib's calibration wait forever on a bare/non-TCXO module (unpatched upstream), or costs a slow failed attempt before falling back even once that's fixed with a timeout. Measured on hardware: XTAL succeeds immediately on a bare module (~350ms) and fails fast and cleanly on a genuine TCXO module (~300ms, RADIOLIB_ERR_SPI_CMD_FAILED), so trying XTAL first is a strict improvement for hang-avoidance regardless of which oscillator is actually present. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * compacted * fix review comment * fix femtofox switches * correct the correction * 13 * 3s timeout * Treat SPI_CMD_TIMEOUT as an LR11x0 init failure The BUSY watchdog breaks RadioLib's wait, so the next bounded transfer returns SPI_CMD_TIMEOUT rather than SPI_CMD_FAILED. Only the latter was checked, so a watchdog-triggered failure fell through to getVersionInfo(), setRfSwitchTable() and startReceive() against an unresponsive chip. Also use Throttle::isWithinTimespanMs() for the watchdog's elapsed-time check instead of raw millis() arithmetic. * Drop the BUSY watchdog and probe XTAL before TCXO The watchdog bounded RadioLib's unbounded BUSY wait in LR11x0::config() by having LockingArduinoHal::digitalRead() report a stuck pin low exactly once. That let a TCXO-first attempt fail cleanly rather than hang, but it meant lying to RadioLib about a GPIO from a HAL shared by every radio driver. Ordering the attempts XTAL-first avoids the hang outright instead: attempt 1 configures no DIO3 Vref, so there is no calibration wait to get stuck in, and the TCXO fallback is only reached on a module that answered and refused XTAL. Attempts are now XTAL, then TCXO, then a settling retry on whichever oscillator was settled on - after a fallback that is a second TCXO attempt. Only TCXO_OPTIONAL builds probe XTAL; a variant that declares a Vref unconditionally still goes straight to it and never probes XTAL at all. SPI_CMD_TIMEOUT stays a failure alongside SPI_CMD_FAILED: a bounded per-command BUSY wait in Module::SPItransferStream() reports it in its own right, independently of the removed watchdog. * Drop a stray tab from the promicro TCXO readme trunk fmt: prettier flags the whitespace-only line inside the <summary> block, which was the only failing check on the PR. --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
8.0 KiB
Notes
News 2025-12-04 - The GPS pin definitions have been changed!!! This has no material effect on current builds, but future builders may wish to review how they are using the wires.
General
The pinout is contained in the variant.h file, and a generic schematic is located in this directory.
This variant is suitable for both TCXO and XTAL types of modules. The old XTAL variant has been removed to reduce confusion.
Note on DIO2, RXEN, TXEN, and RF switching
Several modules require external switching between transmit (Tx) and receive (Rx). This can be achieved using several methods:
- Link the TXEN pin on the radio module to DIO2 on the same module, and then connect RXEN on the radio module to pin 0.17 on the Pro-Micro.
- Use DIO2 to drive a logic inverter, so that when DIO2 is
high, RXEN islow, and vice versa. - Use DIO2 to drive a pair of MOSFETs or transistors to supply the same function.
RXEN is not required to be connected if the selected module already has internal RF switching, or if external RF switching logic is already applied. Also worth noting that the Seeed WIO SX1262 in particular only has RXEN exposed (marked RF_SW) and has the DIO2-TXEN link internally.
Making a node based on this variant
Making your own node based on this design is straightforward. There are various open source and free to use PCB design files available, or you can solder wires directly from a module to the pro-micro.
< Click to expand > The table of known modules is at the bottom of the variant.h, and reproduced here for convenience.
| Mfr | Module | TCXO | RF Switch | Notes |
|---|---|---|---|---|
| Ebyte | E22-900M22S | Yes | Ext | |
| Ebyte | E22-900MM22S | No | Ext | |
| Ebyte | E22-900M30S | Yes | Ext | |
| Ebyte | E22-900M33S | Yes | Ext | MAX_POWER must be set to 8 for this |
| Ebyte | E220-900M22S | No | Ext | LLCC68, looks like DIO3 not connected |
| AI-Thinker | RA-01SH | No | Int | SX1262 |
| Heltec | HT-RA62 | Yes | Int | |
| NiceRF | Lora1262 | yes | Int | |
| Waveshare | Core1262-HF | yes | Ext | |
| Waveshare | LoRa Node Module | yes | Int | |
| Seeed | Wio-SX1262 | yes | Ext | Cute! DIO2/TXEN are not exposed |
| Seeed | Wio-LR1121 | yes | Int | LR1121, build -D LR1121_MODULE_WIO |
| AI-Thinker | RA-02 | No | Int | SX1278 433mhz band only |
| RF Solutions | RFM95 | No | Int | Untested |
| Ebyte | E80-900M2213S | Yes | Int | LR1121 radio |
LR1121 modules - E80 is the default
The E80 from CDEbyte is the most obtainable module at present, and has been selected as the default option.
Naturally, CDEbyte have chosen to ignore the generic Semtech implementation of the RF switching logic and have supplied confusing and contradictory documentation, which is explained below.
tl;dr: The E80 is chosen as the default. If you wish to use another module, select it with an LR1121_MODULE_* build flag, or adjust the table in rfswitch.h accordingly.
rfswitch.h carries a matrix for each known LR1121 module, guarded by a build flag:
| Build flag | Module |
|---|---|
| (none) | Ebyte E80-900M2213S |
LR1121_MODULE_E80 |
Ebyte E80-900M2213S |
LR1121_MODULE_WIO |
Seeed Wio-LR1121 |
Add it to your environment in platformio.ini:
build_flags = ${nrf52840_base.build_flags}
-I variants/nrf52840/diy/nrf52_promicro_diy_tcxo
-D NRF52_PROMICRO_DIY
-D LR1121_MODULE_WIO
E80 switching - the saga
The CDEbyte implementation of the LR1121 is contained in their E80 module. As stated above, CDEbyte have chosen to ignore the generic Semtech implementation of the RF switching logic and have their own table, which is located at the bottom of the page here, and reflected on page 6 of their user manual, and reproduced below:
| DIO5/RFSW0 | DIO6/RFSW1 | RF status |
|---|---|---|
| 0 | 0 | RX |
| 0 | 1 | TX (Sub-1GHz low power mode) |
| 1 | 0 | TX (Sub-1GHz high power mode) |
| 1 | 1 | TX(2.4GHz) |
However, looking at the sample code they provide on page 9, the values would be:
| DIO5/RFSW0 | DIO6/RFSW1 | RF status |
|---|---|---|
| 0 | 1 | RX |
| 1 | 1 | TX (Sub-1GHz low power mode) |
| 1 | 0 | TX (Sub-1GHz high power mode) |
| 0 | 0 | TX(2.4GHz) |
The Semtech default, the values are (taken from here):
< Click to expand >
.rfswitch = {
.enable = LR11XX_SYSTEM_RFSW0_HIGH | LR11XX_SYSTEM_RFSW1_HIGH | LR11XX_SYSTEM_RFSW2_HIGH,
.standby = 0,
.rx = LR11XX_SYSTEM_RFSW0_HIGH,
.tx = LR11XX_SYSTEM_RFSW0_HIGH | LR11XX_SYSTEM_RFSW1_HIGH,
.tx_hp = LR11XX_SYSTEM_RFSW1_HIGH,
.tx_hf = 0,
.gnss = LR11XX_SYSTEM_RFSW2_HIGH,
.wifi = 0,
},
| DIO5/RFSW0 | DIO6/RFSW1 | RF status |
|---|---|---|
| 1 | 0 | RX |
| 1 | 1 | TX (Sub-1GHz low power mode) |
| 0 | 1 | TX (Sub-1GHz high power mode) |
| 0 | 0 | TX(2.4GHz) |
It is evident from the tables above that there is no real consistency to those provided by Ebyte.
An experiment
Tests were conducted in each of the three configurations between a known-good SX1262 and an E80, passing packets in both directions and recording the reported RSSI. The E80 was set at 22db and 14db to activate the high and low power settings respectively. The results are shown in the chart below.
Conclusion
The RF switching is based on the code example given. Logically, this shows the DIO5 and DIO6 are swapped compared to the reference design.
Seeed Wio-LR1121
The Wio is the counter-example to the E80: it follows the Semtech reference exactly, so no swap is needed. Its internal switch is a Skyworks SKY13373-460LF, controlled by DIO5 (V1) and DIO6 (V2) only - there is no third control line, so DIO7 is left out of the pin list. Section 4.5 of the module datasheet, "True Table of the Internal RF Switch", gives:
| V1 (DIO5) | V2 (DIO6) | Status | RadioLib mode |
|---|---|---|---|
| 0 | 0 | Shutdown | MODE_STBY |
| 1 | 0 | RFI_P_LF & RFI_N_LF | MODE_RX |
| 0 | 1 | RFO_HP_LF | MODE_TX_HP |
| 1 | 1 | RFO_LP_LF | MODE_TX |
Note that the LR1121 has no GNSS or WiFi scanning, so MODE_GNSS and MODE_WIFI are left in the shutdown state.
Select it with -D LR1121_MODULE_WIO.
If future DIYers wish to use a module not listed above, add a matrix for it to rfswitch.h behind a new LR1121_MODULE_* guard.
