Skip to content

stm32wl: add TCXO-optional support and fix hardcoded TCXO voltage#10964

Open
ndoo wants to merge 5 commits into
meshtastic:developfrom
mesh-malaysia:rak3172-tcxo-optional
Open

stm32wl: add TCXO-optional support and fix hardcoded TCXO voltage#10964
ndoo wants to merge 5 commits into
meshtastic:developfrom
mesh-malaysia:rak3172-tcxo-optional

Conversation

@ndoo

@ndoo ndoo commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds TCXO-optional support to the STM32WL radio path (STM32WLE5JCInterface), so one rak3172 build works on both non-T RAK3172 (XTAL) and RAK3172-T (3.0V TCXO). Also fixes a bug that silently ignored any STM32WL variant's declared TCXO voltage — hardware-confirmed as an active bug on wio-e5, not just theoretical.

Problem

  1. Hardcoded 1.7V, ignoring SX126X_DIO3_TCXO_VOLTAGE. Every variant except rak3172 got setTCXOVoltage(1.7) unconditionally. russell declares SX126X_DIO3_TCXO_VOLTAGE 3.0, but it was silently overridden to 1.7V.
  2. rak3172 configured no TCXO at all. RAK3172-T (populated 3.0V TCXO) failed radio init outright.

Confirmed on TCXO-equivalent test hardware: RadioLib error -707 (RADIOLIB_ERR_SPI_CMD_FAILED) on stock develop. RAK's own radio_conf.h confirms RAK3172-T needs 3.0V.

flowchart TD
    A["STM32WLE5JCInterface::init()"] --> B{"_VARIANT_RAK3172_ defined?"}
    B -- "yes (rak3172)" --> C["No TCXO configured"]
    B -- "no (every other variant)" --> D["setTCXOVoltage(1.7), hardcoded"]
    D -.-> N["russell/milesight_gs301 declare 3.0V,\nget 1.7V instead — outcome unverified"]
    C --> E["lora.begin()"]
    D --> E
    E --> F{"Success?"}
    F -- "yes" --> G["Radio up"]
    F -- "no" --> H["Fails, no retry.\nRAK3172-T: confirmed fails (-707)"]
Loading

Fix

  • STM32WLE5JCInterface::init() reads SX126X_DIO3_TCXO_VOLTAGE per variant instead of hardcoding 1.7V. No macro → no TCXO call (XTAL).
  • With TCXO_OPTIONAL defined, a failed TCXO attempt retries once on XTAL — same pattern as LR11x0Interface.cpp, LR20x0Interface.cpp, and the SX1262/SX1268 paths in RadioInterface.cpp.
  • rak3172: TCXO_OPTIONAL + SX126X_DIO3_TCXO_VOLTAGE 3.0.
  • wio-e5: SX126X_DIO3_TCXO_VOLTAGE 1.7 (mandatory), matching Seeed's reference driver.
  • CDEBYTE_E77-MBL: TCXO_OPTIONAL + SX126X_DIO3_TCXO_VOLTAGE 1.7hardware varies by unit.
flowchart TD
    A["STM32WLE5JCInterface::init()"] --> B{"SX126X_DIO3_TCXO_VOLTAGE defined?"}
    B -- "yes" --> C["setTCXOVoltage(value)"]
    B -- "no" --> D["No TCXO call, XTAL"]
    C --> E["lora.begin()"]
    D --> E
    E --> F{"Success?"}
    F -- "yes" --> G["Radio up"]
    F -- "no" --> H{"TCXO_OPTIONAL and TCXO\nwas attempted?"}
    H -- "no" --> I["Fails\n(incompatible XTAL populated instead)"]
    H -- "yes" --> J["Retry XTAL\n(rak3172 non-T, CDEBYTE_E77-MBL pre-2024)"]
    J --> K{"Success?"}
    K -- "yes" --> G
    K -- "no" --> I
Loading

4 commits, one per file.

Side effects on other variants

Warning

