SX126x: re-apply 0x8B5 register in resetAGC() to preserve RX sensitivity#10219
Merged
thebentern merged 1 commit intoApr 21, 2026
Merged
Conversation
The CALIBRATE_ALL (0x7F) command inside resetAGC() clears bit 0 of the undocumented 0x8B5 register. That bit is set once in init() by meshtastic#9571 and meshtastic#9777 to improve SX1262 RX sensitivity, and the AGC-reset path was not re-applying it. Result: every SX1262 node silently loses the RX sensitivity patch ~60s after boot and never recovers until reboot. Empirically confirmed on Heltec Mesh Node T114 (nRF52840 + SX1262): - Post-calibration read of 0x8B5 = 0x04 (bit 0 cleared) - After re-apply: 0x05 (bit 0 set) Reproducible every AGC_RESET_INTERVAL_MS tick. Fix re-applies the register bit alongside the existing post-calibration re-applies (setDio2AsRfSwitch, setRxBoostedGainMode).
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes an interaction between the periodic SX126x “AGC reset” maintenance routine and the previously-added SX1262 RX sensitivity patch by re-applying the undocumented 0x8B5 bit-0 setting after CALIBRATE_ALL (0x7F) inside SX126xInterface<T>::resetAGC().
Changes:
- Re-apply the
0x8B5bit-0 RX sensitivity patch at the end ofresetAGC()after calibration. - Add a warning log if the register re-apply fails.
thebentern
pushed a commit
that referenced
this pull request
Apr 21, 2026
…ity (#10219) The CALIBRATE_ALL (0x7F) command inside resetAGC() clears bit 0 of the undocumented 0x8B5 register. That bit is set once in init() by #9571 and #9777 to improve SX1262 RX sensitivity, and the AGC-reset path was not re-applying it. Result: every SX1262 node silently loses the RX sensitivity patch ~60s after boot and never recovers until reboot. Empirically confirmed on Heltec Mesh Node T114 (nRF52840 + SX1262): - Post-calibration read of 0x8B5 = 0x04 (bit 0 cleared) - After re-apply: 0x05 (bit 0 set) Reproducible every AGC_RESET_INTERVAL_MS tick. Fix re-applies the register bit alongside the existing post-calibration re-applies (setDio2AsRfSwitch, setRxBoostedGainMode).
This was referenced Apr 22, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SX126xInterface<T>::resetAGC()(added in #9705) performs a warm-sleep +CALIBRATE_ALL (0x7F)every 60 seconds. This sequence clears bit 0 of the undocumented0x8B5register — the register that PR #9571 / #9777 sets once at init to improve RX sensitivity. The AGC-reset path never re-applies it, so the benefit of #9571 is silently lost ~60 seconds after boot and is never restored until the device is rebooted.The fix is to re-write
0x8B5bit 0 at the end ofresetAGC(), alongside the other register re-applies that are already there (setDio2AsRfSwitch,setRxBoostedGainMode).Empirical evidence
Reproduced on a Heltec Mesh Node T114 (nRF52840 + SX1262) by instrumenting
resetAGC()withmodule.SPIgetRegValue(0x8B5)reads before and after the re-apply:Deterministic, reproduces every
AGC_RESET_INTERVAL_MStick. Bit 2 survives (that's why we see0x04rather than0x00), but bit 0 — the one #9571 cares about — is consistently wiped by the calibration.Why warm sleep + calibration clears it
Two independent signals that undocumented
0x8xx-family registers are NOT auto-retained across the warm-sleep + calibration sequence:0x8B5is not in the documented set.SX126x::setRxBoostedGainMode()explicitly adds register0x08AC(RX_GAIN, documented) to the chip's retention RAM at offsets0x029F-0x02A1. If warm sleep preserved everything in the0x8xxspace automatically, that retention-RAM code would be unnecessary.0x8B5is in the same family and is not whitelisted, so it gets wiped.Additionally,
CALIBRATE_ALL (0x7F)retrains the analog front-end, which is exactly what0x8B5bit 0 configures — so even without warm sleep, the calibration step alone would clear it.Real-world impact
Every release from 2.7.20 (where #9705 landed) through current develop is affected. This includes 2.7.20, 2.7.21, 2.7.22 and 2.7.23. All SX1262-based boards that have the
0x8B5init-time patch compiled in (post-#9777 that is every SX1262 board) lose the sensitivity improvement ~60 s after boot.Consistent with the ~-15 dB RX regression reported by @tonicb78 on #9571 (comment Mar 11) for a Heltec V4 near cell towers on 2.7.20 vs 2.7.15. The bug is most visible in noisy RF environments (cell-tower proximity, dense mesh), which is exactly the scenario #9571 was meant to fix.
Scope of this PR
Minimal and narrowly scoped to the empirically-verified bug: one re-apply call inside
SX126xInterface<T>::resetAGC(), right after the existingsetRxBoostedGainMode()re-apply, guarded with aLOG_WARNon SPI failure.Does not touch
reconfigure()— I only have empirical proof that the bug exists in theresetAGC()path. If reviewers have data thatreconfigure()(region change / bandwidth change) also clears0x8B5, that could be a follow-up PR.Does not touch
LR11x0Interface::resetAGC(). The LR1110 / LR1121 AGC is firmware-black-boxed (per @weebl2000 on #9705), and no one has reported a matching regression on LR11x0 boards yet. Happy to add if there's demand.Test plan
LOG_INFO("0x8B5 = 0x%02X", module.SPIgetRegValue(0x8B5) & 0xFF)immediately before and after the new re-apply and observe0x04 → 0x05every 60 s.0x8B5doesn't do anything (safe: we're setting a single bit, same value Apply SX1262 register 0x8B5 patch for improved GC1109 RX sensitivity #9571 / Unlock 0x8B5 register macro guard for SX162 #9777 set at init).References
0x8B5init-time patchresetAGC()(this PR fixes the interaction with Apply SX1262 register 0x8B5 patch for improved GC1109 RX sensitivity #9571)USE_GC1109_PAguard so Apply SX1262 register 0x8B5 patch for improved GC1109 RX sensitivity #9571 now applies to all SX1262 boards0x8B5actually doesSX126x::setRxBoostedGainMode()— retention-RAM precedent for0x08AC