Skip to content

SF6 / 125 kHz: four channels at 5.1 chirps

Measured 2026-09-14. Seven packets received, then packet 8 missed. The run stopped at that first miss. No RF retry, other dwell, or higher/lower channel count was tested. The target of 100 packets per channel was not reached.

Follow-up: SF8/125 at the same 5.1-chirp dwell missed on packet 13 and captured an off-channel preamble hold. That differs from the absence of observed preamble in this SF6 failure.

Setup

  • XIAO ESP32-S3 + WIO SX1262 scanner, COM31.
  • SenseCAP Indicator ESP32-S3 reference transmitter, COM28.
  • Four centers: 909.500, 909.750, 910.000, 910.250 MHz.
  • SF6 / 125 kHz / CR4/5, 32-symbol programmed TX preamble.
  • User-corrected dwell: 5.1 symbols, ceil(5.1 * 512) = 2,612 us.
  • Same warm production fast retune, buffered 8 MHz SPI, packet guards.
  • 16-byte synthetic payloads at -9 dBm; balanced randomized channel order, seed 606125; varied arrival timing, not synchronized to scan phase.
  • IRQ changes, IRQ clears, hops and first guard deferrals buffered in RAM. Additional read-only IRQ polling at nominal 64 us intervals while armed. No per-event serial printing during capture. Trace read after each result.
python tools/hil/profile_switch_channels.py --receiver COM31 --sender COM28 --output tools/hil/sf6_125_5p1_trace_results.json --samples 100 --preamble 32 --max-channels 4 --dwell-symbols 5.1 --trace

Results and what the trace establishes

Probes 1–7 succeeded on channels 3, 2, 1, 0, 2, 3, 1. Probe 8, sequence 944962150, missed on channel 0 (909.500 MHz). Thus channel 0 had already received a valid probe; this was not a channel that never worked at all. Successful packets had RSSI -42 to -40 dBm and SNR 9.5 to 10.8 dB.

The failed probe has a complete, non-overflowed 3,160-event trace:

  • Expectation armed on channel 3 without selecting the expected channel.
  • 3,158 completed hops during the bounded 10-second confirmation interval.
  • No observed nonzero IRQ bits: no preamble, header, RxDone or CRC event.
  • No guard-held visit on any channel during that expectation.
  • Receiver timeout at 10,000,369 us, with RX mode and zero device errors.
  • Reference TX returned success. All USB sequence acknowledgements matched; no stale replies, missing acknowledgements or cached transport recovery.

The scanner was not stuck on the wrong channel by a false preamble. It also did not acquire a header and then fail a CRC check. The evidence locates the failure before observed preamble acquisition, not at payload decoding. It does not prove why acquisition failed: a short-visit/arrival-phase issue remains a candidate, as does an unobserved RF/reference issue. There was no independent RF capture, and the two MCU clocks were not synchronized.

Actual timing during the failed expectation

Measurement Minimum Mean Maximum
Receive dwell, 3,158 hops 2,613 us 2,628.706 us 2,646 us
Retune, trace hop rows 526 us 538.700 us 630 us
Channel 0 revisit interval, 789 cycles 12,643 us 12,666.829 us 12,705 us

The repeatable scan timing rules out a large software scheduling stall in the failed capture. The 32 programmed symbols occupy 16.384 ms, longer than that idle scan cycle; nevertheless, revisiting within the preamble did not ensure successful acquisition during these short individual visits.

Successful acquisition traces

Times below are relative to the logged hop completion onto the eventual receive channel, not a precisely captured RF edge or hardware RX-start edge. The trace observed the following progression for every successful probe: PreambleDetected (0x0004), HeaderValid (0x0014), RxDone (0x0016), consumption.

Probe Channel First observed preamble after hop RxDone after hop
1 3 1,838 us 32,982 us
2 2 1,836 us 35,470 us
3 1 1,844 us 35,151 us
4 0 2,332 us 37,329 us
5 2 1,847 us 35,532 us
6 3 1,831 us 30,731 us
7 1 1,329 us 32,567 us

After detecting preamble, the production guard kept those visits on-channel until reception completed. The failed probe never reached that observed state. This is not evidence that 5.1 symbols always suffice, nor does 7/8 estimate a stable packet-error rate or establish a channel-capacity limit.

Instrumentation and reporting caveats

The failed capture made 115,783 diagnostic IRQ polls, costing a total 2,821,617 us (about 24.4 us each; maximum 61 us). These reads are not free: they alter loop load, although actual dwell and revisit timing were measured. This is not a matched A/B against the earlier untraced 4.8-symbol run, so seven successes versus two cannot be attributed solely to the extra dwell.

The run used channel_trace: 1. During analysis, a reporting bug was found in the newly added held_dwell aggregate: production startRecv() resets the visit timestamp after reading a packet. That aggregate therefore omitted the preceding held reception time. Do not use its 2.709 ms mean as total held occupancy. The timestamped IRQ/hop trace above is the evidence for the actual 30.7–37.3 ms hop-to-RxDone intervals. The failed capture had no RX restart, so its dwell rows are unaffected.

The source now keeps a separate channel-occupancy timestamp (channel_trace: 2, trace_format: 2). Both HIL targets compiled with this reporting-only correction; it was not flashed or RF-tested, and the saved raw result was not rewritten. Scheduler, packet guard and radio commands were not changed by that correction. Regression coverage includes passive SPI observation, bounded/frozen capture, occupancy accounting, page identity, requested dwell, and stopping at the first miss.

Provenance and device handoff

Raw result SHA-256: 7caa16483b7b0000b388a1906395fe3d381bd0e40de73f48cd5c876d96deab3b.

Actually tested firmware SHA-256 (trace version 1, before reporting fix):

  • XIAO: 35c201f367b0aaa693be03542a4c115024d1a70a2be2fbdbef2c94da5a6053ae
  • Indicator: 8a25d84fc99f6aeaf8318bf4533767e16a9afc0de51394fce27d3a610c63b352

Base commit c329cf1fc1e7f2e8c8733ab0d000094730458fe3 plus local changes; RadioLib 7.7.1 at 187ef24791c3d844939b2be13a68bd890bd04e4c, Espressif32 6.11.0 / Arduino ESP32 2.0.17. No normal production firmware change this turn.

Fresh full 8 MiB snapshots were saved and digest-verified before flashing:

  • XIAO: 35aa2deeb8a8145bc54435c9f87b3db1c65f320f2568ee0b489305db1a6330c2
  • Indicator: dba59cde1df3c69dd2e5995950315951f75cd43886b21be8b14e261ec4b57309

Both snapshots were restored afterward, separately verified against the full flash, and hardware-reset. Snapshots remain in the private current-user backup directory. The RAK4631 and Indicator RP2040 were not modified; the XIAO soak logger was not restarted. Changes were initially handed off locally before publication.