Custom Zephyr firmware that achieves ~77 kHz continuous BLE RSSI sampling on the Nordic nRF54L15 — 3× the rate of prior published results — by bypassing all BLE protocol processing and streaming raw radio energy measurements directly over UART.
Copyright © 2026 Haofei Sun. Released under the MIT License.
Commodity BLE receivers normally cap RSSI sampling at ~25 kHz because each sample passes through preamble detection, packet framing, CRC, and host-side stack processing. For wireless sensing applications (LoRa cross-technology sensing, motion / vital-sign detection, RF spectrum monitoring) we need continuous, gap-free, high-rate energy measurements at the RADIO peripheral level — protocol processing is irrelevant and harmful.
This firmware reconfigures the nRF54L15 RADIO into a pure energy detector: no packet processing, no shortcuts, no auto-disable. The RADIO enters RX once and stays there forever. Each RSSISTART → RSSISAMPLE cycle takes ~13 µs, the value is read inside irq_lock() and pushed to UART as a single byte at 921600 baud. The result is a continuous stream at ~77 kHz with drops < 0.01%.
| Technique | Why it matters |
|---|---|
NRF_RADIO->SHORTS = 0 |
Prevents the RADIO from automatically leaving RX on any event |
PCNF0 = 0, PCNF1 = 0, CRCCNF = 0, BCC = 0 |
Disables preamble detection, packet framing, CRC, bit counter — RADIO stays in RX state forever |
FREQUENCY = 40 (2440 MHz) |
Forces fixed frequency, no channel hopping |
| HFXO + FICR trim values | Applies all 21 RADIO trim words from FICR to maintain receiver sensitivity |
| Errata 31, MLTPAN-6/56, fast_ramp_up | Critical RADIO workarounds for nRF54L15 silicon |
Inline UART streaming inside irq_lock() |
Sample → byte-out → next sample, no buffering, no ISR latency |
| 16-byte sync header every 1024 samples | 0xDEADBEEF magic + sequence + timestamp + length, for downstream gap detection |
| 921600 baud UART | Sustains 1 byte/sample at 77 kHz with margin |
| Optional AAF wideband override | Widens the analog anti-alias filter for true wideband energy capture |
- Nordic nRF54L15-DK (development kit)
- Host PC with USB serial adapter (J-Link OB on the DK works at 921600 baud; XDS110 does NOT)
- Antenna connected to the J1 RF connector (SMA)
- NCS v3.2.2 (Nordic Connect SDK)
# Source nRF Connect SDK environment
source ~/ncs/v3.2.2/zephyr/zephyr-env.sh
# Build for nRF54L15-DK
west build -b nrf54l15dk/nrf54l15/cpuapp -p
# Flash
west flashThe default CAPTURE_MODE in src/main.c is 3 (HSRSSI — high-speed RSSI). Other modes are available for development:
| Mode | Purpose |
|---|---|
| 0 | AUXDATADMA — direct DMA capture (advanced, hardware-specific) |
| 1 | CSTONES — channel sounding tones |
| 2 | RSSI — standard BLE RSSI capture (~25 kHz) |
| 3 | HSRSSI — high-speed continuous RSSI (~77 kHz, this paper) |
The firmware emits a continuous binary stream:
[16-byte header] [1024 × 1-byte RSSI samples] [16-byte header] [1024 samples] ...
Each header:
| Offset | Field | Bytes |
|---|---|---|
| 0 | Magic = 0xDEADBEEF |
4 |
| 4 | Sequence number | 4 |
| 8 | Sample timestamp (chunk start index) | 4 |
| 12 | Chunk length (= 1024) | 4 |
Each sample is a signed int8 RSSI in dBm (e.g. -67).
scripts/capture_simultaneous.py reads the UART stream, validates headers, detects gaps, and (optionally) captures synchronized USRP B210 IQ in parallel for ground-truth comparison.
# Just BLE
python scripts/capture_simultaneous.py \
--ble-port COM7 --ble-direct \
--no-usrp \
--duration 60 --out my_capture.npz
# BLE + synchronized USRP (for ground truth)
python scripts/capture_simultaneous.py \
--ble-port COM7 --ble-direct \
--usrp-rate 500000 --usrp-gain 10 \
--duration 120 --out my_capture.npzThe output .npz contains:
ble_rssi: int8 array of RSSI samples (dBm)ble_rate: actual sample rate (typically ~76800 Hz)ble_drops,ble_n_packets: integrity statisticsble_wall_time: capture start (UNIX timestamp)usrp_iq: complex64 IQ samples (if USRP enabled)
Measured on nRF54L15-DK + J-Link OB UART @ 921600 baud:
| Metric | Value |
|---|---|
| Sustained sample rate | 76,843 Hz |
| Drops (over 120 s) | < 0.01% (typically 0–2 missing chunks) |
| Sample bit-depth | 7 bits (signed dBm, range −127…0) |
| Frequency | 2440 MHz (fixed) |
| Receiver sensitivity | Equivalent to standard BLE RX (FICR trims applied) |
This is 3× higher than the ~25 kHz typically reported for BLE RSSI sampling on commodity hardware (e.g. CC2652, ESP32, prior nRF52 work).
.
├── src/
│ ├── main.c # Full firmware (4 capture modes; CAPTURE_MODE=3 is HSRSSI)
│ ├── rssi_highspeed.c # High-speed RSSI helper module
│ └── rssi_highspeed.h
├── scripts/
│ └── capture_simultaneous.py # UART receiver + optional USRP capture
├── prj.conf # Zephyr Kconfig fragments
├── CMakeLists.txt # Zephyr build script
├── LICENSE # MIT — Copyright (c) 2026 Haofei Sun
└── README.md
If you use this firmware in academic work, please cite (placeholder):
@misc{sun2026hsrssi,
author = {Haofei Sun},
title = {High-Speed BLE RSSI Sampling on nRF54L15},
year = {2026},
howpublished = {\url{https://github.com/HumphreySun98/High-speed-BLE-RSSI-sampling-rate}}
}Built on top of the Nordic Connect SDK (NCS v3.2.2) and the Zephyr RTOS. The RADIO peripheral configuration is based on the nRF54L15 Product Specification and Errata documents from Nordic Semiconductor.
This firmware was developed to support cross-technology wireless sensing research; see also the companion repository physical-informed-DL-for-wireless-sensing for the deep-learning processing pipeline.
MIT License — Copyright © 2026 Haofei Sun. See LICENSE for details.