Skip to content

firmware: fix explicit LO frequency being ignored in radio_update_frequency#1795

Closed
munzzyy wants to merge 1 commit into
greatscottgadgets:mainfrom
munzzyy:fix-explicit-lo-after-reset
Closed

firmware: fix explicit LO frequency being ignored in radio_update_frequency#1795
munzzyy wants to merge 1 commit into
greatscottgadgets:mainfrom
munzzyy:fix-explicit-lo-after-reset

Conversation

@munzzyy

@munzzyy munzzyy commented Jul 5, 2026

Copy link
Copy Markdown

Fixes #1785.

The bug

In radio_update_frequency() (firmware/common/radio.c), the LO branch calls
mixer_set_frequency() with freq_lo instead of requested_lo:

if (requested_lo != RADIO_UNSET) {
    freq_lo = mixer_set_frequency(&mixer, freq_lo, false);
}

freq_lo is initialized a few lines up from applied_lo (the last LO actually
programmed into the mixer), so this branch reprograms the mixer with whatever
LO was already applied and throws away requested_lo entirely. The IF branch
directly above it does this correctly with requested_if, so LO was just out
of step with it.

This means any explicit LO tune that differs from the currently applied one
gets silently dropped, not just the first tune after a reset. It's worse right
after a reset, though: radio_init() sets every RADIO_BANK_APPLIED register,
LO included, to RADIO_UNSET (0xffffffffffffffff). freq_lo starts out as
applied_lo, so on the first explicit tune after reset it's RADIO_UNSET
flowing into mixer_set_frequency(). As an fp_40_24_t that's a huge value,
and rffc5071_config_synth() clamps it straight down:

#define MAX_LO      FP_MHZ(5400)
...
lo = MIN(lo, MAX_LO);

So the RFFC5071 gets programmed to 5400 MHz regardless of what LO was
requested, matching the register dumps in #1785 (LO=5400 MHz, RF =
5400-2380 = 3020 MHz).

The fix

Pass requested_lo instead of freq_lo, matching the IF branch above it.

 if (requested_lo != RADIO_UNSET) {
-    freq_lo = mixer_set_frequency(&mixer, freq_lo, false);
+    freq_lo = mixer_set_frequency(&mixer, requested_lo, false);
 }

One line, one file. freq_lo still gets updated afterward for whatever
downstream RF math still reads it (e.g. the PRALINE image-rejection block),
now with the value the mixer was actually just programmed to.

Scope check

Only the explicit-LO path is touched. The auto-tune path (requested_lo == RADIO_UNSET, the "compute precise LO" block further down) never runs
mixer_set_frequency() with freq_lo, so it's unaffected. RX/TX/RX_SWEEP
startup and the CLKIN/XTAL clock-source-selection path are also untouched by
this diff.

Not bench-tested

I don't have an ARM toolchain or a HackRF on hand to build and flash this, so
this is reasoned from source and the register dumps in the issue, not
verified on hardware. To confirm: flash this build, do a cold reset, issue an
explicit LO tune (e.g. via hackrf_set_freq_explicit) to something other than
5400 MHz, and check with hackrf_debug/a register dump that the RFFC5071 LO
matches what was requested instead of clamping to 5400 MHz. Worth also
re-running a normal auto-tune (hackrf_set_freq) afterward to confirm that
path still behaves as before.

mixer_set_frequency() was called with freq_lo instead of requested_lo,
so any explicit LO that differs from the currently applied one gets
silently dropped and the mixer stays on the old LO. The IF branch just
above already passes requested_if correctly, so this brings LO in
line with it.

It's worse right after a device reset: radio_init() sets every
RADIO_BANK_APPLIED register, including LO, to RADIO_UNSET, and
freq_lo starts out as applied_lo. RADIO_UNSET is 0xffffffffffffffff,
so passed through as an fp_40_24_t it gets clamped straight down to
MAX_LO by rffc5071_config_synth() (5400 MHz), which is exactly what
greatscottgadgets#1785's register dumps show (LO=5400 MHz, RF=5400-2380=3020 MHz)
instead of the requested LO.
@mossmann

mossmann commented Jul 6, 2026

Copy link
Copy Markdown
Member

We do not accept LLM-generated contributions.

@mossmann mossmann closed this Jul 6, 2026
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.

Explicit tuning following device reset no longer configures the correct center frequency on pre-release builds.

2 participants