Skip to content

5/10 MHz narrowband on the RTL8812AU + a narrowband machinery doc#220

Merged
josephnef merged 4 commits into
masterfrom
jaguar1-narrowband-8812
Jul 8, 2026
Merged

5/10 MHz narrowband on the RTL8812AU + a narrowband machinery doc#220
josephnef merged 4 commits into
masterfrom
jaguar1-narrowband-8812

Conversation

@josephnef

Copy link
Copy Markdown
Collaborator

What

Two deliverables:

  1. 5/10 MHz narrowband on the RTL8812AU/8811AU — a chip the vendor never gave narrowband, and which the codebase documented as impossible ("dead enum values only").
  2. docs/narrowband.md — a machinery + porting guide for 5/10 MHz across all three generations, including the chip-specific walls, so the next person who hits one finds it written down.

The idea

Narrowband = underclock the baseband ADC/DAC, leave the RF in 20 MHz mode. The Jaguar2 work revealed the mechanism; the insight here is that the 8812A drives the same 0x8ac clock-divider block the 8822B uses — its [9:8] ADC-clock field is even poked (and labelled "ADC clock 160M/80M") by the existing phy_FixSpur_8812A. The vendor simply never programmed the small-BW field.

Result (bench, RTL8812AU ↔ Jaguar3 peer)

  • SDR occupied bandwidth: 20M=16.8, 10M=8.2, 5M=4.1 MHz (clean 2.05× / 4.02×)
  • 8812AU 10 MHz TX → Jaguar3 RX: 15800 hits; 5 MHz TX @2.4 GHz → 14800
  • Jaguar3 10 MHz TX → 8812AU RX: 6900 (receives narrowband too)
  • 20 MHz on-air regression 9900; ctest 13/13 (20/40/80 paths byte-unchanged — only new switch cases)

Divide codes are characterized, not guessed (tests/jaguar1_nb_divide_sweep.sh — full SDR × cross-RX grid): DAC code sets the TX lobe, ADC code sets RX sensitivity; octave-step pattern off the 20 MHz values (10M → dac2/adc1, 5M → dac1/adc0).

Scope / honest boundaries

  • 8812AU / 8811AU — supported, characterized.
  • 8821AU excluded — healthy at 20 MHz, but its 1T1R clock tree couples the DAC clock to the TX DMA/USB path; dividing it starves TX (bulk-out rc -2 failures scale with divide depth: ~35 % at 10M, ~72 % at 5M, 0 % at full clock). Gated to the 8812 die; the 8821A falls back to a 20 MHz baseband. A shared register block does not guarantee shared behavior — each die is validated on hardware.
  • 8814A excluded — different BW mechanism (0x8ac[1:0] mode selector), separate effort.
  • 5 MHz @ 5 GHz is CFO-limited — physics (quartered subcarrier spacing), not a bug; documented, tracked separately.

The doc

docs/narrowband.md (companion to docs/frequency-hopping.md) covers the underclock idea, the per-generation register machinery (Jaguar1 0x8ac, Jaguar2 0x8ac + the RF18 re-latch edge, Jaguar3 0x9b0/0x9b4), the four walls above, and the SDR-occupied-bandwidth + cross-RX validation methodology. README and CLAUDE.md updated to match.

Test knobs

DEVOURER_NB_BW=5|10 selects narrowband; DEVOURER_NB_ADC/NB_DAC expose the divide codes for characterizing other cuts. GetAdapterCaps().narrowband_ok reports support per chip.

🤖 Generated with Claude Code

josephnef and others added 4 commits July 8, 2026 17:57
…0x8ac clock block

Jaguar1 was believed to have no narrowband path ("no vendor reference,
dead enum values only"). The Jaguar2/3 work revealed the mechanism is a
baseband ADC/DAC clock divide with the RF left in 20 MHz mode — and the
8812A drives the SAME 0x8ac block: phy_PostSetBwMode8812 writes the
bandwidth via 0x8ac under mask 0x003003C3 (bits [1:0] rf-mode, [7:6]
small-BW, [9:8] ADC clock, [21:20] DAC clock), and phy_FixSpur_8812A
already pokes 0x8ac[9:8] calling it "ADC clock 160M/80M". So the divider
fields exist on 8812A silicon; the vendor just never programs small-BW.

This spike adds CHANNEL_WIDTH_5/10 to the 8812/8821 bandwidth path
(rtw_get_center_ch, phy_SetRegBW_8812 = MAC 20M, PHY_RF6052SetBandwidth
= RF 20M, and a new 0x8ac branch that divides ADC/DAC one/two notches
down + sets small-BW; phy_FixSpur skipped so it doesn't stomp the
divided clock). Divide codes are sweepable via DEVOURER_NB_ADC/NB_DAC.

Bench result (first working attempt) — the block reuse holds:
- SDR occupied bandwidth, 8812AU TX ch44: 20M=16.8, 10M=8.2, 5M=4.2 MHz
  (2.05x / 4.02x — clean halving/quartering)
- 8812AU 10M TX -> Jaguar3 RX: 15300 hits (decodable, not just narrow)
- 8812AU 5M TX @2.4G -> Jaguar3 RX: 14800 (5M works; the 5G zero is the
  #217 CFO bimodality, not a divide error)
- Jaguar3 10M TX -> 8812AU RX: 6900 (receives narrowband too)
- 20 MHz on-air regression 9900; ctest 13/13 (wide paths byte-unchanged)

Caps: narrowband_ok + kBw5/kBw10 on the 8812/8821 die only (8814A has a
separate phy_PostSetBwMode8814A path, untouched). EXPERIMENTAL — divide
codes not fully characterized, 8814/8821A-pair and 5M@5G still open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…14A gap

Divide-code characterization (tests/jaguar1_nb_divide_sweep.sh — full
SDR occupied-bandwidth grid + cross-RX vs a Jaguar3 peer):

- The DAC code (0x8ac[21:20]) sets the emitted lobe width; the ADC code
  (0x8ac[9:8]) sets receive sensitivity. Octave step off the 20 MHz
  values (DAC 3 / ADC 2):
    10 MHz -> DAC 2, ADC 1   (TX lobe 8.2 MHz; RX 4700 hits @adc1 vs 1900 @adc0)
     5 MHz -> DAC 1, ADC 0   (TX lobe 4.1 MHz; DAC 0/2 read wide)
- SDR grid: DAC>=2 yields the 10 MHz lobe; DAC=1 the 5 MHz lobe.
  The shipped defaults are the characterized optimum. TX cross-RX flat
  ~12500 across ADC (ADC doesn't shape TX); RX ADC sweep picks ADC 1.
- Comment upgraded from hypothesis to measured; DEVOURER_NB_ADC/NB_DAC
  retained as overrides for other cuts.

8814A: documented as NOT ported — it uses a different BW mechanism
(0x8ac[1:0] mode selector + phy_SetBwRegAgc_8814A, not the [9:8] divider),
so the 8812AU divide does not transplant; caps already gate it off.
8814 narrowband is a separate research effort (host TX needs the 3081
MCU; RX flaky on the host rig).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… DAC clock

Bench characterization of the 8821AU (2357:0120): it is healthy at
20 MHz (TX 15200 hits, 0 USB failures; RX 11400) but narrowband
destabilizes its TX — bulk-out submission failures (rc -2) scale with
DAC-clock divide depth: dac=2 ~35% fail, dac=1 ~72%, vs 0% at full
clock. Its 1T1R clock tree couples the DAC clock to the TX DMA/USB path,
which the divide starves; the 8812AU (separate 2T2R baseband) is
unaffected.

- Caps: narrowband_ok + kBw5/kBw10 now gated to CHIP_8812 (8812AU/8811AU)
  only, was all-non-8814.
- Path: the 0x8ac narrowband branch guards on CHIP_8812 and falls back to
  a plain 20 MHz baseband on other dies (verified: 8821AU forced-NB TX =
  0 failures, received as 20 MHz).

8812AU narrowband unaffected (10M TX -> J3 RX 15800). ctest 13/13.

Remaining known-open (not code bugs): 5 MHz @ 5 GHz is CFO-limited
(issue #217, needs the XTAL-cap trim); 8814A narrowband is a separate
effort against its different BW mechanism.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…EADME/CLAUDE

New docs/narrowband.md — the 5/10 MHz companion to docs/frequency-hopping.md:
the underclock-the-baseband idea, the per-generation register machinery
(Jaguar1 0x8ac shared block, Jaguar2 0x8ac + RF18 re-latch edge, Jaguar3
0x9b0/0x9b4), the chip-specific walls (8822B RF18 edge, 8821A DAC-clock
starve, 5 MHz/5 GHz CFO limit, 8814A different mechanism), and the
SDR-occupied-bandwidth + cross-RX validation methodology — so the next person
who hits one of these walls finds it documented.

README: link the doc, mark 8812AU/8811AU 5/10 MHz capable. CLAUDE.md: the
Jaguar1 bullet now records the 8812-die narrowband and the 8821A/8814A
exclusions; drop the stale "Jaguar1 has no narrowband" line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@josephnef josephnef merged commit eb207c2 into master Jul 8, 2026
15 checks passed
@josephnef josephnef deleted the jaguar1-narrowband-8812 branch July 8, 2026 16:09
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