russell and milesight_gs301 change behavior as a side effect (their variant.h wasn't touched), untested. A regression on either after merge means that board's actual TCXO voltage doesn't match its declared SX126X_DIO3_TCXO_VOLTAGE — check the schematic and fix the value, don't revert this PR.

Variant Before After
russell Declared 3.0V, silently got 1.7V Declaration now honored
milesight_gs301 Declared 3.0V (mandatory), silently got 1.7V Gets 3.0V, still mandatory

RadioLib's SX126x::modSetup() has its own one-shot internal TCXO→XTAL fallback on oscillator-start failure — likely why the old bug wasn't visibly broken elsewhere. Doesn't help boards with no XTAL to fall back to (wio-e5). This PR's retry is explicit so it's visible in logs rather than silent.

Testing

  • rak3172 (TCXO path): hardware-tested — -707 on stock develop, succeeds at 3.0V after this fix.
  • wio-e5: hardware-tested via ST-Link/SWD (no UART bootloader on this board). With SX126X_DIO3_TCXO_VOLTAGE 1.7, meshtastic --sendtext --ack against a live rak3172 node returned PKI_SEND_FAIL_PUBLIC_KEY (unrelated — no shared public key yet) instead of NO_INTERFACE, and --traceroute round-tripped successfully.
  • Not hardware-tested: genuine non-T RAK3172, russell, milesight_gs301, CDEBYTE_E77-MBL.
  • Build-verified: rak3172, russell, wio-e5, CDEBYTE_E77-MBL all compile clean. rak3172: 73.8% flash (182,952 / 247,808), ~63KB headroom.
  • ./bin/run-tests.sh: STM32WL code is #ifdef ARCH_STM32WL-gated, not exercised by the native suite.

🤝 Attestations

  • I have tested that my proposed changes behave as described — rak3172 TCXO path and wio-e5, both hardware-verified; see Testing above for what wasn't.
  • I have tested that my proposed changes do not cause any obvious regressions on the following devices:
    • Heltec (Lora32) V3
    • LilyGo T-Deck
    • LilyGo T-Beam
    • RAK WisBlock 4631
    • Seeed Studio T-1000E tracker card
    • RAK3172 (RAK3172-T module)
    • Wio-E5
    • Other (please specify below)

Not tested on: genuine non-T RAK3172, russell, milesight_gs301, CDEBYTE_E77-MBL.

Summary by CodeRabbit

  • New Features
    • Improved LoRa radio initialization across supported STM32 boards with TCXO and crystal oscillator hardware.
    • Added automatic fallback to crystal oscillator mode when TCXO initialization is unavailable or unsuccessful.
    • Added hardware-specific oscillator configuration for EByte E77-MBL, RAK3172, and Wio-E5 variants.
  • Bug Fixes
    • Improved startup reliability for devices using optional or varying oscillator configurations.

ndoo added 4 commits July 10, 2026 03:53
Every STM32WL variant except rak3172 got setTCXOVoltage(1.7) unconditionally,
regardless of what the board's hardware actually needs, and rak3172 got no
TCXO configuration at all - so a real RAK3172-T (populated TCXO) failed
radio init outright.

Read SX126X_DIO3_TCXO_VOLTAGE per variant instead. When TCXO_OPTIONAL is
also defined, retry once on XTAL if the TCXO attempt fails, mirroring the
existing pattern in LR11x0Interface.cpp, LR20x0Interface.cpp, and the
SX1262/SX1268 paths in RadioInterface.cpp.

Signed-off-by: Andrew Yong <me@ndoo.sg>
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
RAK3172 is XTAL-only; RAK3172-T has a populated 3.0V TCXO, matching RAK's
own reference radio_conf.h. One PlatformIO environment now serves both:
tries the TCXO first, falls back to XTAL if not populated.

Hardware-verified on a TCXO-equipped board electrically equivalent to
RAK3172-T. Genuine non-T hardware not available to re-verify the fallback
path; reasoned from RadioLib source instead (see PR description).

Signed-off-by: Andrew Yong <me@ndoo.sg>
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Matches Seeed's own reference radio driver. wio-e5 previously relied on
the hardcoded 1.7V fallback being removed by the preceding commit, which
would have broken it - declare the voltage explicitly instead.

Hardware-verified via SWD: without this define, the radio interface fails
to come up at all (sendtext NAKs with NO_INTERFACE, meaning rIf is null).
With it, NO_INTERFACE goes away and the device sends/receives normally.

Signed-off-by: Andrew Yong <me@ndoo.sg>
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
… by unit

EByte changed the E77-MBL hardware in early 2024: units with serial number
>= 3202995 have a TCXO, older units have a ceramic crystal oscillator
instead. Both ship under the same module name, so probe for the TCXO and
fall back to XTAL rather than assuming either.

https://github.com/olliw42/mLRS-docu/blob/main/docs/EBYTE_E77_MBL.md

Not hardware-tested - no E77-MBL board available this session.

Signed-off-by: Andrew Yong <me@ndoo.sg>
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

⚡ Try this PR in the Web Flasher

Note

Building this pull request… the flash button, badges and supported-board
list will appear here automatically once CI finishes.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0ba8eff0-dcf3-4eb9-badc-f790f8436489

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR updates STM32WLE5JCInterface LoRa initialization to conditionally configure TCXO voltage and retry in XTAL mode when eligible TCXO initialization failures occur. It also adds TCXO configuration macros and hardware notes for three STM32 variants.

Changes

TCXO Optional Fallback

Layer / File(s) Summary
Conditional TCXO init and retry-to-XTAL logic
src/mesh/STM32WLE5JCInterface.cpp
TCXO voltage setup is compile-time gated; eligible failures with optional TCXO disable TCXO and retry lora.begin(...) in XTAL mode.
Variant TCXO macro configuration
variants/stm32/CDEBYTE_E77-MBL/variant.h, variants/stm32/rak3172/variant.h, variants/stm32/wio-e5/variant.h
Adds variant-specific TCXO voltage definitions, optional fallback configuration where applicable, and oscillator hardware notes.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: TCXO-optional support and corrected TCXO voltage handling.
Description check ✅ Passed The description includes the required summary, problem, fix, testing, and attestations sections and is sufficiently detailed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@ndoo

ndoo commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
variants/stm32/CDEBYTE_E77-MBL/variant.h (1)

27-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Trim comment block to meet length guideline.

The 4-line explanatory block exceeds the repo's comment-length limit. Functionally the TCXO_OPTIONAL + SX126X_DIO3_TCXO_VOLTAGE 1.7 config is correct for mixed E77-MBL hardware revisions.

As per coding guidelines: "Keep code comments minimal: one or two lines maximum, only when the reason is not obvious, and do not restate the next line."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@variants/stm32/CDEBYTE_E77-MBL/variant.h` around lines 27 - 35, The comment
block around TCXO_OPTIONAL is too long and restates what the following defines
already show. Shorten the explanatory note in variant.h to one or two concise
lines while keeping the hardware-revision context, and leave the existing
TCXO_OPTIONAL and SX126X_DIO3_TCXO_VOLTAGE definitions unchanged.

Source: Coding guidelines

variants/stm32/rak3172/variant.h (1)

27-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Trim comment block to meet length guideline.

Same as the CDEBYTE_E77-MBL file: the comment spans 4 lines, exceeding the repo's 1-2 line comment limit. The TCXO_OPTIONAL + SX126X_DIO3_TCXO_VOLTAGE 3.0 config itself correctly matches the RAK3172/RAK3172-T hardware split described in the PR.

As per coding guidelines: "Keep code comments minimal: one or two lines maximum, only when the reason is not obvious, and do not restate the next line."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@variants/stm32/rak3172/variant.h` around lines 27 - 35, The comment block in
variant.h is too long for the repo guideline and should be reduced to one or two
lines. Keep the hardware distinction for RAK3172 vs RAK3172-T, but trim the
multi-line explanation and link reference around the TCXO_OPTIONAL and
SX126X_DIO3_TCXO_VOLTAGE settings so the comment does not restate the config
directly.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@variants/stm32/CDEBYTE_E77-MBL/variant.h`:
- Around line 27-35: The comment block around TCXO_OPTIONAL is too long and
restates what the following defines already show. Shorten the explanatory note
in variant.h to one or two concise lines while keeping the hardware-revision
context, and leave the existing TCXO_OPTIONAL and SX126X_DIO3_TCXO_VOLTAGE
definitions unchanged.

In `@variants/stm32/rak3172/variant.h`:
- Around line 27-35: The comment block in variant.h is too long for the repo
guideline and should be reduced to one or two lines. Keep the hardware
distinction for RAK3172 vs RAK3172-T, but trim the multi-line explanation and
link reference around the TCXO_OPTIONAL and SX126X_DIO3_TCXO_VOLTAGE settings so
the comment does not restate the config directly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ca438065-7797-4d90-8a23-74966306a7b6

📥 Commits

Reviewing files that changed from the base of the PR and between b3ddeca and 4ba8775.

📒 Files selected for processing (4)
  • src/mesh/STM32WLE5JCInterface.cpp
  • variants/stm32/CDEBYTE_E77-MBL/variant.h
  • variants/stm32/rak3172/variant.h
  • variants/stm32/wio-e5/variant.h

Per review feedback on PR meshtastic#10964 (CodeRabbit nitpicks) - the rak3172 and
CDEBYTE_E77-MBL variant.h comments were 4-line blocks, exceeding the
repo's comment-length convention. Condensed to one line each, same
information and links retained.

Signed-off-by: Andrew Yong <me@ndoo.sg>
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
@ndoo ndoo marked this pull request as ready for review July 9, 2026 23:52
@ndoo

ndoo commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Nitpick comments addressed

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

@ndoo Thanks for confirming — I'll kick off a fresh review of the latest changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant