mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-03 19:12:00 +10:00
Lr1121 tcxo optional tries xtal first, and get all my yamls in a row (#11215)
* 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>
This commit is contained in:
co-authored by
Claude Sonnet 5
Thomas Göttgens
parent
03e6b80989
commit
e78b121d9f
@@ -1,30 +1,31 @@
|
||||
---
|
||||
Lora:
|
||||
## Ebyte E80-900M22S
|
||||
## This is a bit experimental
|
||||
##
|
||||
##
|
||||
## Ebyte E80-900M2213S
|
||||
## This is a bit experimental
|
||||
##
|
||||
##
|
||||
Module: lr1121
|
||||
gpiochip: 1 # subtract 32 from the gpio numbers
|
||||
DIO3_TCXO_VOLTAGE: 1.8
|
||||
CS: 16 #pin6 / GPIO48 1C0
|
||||
IRQ: 23 #pin17 / GPIO55 1C7
|
||||
IRQ: 23 #pin17 / GPIO55 1C7
|
||||
Busy: 22 #pin16 / GPIO54 1C6
|
||||
Reset: 25 #pin13 / GPIO57 1D1
|
||||
|
||||
|
||||
spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19)
|
||||
spiSpeed: 2000000
|
||||
|
||||
rfswitch_table:
|
||||
pins: [DIO5, DIO6, DIO7]
|
||||
MODE_STBY: [LOW, LOW, LOW]
|
||||
MODE_RX: [LOW, HIGH, LOW]
|
||||
MODE_TX: [HIGH, HIGH, LOW]
|
||||
MODE_TX_HP: [HIGH, LOW, LOW]
|
||||
MODE_TX_HF: [LOW, LOW, LOW]
|
||||
MODE_GNSS: [LOW, LOW, HIGH]
|
||||
MODE_WIFI: [LOW, LOW, LOW]
|
||||
|
||||
# CDEbyte do not follow the Semtech reference switching: DIO5/DIO6 are swapped.
|
||||
# DIO7 is wired to the GNSS path. See variants/nrf52840/diy/nrf52_promicro_diy_tcxo/readme.md
|
||||
rfswitch_table:
|
||||
pins: [DIO5, DIO6, DIO7]
|
||||
MODE_STBY: [LOW, LOW, LOW]
|
||||
MODE_RX: [LOW, HIGH, LOW]
|
||||
MODE_TX: [HIGH, HIGH, LOW]
|
||||
MODE_TX_HP: [HIGH, LOW, LOW]
|
||||
MODE_TX_HF: [LOW, LOW, LOW]
|
||||
MODE_GNSS: [LOW, LOW, HIGH]
|
||||
MODE_WIFI: [LOW, LOW, LOW]
|
||||
|
||||
General:
|
||||
MACAddressSource: eth0
|
||||
|
||||
@@ -1,46 +1,28 @@
|
||||
---
|
||||
Lora:
|
||||
## Ebyte E80-900M22S
|
||||
## This is a bit experimental
|
||||
##
|
||||
##
|
||||
## Generic LR1121 module (Semtech reference RF switch topology)
|
||||
## This is a bit experimental
|
||||
Module: lr1121
|
||||
gpiochip: 1 # subtract 32 from the gpio numbers
|
||||
DIO3_TCXO_VOLTAGE: 1.8
|
||||
CS: 16 #pin6 / GPIO48 1C0
|
||||
IRQ: 23 #pin17 / GPIO55 1C7
|
||||
IRQ: 23 #pin17 / GPIO55 1C7
|
||||
Busy: 22 #pin16 / GPIO54 1C6
|
||||
Reset: 25 #pin13 / GPIO57 1D1
|
||||
|
||||
|
||||
spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19)
|
||||
spiSpeed: 2000000
|
||||
|
||||
rfswitch_table:
|
||||
pins:
|
||||
- DIO5
|
||||
- DIO6
|
||||
MODE_STBY:
|
||||
- LOW
|
||||
- LOW
|
||||
MODE_RX:
|
||||
- HIGH
|
||||
- LOW
|
||||
MODE_TX:
|
||||
- HIGH
|
||||
- HIGH
|
||||
MODE_TX_HP:
|
||||
- LOW
|
||||
- HIGH
|
||||
MODE_TX_HF:
|
||||
- LOW
|
||||
- LOW
|
||||
MODE_GNSS:
|
||||
- LOW
|
||||
- LOW
|
||||
MODE_WIFI:
|
||||
- LOW
|
||||
- LOW
|
||||
|
||||
# Semtech reference switching (SWSD006): rx=RFSW0, tx=RFSW0|RFSW1, tx_hp=RFSW1.
|
||||
rfswitch_table:
|
||||
pins: [DIO5, DIO6]
|
||||
MODE_STBY: [LOW, LOW]
|
||||
MODE_RX: [HIGH, LOW]
|
||||
MODE_TX: [HIGH, HIGH]
|
||||
MODE_TX_HP: [LOW, HIGH]
|
||||
MODE_TX_HF: [LOW, LOW]
|
||||
MODE_GNSS: [LOW, LOW]
|
||||
MODE_WIFI: [LOW, LOW]
|
||||
|
||||
General:
|
||||
MACAddressSource: eth0
|
||||
|
||||
@@ -1,30 +1,37 @@
|
||||
---
|
||||
Lora:
|
||||
## Ebyte E80-900M22S
|
||||
## This is a bit experimental
|
||||
##
|
||||
##
|
||||
## Seeed Wio-LR1121
|
||||
## This is a bit experimental
|
||||
Module: lr1121
|
||||
gpiochip: 1 # subtract 32 from the gpio numbers
|
||||
DIO3_TCXO_VOLTAGE: 1.8
|
||||
CS: 16 #pin6 / GPIO48 1C0
|
||||
IRQ: 23 #pin17 / GPIO55 1C7
|
||||
IRQ: 23 #pin17 / GPIO55 1C7
|
||||
Busy: 22 #pin16 / GPIO54 1C6
|
||||
Reset: 25 #pin13 / GPIO57 1D1
|
||||
|
||||
|
||||
spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19)
|
||||
spiSpeed: 2000000
|
||||
|
||||
rfswitch_table:
|
||||
pins: [DIO5, DIO6, DIO7]
|
||||
MODE_STBY: [LOW, LOW, LOW]
|
||||
MODE_RX: [LOW, LOW, LOW]
|
||||
MODE_TX: [LOW, HIGH, LOW]
|
||||
MODE_TX_HP: [HIGH, LOW, LOW]
|
||||
# MODE_TX_HF: []
|
||||
# MODE_GNSS: []
|
||||
MODE_WIFI: [LOW, LOW, LOW]
|
||||
|
||||
# Internal RF switch is a Skyworks SKY13373-460LF driven by DIO5 (V1) and DIO6 (V2).
|
||||
# Datasheet section 4.5 "True Table of the Internal RF Switch":
|
||||
# V1 V2 Status
|
||||
# 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
|
||||
# This matches the Semtech reference topology (SWSD006):
|
||||
# rx=RFSW0, tx=RFSW0|RFSW1, tx_hp=RFSW1.
|
||||
# The LR1121 has no GNSS/WiFi scanning, so those modes are unused.
|
||||
rfswitch_table:
|
||||
pins: [DIO5, DIO6]
|
||||
MODE_STBY: [LOW, LOW]
|
||||
MODE_RX: [HIGH, LOW]
|
||||
MODE_TX: [HIGH, HIGH]
|
||||
MODE_TX_HP: [LOW, HIGH]
|
||||
MODE_TX_HF: [LOW, LOW]
|
||||
MODE_GNSS: [LOW, LOW]
|
||||
MODE_WIFI: [LOW, LOW]
|
||||
|
||||
General:
|
||||
MACAddressSource: eth0
|
||||
|
||||
@@ -47,7 +47,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||
#endif
|
||||
|
||||
// the 2.4G part maxes at 13dBm
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
#define LR1120_MAX_POWER portduino_config.lr1120_max_power
|
||||
#endif
|
||||
@@ -55,6 +54,23 @@ static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||
#define LR1120_MAX_POWER 13
|
||||
#endif
|
||||
|
||||
// Vref to assume for a board that declares a TCXO may be fitted without saying at what voltage.
|
||||
// "TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip." per
|
||||
// https://github.com/jgromes/RadioLib/blob/690a050ebb46e6097c5d00c371e961c1caa3b52e/src/modules/LR11x0/LR11x0.h#L471C26-L471C104
|
||||
#if defined(TCXO_OPTIONAL)
|
||||
#define LR11X0_TCXO_DEFAULT_VOLTAGE 1.6f
|
||||
#else
|
||||
#define LR11X0_TCXO_DEFAULT_VOLTAGE 0
|
||||
#endif
|
||||
|
||||
// A chip that never answers can surface either way depending on where RadioLib gave up: a bounded
|
||||
// per-command BUSY wait in Module::SPItransferStream() reports SPI_CMD_TIMEOUT rather than
|
||||
// SPI_CMD_FAILED, so both have to count as "the chip did not talk to us"
|
||||
static inline bool lr11x0SpiFailed(int res)
|
||||
{
|
||||
return res == RADIOLIB_ERR_SPI_CMD_FAILED || res == RADIOLIB_ERR_SPI_CMD_TIMEOUT;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
LR11x0Interface<T>::LR11x0Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
|
||||
RADIOLIB_PIN_TYPE busy)
|
||||
@@ -73,22 +89,26 @@ template <typename T> bool LR11x0Interface<T>::init()
|
||||
digitalWrite(LR11X0_POWER_EN, HIGH);
|
||||
#endif
|
||||
|
||||
// An explicit Vref always wins; TCXO_OPTIONAL only supplies a default for boards that declare a
|
||||
// TCXO may be fitted without saying at what voltage. Both may appear in the same variant file.
|
||||
#if ARCH_PORTDUINO
|
||||
float tcxoVoltage = (float)portduino_config.dio3_tcxo_voltage / 1000;
|
||||
// FIXME: correct logic to default to not using TCXO if no voltage is specified for LR11x0_DIO3_TCXO_VOLTAGE
|
||||
// Portduino leaves dio3_tcxo_voltage at 0 whenever the YAML omits DIO3_TCXO_VOLTAGE, which is the
|
||||
// "no explicit Vref" case, so the TCXO_OPTIONAL default still has to apply there
|
||||
float tcxoVoltage =
|
||||
portduino_config.dio3_tcxo_voltage > 0 ? (float)portduino_config.dio3_tcxo_voltage / 1000 : LR11X0_TCXO_DEFAULT_VOLTAGE;
|
||||
#elif defined(LR11X0_DIO3_TCXO_VOLTAGE)
|
||||
float tcxoVoltage = LR11X0_DIO3_TCXO_VOLTAGE;
|
||||
LOG_DEBUG("LR11X0_DIO3_TCXO_VOLTAGE defined, using DIO3 as TCXO reference voltage at %f V", LR11X0_DIO3_TCXO_VOLTAGE);
|
||||
// (DIO3 is not free to be used as an IRQ)
|
||||
#elif defined(TCXO_OPTIONAL)
|
||||
float tcxoVoltage = 1.6f; // TCXO_OPTIONAL: try default 1.6 V first, fall back to XTAL on failure
|
||||
LOG_DEBUG("TCXO_OPTIONAL: no LR11X0_DIO3_TCXO_VOLTAGE defined, trying default TCXO Vref 1.6 V first");
|
||||
#else
|
||||
float tcxoVoltage =
|
||||
0; // "TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip." per
|
||||
// https://github.com/jgromes/RadioLib/blob/690a050ebb46e6097c5d00c371e961c1caa3b52e/src/modules/LR11x0/LR11x0.h#L471C26-L471C104
|
||||
// (DIO3 is free to be used as an IRQ)
|
||||
LOG_DEBUG("LR11X0_DIO3_TCXO_VOLTAGE not defined, not using DIO3 as TCXO reference voltage");
|
||||
float tcxoVoltage = LR11X0_TCXO_DEFAULT_VOLTAGE;
|
||||
#endif
|
||||
|
||||
// DIO3 is free to be used as an IRQ only while no TCXO Vref is driven on it
|
||||
if (tcxoVoltage > 0)
|
||||
LOG_DEBUG("LR11x0 TCXO Vref %f V on DIO3 (DIO3 unavailable as an IRQ)", tcxoVoltage);
|
||||
else
|
||||
LOG_DEBUG("LR11x0 no TCXO Vref, XTAL only (DIO3 free as an IRQ)");
|
||||
#if defined(TCXO_OPTIONAL)
|
||||
LOG_DEBUG("TCXO_OPTIONAL: oscillator type unknown, probing XTAL first and using any TCXO Vref only as fallback");
|
||||
#endif
|
||||
|
||||
RadioLibInterface::init();
|
||||
@@ -114,29 +134,48 @@ template <typename T> bool LR11x0Interface<T>::init()
|
||||
// Allow extra time for TCXO to stabilize after power-on
|
||||
delay(10);
|
||||
|
||||
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
|
||||
|
||||
// Retry if we get SPI command failed - some units need extra TCXO stabilization time
|
||||
if (res == RADIOLIB_ERR_SPI_CMD_FAILED) {
|
||||
LOG_WARN("LR11x0 init failed with %d (SPI_CMD_FAILED), retrying after delay...", res);
|
||||
delay(100);
|
||||
res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
|
||||
}
|
||||
// Timestamped brackets so a hang inside RadioLib leaves a dangling "attempt" line in the boot log
|
||||
auto tryBegin = [&](int attempt, float vref) {
|
||||
uint32_t attemptStart = millis();
|
||||
LOG_INFO("LR11x0 begin() attempt %d: tcxoVoltage=%.3fV at t=%ums", attempt, vref, attemptStart);
|
||||
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, vref);
|
||||
LOG_INFO("LR11x0 begin() attempt %d returned %d after %ums", attempt, res, millis() - attemptStart);
|
||||
return res;
|
||||
};
|
||||
|
||||
#if defined(TCXO_OPTIONAL)
|
||||
// If init failed for any reason other than chip not found, retry without TCXO (XTAL mode)
|
||||
// 1. XTAL, because a TCXO-first attempt hangs RadioLib's unbounded calibration wait on a module
|
||||
// with no TCXO fitted, whereas XTAL fails fast and cleanly on a module that does have one
|
||||
float attemptVoltage = 0;
|
||||
#else
|
||||
// 1. Whatever Vref the variant configured, which it declared unconditionally
|
||||
float attemptVoltage = tcxoVoltage;
|
||||
#endif
|
||||
int res = tryBegin(1, attemptVoltage);
|
||||
|
||||
#if defined(TCXO_OPTIONAL)
|
||||
// 2. XTAL failed with the chip present, so fall back to the TCXO if the variant configured one
|
||||
if (res != RADIOLIB_ERR_NONE && res != RADIOLIB_ERR_CHIP_NOT_FOUND && tcxoVoltage > 0) {
|
||||
LOG_WARN("LR11x0 init failed with TCXO Vref %f V (err %d), retrying without TCXO", tcxoVoltage, res);
|
||||
tcxoVoltage = 0;
|
||||
res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
|
||||
LOG_WARN("LR11x0 XTAL init failed (err %d), retrying with TCXO Vref %f V", res, tcxoVoltage);
|
||||
attemptVoltage = tcxoVoltage;
|
||||
res = tryBegin(2, attemptVoltage);
|
||||
if (res == RADIOLIB_ERR_NONE)
|
||||
LOG_INFO("LR11x0 init success without TCXO (XTAL mode)");
|
||||
LOG_INFO("LR11x0 init success with TCXO Vref %f V", tcxoVoltage);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 3. Some units need extra settling time, so give whichever oscillator we settled on one retry.
|
||||
// After a step 2 fallback that is a second TCXO attempt, which is where settling actually matters.
|
||||
if (lr11x0SpiFailed(res)) {
|
||||
LOG_WARN("LR11x0 init failed with %d (SPI command failure), retrying after delay...", res);
|
||||
delay(100);
|
||||
res = tryBegin(3, attemptVoltage);
|
||||
}
|
||||
|
||||
// \todo Display actual typename of the adapter, not just `LR11x0`
|
||||
LOG_INFO("LR11x0 init result %d", res);
|
||||
if (res == RADIOLIB_ERR_CHIP_NOT_FOUND || res == RADIOLIB_ERR_SPI_CMD_FAILED) {
|
||||
|
||||
if (res == RADIOLIB_ERR_CHIP_NOT_FOUND || lr11x0SpiFailed(res)) {
|
||||
#ifdef LR11X0_UPDATE_FIRMWARE_TO
|
||||
// An interrupted update leaves the radio sitting in bootloader mode, where begin() fails. Retry the
|
||||
// flash from here rather than giving up, otherwise the device could never recover on its own.
|
||||
|
||||
@@ -42,7 +42,7 @@ Making your own node based on this design is straightforward. There are various
|
||||
| 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, needs alternate rfswitch.h |
|
||||
| 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 |
|
||||
@@ -55,7 +55,24 @@ The E80 from CDEbyte is the most obtainable module at present, and has been sele
|
||||
|
||||
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, the table in `rfswitch.h` must be adjusted accordingly.**
|
||||
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`:
|
||||
|
||||
```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
|
||||
|
||||
@@ -82,7 +99,7 @@ The Semtech default, the values are (taken from [here](https://github.com/Lora-n
|
||||
<details>
|
||||
|
||||
<summary> < Click to expand >
|
||||
|
||||
|
||||
</summary>
|
||||
|
||||
```cpp
|
||||
@@ -119,4 +136,19 @@ Tests were conducted in each of the three configurations between a known-good SX
|
||||
|
||||
The RF switching is based on the code example given. Logically, this shows the DIO5 and DIO6 are swapped compared to the reference design.
|
||||
|
||||
If future DIYers wish to use an alternative module, the table in `rfswitch.h` must be adjusted accordingly.
|
||||
## 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.
|
||||
|
||||
@@ -6,6 +6,22 @@
|
||||
#define LR20x0 LR2021
|
||||
#endif
|
||||
|
||||
// LR1121 modules differ in how their internal RF switch is wired, so the matrix must match the
|
||||
// module actually fitted. The Ebyte E80-900M2213S is the default; define one of the alternatives
|
||||
// below in your build_flags (or above the #include of this header) to select a different module.
|
||||
//
|
||||
// LR1121_MODULE_E80 Ebyte E80-900M2213S (default if nothing is defined)
|
||||
// LR1121_MODULE_WIO Seeed Wio-LR1121
|
||||
#ifdef USE_LR1121
|
||||
|
||||
#if !defined(LR1121_MODULE_E80) && !defined(LR1121_MODULE_WIO)
|
||||
#define LR1121_MODULE_E80
|
||||
#endif
|
||||
#if defined(LR1121_MODULE_E80) && defined(LR1121_MODULE_WIO)
|
||||
#error "Define only one LR1121_MODULE_* option"
|
||||
#endif
|
||||
|
||||
#ifdef LR1121_MODULE_E80
|
||||
// This is rewritten to match the requirements of the E80-900M2213S
|
||||
// The E80 does not conform to the reference Semtech switches(!) and therefore needs a custom matrix.
|
||||
// See footnote #3 in "https://www.cdebyte.com/products/E80-900M2213S/2#Pin"
|
||||
@@ -13,7 +29,6 @@
|
||||
// DIO5 -> RFSW0_V1
|
||||
// DIO6 -> RFSW1_V2
|
||||
// DIO7 -> not connected on E80 module - note that GNSS and Wifi scanning are not possible.
|
||||
#ifdef USE_LR1121
|
||||
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7, RADIOLIB_NC,
|
||||
RADIOLIB_NC};
|
||||
|
||||
@@ -30,7 +45,39 @@ static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||
END_OF_MODE_TABLE,
|
||||
// clang-format on
|
||||
};
|
||||
#endif
|
||||
#endif // LR1121_MODULE_E80
|
||||
|
||||
#ifdef LR1121_MODULE_WIO
|
||||
// Seeed Wio-LR1121. Unlike the E80 this module DOES follow the Semtech reference topology
|
||||
// (SWSD006: rx = RFSW0, tx = RFSW0|RFSW1, tx_hp = RFSW1).
|
||||
// The internal switch is a Skyworks SKY13373-460LF driven by two lines only:
|
||||
// DIO5 -> V1
|
||||
// DIO6 -> V2
|
||||
// Datasheet section 4.5, "True Table of the Internal RF Switch":
|
||||
// V1 V2 Status
|
||||
// 0 0 Shutdown
|
||||
// 1 0 RFI_P_LF & RFI_N_LF (receive)
|
||||
// 0 1 RFO_HP_LF (sub-GHz high power)
|
||||
// 1 1 RFO_LP_LF (sub-GHz low power)
|
||||
// The LR1121 has no GNSS or WiFi scanning, so those modes are left in the shutdown state.
|
||||
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||
|
||||
static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||
// clang-format off
|
||||
// mode DIO5 DIO6
|
||||
{LR11x0::MODE_STBY, {LOW, LOW}},
|
||||
{LR11x0::MODE_RX, {HIGH, LOW}},
|
||||
{LR11x0::MODE_TX, {HIGH, HIGH}},
|
||||
{LR11x0::MODE_TX_HP, {LOW, HIGH}},
|
||||
{LR11x0::MODE_TX_HF, {LOW, LOW}},
|
||||
{LR11x0::MODE_GNSS, {LOW, LOW}},
|
||||
{LR11x0::MODE_WIFI, {LOW, LOW}},
|
||||
END_OF_MODE_TABLE,
|
||||
// clang-format on
|
||||
};
|
||||
#endif // LR1121_MODULE_WIO
|
||||
|
||||
#endif // USE_LR1121
|
||||
|
||||
// LR2021 RF switch matrix following the standard Semtech / Seeed T1000-E reference topology.
|
||||
// DIO5 -> antenna path select (HIGH = sub-GHz LF)
|
||||
|
||||
@@ -262,7 +262,7 @@ settings.
|
||||
| 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, needs alternate rfswitch.h |
|
||||
| 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 |
|
||||
|
||||
Reference in New Issue
Block a user