fix(radio): fix SX1262 image calibration leaving radio on the wrong frequency#21
fix(radio): fix SX1262 image calibration leaving radio on the wrong frequency#210x00001312 wants to merge 2 commits into
Conversation
calibrate_image() called the generic standby() helper before issuing CalibrateImage, which enters STDBY_XOSC on this TCXO-equipped board. The SX1262 datasheet requires CalibrateImage to run from STDBY_RC, same as the general Calibrate() command a few lines above it (which already forces STDBY_RC explicitly, with a comment to that effect) — calibrate() had the fix, calibrate_image() didn't. Symptom this produces: image/PLL calibration only actually runs when imageCalParams() reports a new band (_imageCalBand is cached per band), so switching regions (e.g. default Americas 915MHz to a configured Europe 868MHz frequency) is exactly when the wrong-mode calibration fires. The chip's subsequent SetRfFrequency write appears to apply in software, but the radio stays locked on the previously-calibrated band's frequency. Re-entering Settings and reapplying any LoRa value — even the same one — calls setFrequency() again, but by then _imageCalBand already matches the target band, so the broken calibration step is skipped and a clean SetRfFrequency goes through on an otherwise-idle chip, which is why that "fixes" it. Configured region was stuck on the boot default until a no-op Settings save; this fix resolves it. (cherry picked from commit a2ffda0)
setFrequency() to a new ISM band (e.g. Americas 915MHz -> Europe 868MHz on first applying a saved custom frequency) appeared to apply in software and logs, but the chip kept transmitting/receiving on the old frequency until the same value was reapplied a second time (e.g. by reopening Settings and confirming any radio value). The second call "worked" only because calibrate_image() caches per-band and skips recalibration once a band has been calibrated, landing a clean SetRfFrequency on an otherwise idle chip — masking that the first, real calibration attempt never actually got there. Root cause: waitOnBusy() capped its poll at 100ms. CalibrateImage on a fresh (uncached) band can legitimately run longer than that on this hardware; once the cap was hit, the function returned while BUSY was still genuinely asserted. The SX126x ignores SPI while busy, so the SetRfFrequency write issued immediately after by setFrequency() landed on a still-busy chip and was silently dropped, leaving the old frequency in effect even though _imageCalBand now (wrongly) recorded the new band as calibrated. Raise the waitOnBusy() cap to 1000ms (well beyond any documented SX126x opcode duration) and add the same settle delay calibrate() already has before its own waitOnBusy(), since CalibrateImage has the same BUSY-assertion-propagation gap. (cherry picked from commit 5e03e0d)
|
Tested both fixes on hardware: switched from the 915MHz boot default to a custom 868MHz frequency via Settings, rebooted, and the radio came up on the new frequency immediately — no reconfirm-without-reboot workaround needed. |
|
Worth calling out separately from the Settings-reconfirm symptom: this isn't a Settings-page quirk, it's the chip's actual RF tuning being wrong. That matches what was reported in #19: announces not getting through, and not receiving anything from other nodes on the same settings either, plus the SDR captures showing a faint/off-looking signal that grew into a vague "cloud" the more the announce button got spammed — consistent with the chip transmitting off the configured frequency the whole time. I wouldn't extend this further without testing it directly — the bandwidth-reverting-after-reboot symptom mentioned earlier in the thread goes through a different opcode ( |
|
One nuance worth flagging for review: this is a timing race, not a deterministic failure. Whether the |
Summary
Fixes the root cause behind #19: after switching to a configured frequency in a different ISM band from the 915MHz boot default, the SX1262 silently stays on the old frequency until any radio setting is reconfirmed in Settings without a reboot. That "fix" doesn't actually fix anything — it just skips the broken calibration path on the second call.
Two bugs in
calibrate_image()/waitOnBusy()combine to cause this, both insrc/radio/SX1262.cpp:calibrate_image()issuedCalibrateImagefromSTDBY_XOSC, notSTDBY_RC. The SX1262 datasheet requiresSTDBY_RCfor this opcode, same as the generalCalibrate()a few lines above it (which already forcedSTDBY_RCexplicitly) —calibrate_image()was missing the same fix.waitOnBusy()capped its poll at 100ms.CalibrateImageon a fresh, never-calibrated band can legitimately run longer than that on this hardware. When the cap hit, the function returned while BUSY was still genuinely asserted. The SX126x ignores SPI while busy, so theSetRfFrequencywrite issued immediately after bysetFrequency()landed on a still-busy chip and was silently dropped — frequency stayed on the old band even though_imageCalBandnow (wrongly) recorded the new band as calibrated.Because
_imageCalBandcaches per-band and skips recalibration once a band is marked done, both bugs produce the same masking symptom: reopening Settings and reconfirming any value callssetFrequency()again, but_imageCalBandalready matches the target band, so the broken calibration step is skipped entirely and a cleanSetRfFrequencygoes through on an otherwise idle chip — "fixing" it until the next reboot.Changes
CalibrateImagefromSTDBY_RCexplicitly, matchingCalibrate().waitOnBusy()poll cap from 100ms to 1000ms (well beyond any documented SX126x opcode duration).waitOnBusy()thatcalibrate()already has, sinceCalibrateImagehas the same BUSY-assertion-propagation gap.Both fixes have been running on a downstream fork (rsCardputer-CE) since v0.0.5 with no recurrence of the stuck-frequency symptom.
Test plan
standalone_915viapio run -e standalone_915