P4 SDR: Handheld ESP32-P4 RTL-SDR Spectrum Receiver with ADS-B and WiFi BLE Scanner

TL;DR: P4 SDR by John-ODell turns a Waveshare ESP32-P4 Module DEV KIT, a cheap 3.5 inch Raspberry Pi touchscreen and an RTL-SDR Blog V4 dongle into a handheld spectrum and waterfall receiver with no Linux or PC in the loop. Native ESP-IDF firmware drives the dongle over USB host at 2.4 MS/s with zero dropped bytes, decodes broadcast FM with RDS plus narrow FM and AM, tracks ADS-B aircraft on a list and offline map, scans 2.4 GHz WiFi and BLE on the onboard ESP32-C6, logs everything to SD card CSV files, and ships as prebuilt flash images for chip revisions v1.x and v3.1 plus full source under GPL-3.0-or-later at v1.1.0.

The photo above says the whole project in one frame. The same receiver screen rendered in Studio, PortaPack, Phosphor, Vintage and Neon looks. One firmware, one cheap touchscreen, five personalities, and a real RTL-SDR dongle doing the RF work behind it. For hams who like bench tools that fit in a jacket pocket, this is a screen, a kit board and a dongle becoming a signal hunting instrument.

P4 SDR receiver and menu shown in all five looks Studio PortaPack Phosphor Vintage and Neon on the Waveshare ESP32-P4 kit with 3.5 inch touchscreen

What Is P4 SDR?

P4 SDR is open source ESP-IDF firmware for the Waveshare ESP32-P4 Module DEV KIT that drives an RTL-SDR Blog V4 dongle over USB host to make a handheld spectrum and waterfall receiver with ADS-B aircraft tracking plus WiFi and BLE scanning and no PC attached.

The repo tagline states it plainly: RTL-SDR Blog V4 spectrum and waterfall receiver, ADS-B aircraft map and WiFi plus BLE scanner on the ESP32-P4 kit with the 3.5 inch RPi touchscreen, native ESP-IDF, no Linux. A companion repo holds just the screen driver, esp32-p4-3.5-inch-rpi-display, MIT licensed with a flash and test tool for people who only want the display working. This repo is the full radio tool built on top of that driver.

Three facts define the design:

  1. The dongle does the RF, the P4 does everything else. The RTL-SDR tunes and digitizes. The ESP32-P4 moves 4.80 MB/s over USB high speed, runs the FFT, draws spectrum and waterfall at about 10 fps, demodulates audio, decodes ADS-B and RDS, and handles touch, settings and SD logging.
  2. The C6 does the ISM bands. The module on the DEV KIT carries an ESP32-C6. WiFi and BLE scanning run there over the esp_hosted link, so 2.4 GHz survey happens without touching the RTL-SDR stream.
  3. Everything is reproducible on a PC. The tools/preview program builds the exact drawing code on Mac or Linux, feeds it fake stations and aircraft, and writes PNG files of every screen in every look. What you see in the docs is what the firmware draws, not a mockup.

Release state at the time of writing is v1.1.0 from 18 Oct 2026 plus unreleased audio, memories, RDS, Neon look, signal markers, S/N meter and portrait work already in the tree. Licence is GPL-3.0-or-later, chosen because linked librtlsdr is GPL-2.0-or-later and GPLv3 combines cleanly with ESP-IDF Apache-2.0 code where GPLv2 can’t.

Why This Combination Matters

From TV sticks to lab tools: the RTL-SDR story

Modern cheap SDR starts in 2012 when Osmocom hackers found that Realtek RTL2832U DVB-T sticks could stream raw I/Q samples. A 20 dollar TV tuner became a wideband receiver. Community drivers, then librtlsdr, then purpose built hardware like the RTL-SDR Blog series with R820T and later R828D tuners, bias tee power, HF upconversion paths and improved clocks turned the toy into a serious instrument. The Blog V4 used here pairs the R828D tuner with a robust front end and remains the reference cheap dongle for VHF and UHF work.

P4 SDR rides that whole history. It uses the RTL-SDR Blog fork of librtlsdr unmodified, on a small libusb shim over the ESP-IDF USB host stack. The E USBH: Dev 1 EP 0 STALL lines at open time are just librtlsdr probing for other tuner types and are harmless.

Why the ESP32-P4 fits this job

The ESP32-P4 is Espressif first high performance part with no built in WiFi or Bluetooth radio. It offers a dual core RISC-V application processor, large PSRAM options, MIPI display and camera interfaces, high speed USB, Ethernet and plenty of DMA. For SDR it is attractive because CPU and memory bandwidth go to samples and pixels instead of a wireless stack.

Waveshare pairs it with an ESP32-C6 module for wireless. The C6 brings 2.4 GHz WiFi 6 and Bluetooth 5 plus 802.15.4. In P4 SDR the C6 runs WiFi and BLE scanning through esp_hosted and esp_wifi_remote version 1.4. That split keeps the RF survey tools isolated from the USB sample path.

Why the cheap 3.5 inch RPi screen

The 480×320 resistive touchscreens sold for Raspberry Pi boards are abundant, cheap and well understood: ILI9486 command set over 16 bit SPI plus XPT2046 resistive touch. They plug straight onto the DEV KIT 40 pin header, pin 1 to pin 1. The tested panel is the MHS 3.5 inch Display IPS with one square chip on the back plus the XPT2046 controller. The older MPI3501 with four logic chips uses the same protocol but is untested. Big touch keys, press highlight, fire on lift, and a 5 point calibration routine suit the resistive panel well.

Waveshare ESP32-P4 Module DEV KIT board used by P4 SDR handheld receiver

MHS 3.5 inch Display IPS back showing XPT2046 touch controller and 40 pin socket

Left: Waveshare ESP32-P4 Module DEV KIT with onboard ESP32-C6 for WiFi and BLE. Right: tested MHS 3.5 inch Display IPS panel with XPT2046 touch controller.

What You Need

Part Notes
Waveshare ESP32-P4-Module-DEV-KIT Base board. The attached C6 module runs WiFi and BLE scanners.
MHS 3.5 inch Display IPS 480×320, ILI9486 over 16 bit SPI, XPT2046 touch Tested screen. Plugs onto the 40 pin header, pin 1 to pin 1.
RTL-SDR Blog V4 dongle plus antenna Only tested dongle. Fits either USB-A port. Set H3 jumper to HOST.
Small 8 ohm speaker, optional Plugs into the 2 pin MX1.25 speaker connector. Driven by ES8311 codec plus NS4150B amp.
micro-SD card FAT32, optional Holds MAP.BIN for the ADS-B map plus LOGS/ CSV files.

Antenna choice decides results more than any setting. A telescopic whip works for strong broadcast FM. Airband, marine, NOAA weather, 2 m, PMR and 70 cm each want a resonant whip. ADS-B at 1090 MHz wants a 1090 MHz antenna with clear sky view. The dongle USB-A power rail is always on, so software can’t power cycle a hung dongle. Unplug and plug it back in if the link check fails.

Receiver Core: Spectrum, Waterfall, Audio and Memories

The receiver covers 2.4 MHz of RTL-SDR range per view with zoom steps at 2.4 MHz, 1.2 MHz, 600 kHz and 300 kHz. FFT size follows zoom from 1024 to 4096 points with Hann windowing and per frame averaging. Display elements include peak hold, a dB scale, a shaded passband, an S/N bar meter with dB figure, and up to three markers that label strong signals outside the passband with their frequencies. Touch a signal on spectrum or waterfall and it moves to centre on finger lift.

Stepping keys sit in the header at minus 1M, minus 100k, plus 100k and plus 1M with hold to repeat. Tapping the frequency readout cycles the look. The MENU key shows live gain underneath. These small choices make one hand tuning practical on a resistive panel.

Audio path

The filter choice also picks the mode: WFM 200k, NFM 25k, NFM 12.5k and AM 8k. Demodulation runs FIR decimation to 480 kS/s then WFM, NFM or AM to 48 kHz output. Volume from 0 to off plus squelch in 3 dB steps: on FM each step wants 3 dB more quieting so an on air station opens it, on AM each step wants more level above heard noise. Squelch fades over 5 ms instead of hard switching, and AM grabs a new carrier level at once, which avoids clicks. A mode plate on the spectrum shows the active filter and lights its speaker icon while sound plays. Output is mono because the kit has one speaker channel.

Honest status: the demodulator passes its host test in tools/demod_test on synthesized FM and AM stations with neighbours and stereo pilot, but audio hasn’t yet been heard on real kit hardware with a speaker. Load on the P4 and subjective sound remain to be checked.

RDS on broadcast FM

On broadcast FM the chain adds RDS: 57 kHz down mix, bit timing, block sync, station name and RadioText. The decoded name replaces volume on the mode plate. While programme ID, name and RadioText go to the serial log. So far RDS is verified on synthesized stations with clock offsets up to 100 ppm, not yet on live broadcast captures.

Bands, gains and memories

Band presets cover FM, AIR, MARINE, NOAA, 2M, PMR, 70CM and ADS-B at 1090 MHz. Gain walks every tuner step plus AGC, 15, 30 and MAX positions. Range runs auto or manual top level and span in 5 dB steps. Channel memories hold 8 slots of frequency plus filter. MENU then SCAN then SAVE stores the tuned channel, MEMORY tunes a slot, and SCAN hops through stored slots and stops while squelch is open plus 2 s after. Any touch stops the scan. Settings persist to flash.

ADS-B at 1090 MHz: List, Map and Offline Base Map

Tune the ADS-B band preset and the receiver hands the whole screen to ADS-B and pauses spectrum work. Two views cover traffic:

P4 SDR ADS-B aircraft list showing callsign altitude speed heading and climb rate

ADS-B aircraft list: callsign, altitude, speed, heading, climb rate and message counts.

P4 SDR ADS-B aircraft map with range rings from 5 to 400 km on ESP32-P4 handheld

ADS-B map with range rings from 5 to 400 km. Add MAP.BIN on SD card for coastlines and towns.

The list shows callsign, altitude in feet, speed in knots, track heading, vertical rate and message counts. The map plots aircraft with range rings from 5 to 400 km. With no SD card that’s the whole map: rings plus targets on a blank field, still useful for direction and distance.

Add a FAT32 card with MAP.BIN in the root and the map gains coastlines, lakes, rivers, borders, roads, runways, towns and airports. The file is built on a computer from Natural Earth data plus OpenStreetMap detail near the centre:

python3 tools/mapgen/make_map.py --place "Leeds, UK" --out /Volumes/SDCARD/MAP.BIN
python3 tools/mapgen/make_map.py --lat 52.31 --lon 4.76 --name SCHIPHOL --radius 300

The generator needs only the Python standard library. First run downloads about 27 MB of Natural Earth data into ~/.cache/p4-sdr-mapgen. OSM detail arrives through the public Overpass API, which is often busy. Failed queries still write a map without that layer, rerun later to fill it in, or pass --no-osm to skip Overpass. The card is read once, the first time ADS-B opens. Centre the map near your antenna because the map centre becomes home on the kit.

WiFi and BLE Scanners on the ESP32-C6

Like ADS-B, each scanner takes the full screen and pauses the receiver. EXIT returns to radio work at the previous frame rate.

P4 SDR WiFi scanner list of 2.4 GHz access points on ESP32-C6

WiFi list on the C6: SSID, BSSID, channel, RSSI and security per network per sweep.

P4 SDR WiFi channel view showing one hump per network across 2.4 GHz band

Channel view: one hump per network across the 2.4 GHz band. Fast way to spot congestion.

P4 SDR BLE scanner listing nearby Bluetooth devices with signal and advert count

BLE scanner: name, maker or service, address, signal, connectability and advert counts.

The WiFi scanner lists 2.4 GHz access points with SSID, BSSID, channel, RSSI and security, plus a channel view that draws one hump per network. The BLE scanner lists nearby devices with name, maker or service, address, address type, RSSI, connectability and advert counts. Measured on chip v1.0 hardware: 29 networks across 5 sweeps of about 2 s each, and 13 BLE devices in 10 s. Only 2.4 GHz WiFi is possible because the C6 has no 5 GHz radio.

Logging to SD Card

With a FAT32 card in the slot, each mode writes CSV files to LOGS/ while open. The header shows a red dot plus REC while recording, just the dot where space is short, and SD ERR on write failure. Without a card nothing changes.

File One row Columns
ADSBnnnn.CSV per aircraft, at most every 5 s, when heard since its last row t_s, icao, callsign, alt_ft, speed_kt, track_deg, vrate_fpm, lat, lon, msgs
WIFInnnn.CSV per network heard in each sweep, about every 2 s t_s, bssid, ssid, channel, rssi_dbm, security
BLEnnnn.CSV per device heard in the last 5 s t_s, address, address_type, rssi_dbm, name, maker_or_service, connectable, adverts

Session number nnnn steps up each power on. Reopening a mode in the same session appends to its file. Time t_s counts seconds since power on because the kit has no clock, so cards show files dated 1980 and analysis joins on elapsed time. Text fields are quoted and empty until heard. Measured sizes: ADS-B about 0.2 MB per hour with 8 aircraft in view, WiFi about 4 MB per hour with 45 networks nearby. A low priority task writes rows and syncs the card every 2 s, so pulling the card loses at most the last 2 s. A 14 minute ADS-B log of 24 aircraft and 815 rows showed no gap over 5 s with the decoder at 22 percent load and zero bytes dropped.

Five Looks and Portrait Mode

MENU then LOOK picks Studio, PortaPack, Phosphor, Vintage or Neon in violet, cyan and magenta. The header frequency readout also steps through looks with one tap. Boot splash, menus and all screens follow the saved look with an animated tune in splash.

P4 SDR portrait mode with receiver menu ADS-B map and WiFi list in Neon look

Portrait mode: USB ports up, step keys under the frequency, two wide menu tiles, scanner keys in a row. Saved across reboots with software turned touch calibration.

LOOK then TURN switches landscape and portrait. Portrait stands the kit with USB-A and Ethernet at the top and the dongle pointing up. Step keys move to a row under the frequency, the eight menu tiles flow two wide, and ADS-B plus scanner keys sit in a row under their title. Choice persists across reboots. Touch calibration stays in landscape and turns in software, so no recalibration is needed. Status: portrait is verified in tools/preview only, on kit orientation and touch mapping are still to be confirmed.

Flashing and First Boot

  1. Plug the kit USB TO UART Type-C port to your computer.
  2. Find chip revision:
esptool.py --chip esp32p4 -p PORT flash_id

Look for Chip is ESP32-P4 (revision vX.Y) in the output.
3. Grab the matching image from the latest release:
– p4-sdr-1.1.0-rev1.bin for v1.x early kits, tested on v1.0
– p4-sdr-1.1.0-rev3.bin for v3.1 and later, built but not tested on hardware
4. Flash at 921600 baud:

esptool.py --chip esp32p4 -p PORT -b 921600 write_flash 0x0 p4-sdr-1.1.0-rev1.bin

Port names look like /dev/cu.usbmodem... on macOS, /dev/ttyACM0 on Linux or COM5 on Windows. Images are full flash images, so saved settings and touch calibration clear on flash. Check against SHA256SUMS on the release page. Web flashers can read workbench-manifest.json for URL, flash address, size, SHA-256 and supported revisions.

First boot sequence:

  1. Splash. Drawn in the saved look with a short tune in animation. First boot runs 5 point touch calibration. Tap each cross centre. Hold the screen during splash later to redo it.
  2. Dongle search. Firmware looks for the RTL-SDR on USB-A ports. If absent, check the H3 HOST jumper, then reseat the dongle.
  3. Link check. A 1.5 s USB test streams a byte counter so any lost byte is caught before receiving starts.
  4. Receiver. Starts at 100.0 MHz FM broadcast, then at the last used frequency after that.

Serial console on USB TO UART at 115200 baud logs fps, USB errors, noise floor and sample rate every 5 s, plus free internal RAM, low water mark and largest DMA block.

Building From Source and Test Tools

You need ESP-IDF v5.5, tested with v5.5.5:

. $IDF_PATH/export.sh
idf.py build
idf.py -p PORT -b 921600 flash monitor

For v1.x chips, add sdkconfig.rev1 to defaults from a clean tree:

rm -f sdkconfig
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.rev1" build

Component manager fetches esp_hosted, esp_wifi_remote and esp_codec_dev on first build, pinned in dependencies.lock. Script tools/build_release.sh builds both chip images into dist/ with SHA256SUMS and the Workbench manifest.

Host side test tools run without hardware:

  • tools/preview builds drawing code on Mac or Linux, feeds fake stations and aircraft, writes PNG files of every screen in every look plus portrait variants.
  • tools/adsb_test runs the ADS-B decoder against known messages.
  • tools/demod_test runs audio demod on synthesized FM and AM stations with neighbours, stereo pilot and RDS groups, checking tone, squelch and decoded ID plus name and RadioText with station clocks up to 100 ppm off.
  • tools/capture_log.py PORT SECONDS resets the kit and prints its serial log. --attach skips reset and survives USB serial dropouts for long runs.
  • tests/stage1_stream_test.c runs a 20 s USB counter and sample test when copied over main/main.c.

Code Tour and Dual Core Split

File Job
main/main.c boot, splash, calibration, link check
main/sdr.c dongle open, tune and gain, read_async into 1 MB PSRAM IQ ring
main/spectrum.c Hann window, 1024 to 4096 FFT by zoom, averaged per frame
main/view.c, main/panel.c all receiver and menu drawing in five looks and both orientations, no ESP-IDF calls
main/ui.c receiver loop, touch tracker, saved settings, stream recovery, mode switching
main/demod.c FIR decimation to 480 kS/s, WFM NFM AM to 48 kHz, squelch, no ESP-IDF calls
main/rds.c 57 kHz down mix, bit timing, block sync, name and RadioText
main/dsp.c shared FIR filters and atan2 for demod and RDS
main/audio.c ES8311 codec, I2S, feeder task from IQ ring
main/adsb.c, main/adsb_view.c ADS-B demod plus decoder, list and map screens
main/amap.c, main/sdcard.c SD base map format in amap.h, shared card mount
main/sdlog.c CSV logs, PSRAM ring, writer task, per boot numbering
main/radio_scan.c, main/scan_view.c C6 WiFi and BLE scanning plus screens
components/rtlsdr Blog fork librtlsdr unmodified on libusb shim over ESP-IDF USB host
components/rpi_display screen, text, canvas, touch and calibration from the screen repo
tools/mapgen make_map.py for MAP.BIN

Core 0 runs USB host, IQ stream and audio demod. Core 1 runs FFT, drawing and touch. That split is why the waterfall holds near 10 fps while USB moves full rate samples without loss.

Measured Performance on Chip v1.0 plus Blog V4

  • Dongle enumerates at USB high speed through the kit CH334F hub.
  • Counter test 20 s at 2.4 MS/s: 4.80 MB/s with 0 bytes lost and 0 USB errors.
  • Receiver: 9.8 fps at FFT 1024 and 9.4 fps at FFT 4096 with 0 USB errors at full IQ rate.
  • WiFi: 29 networks in 5 sweeps of about 2 s each. BLE: 13 devices in 10 s. Receiver returns at 9.8 fps.
  • SD logging: 14 minute ADS-B log, 24 aircraft, 815 rows, no gap over 5 s, decoder 22 percent, 0 bytes dropped. Same session logged 88 WiFi networks and 40 BLE devices, receiver back at 10.1 fps.
  • Long run one boot with card and logging: 18 min receiver, 3.5 min WiFi, 6 min BLE, then 44 min ADS-B. All 530 ADS-B reports at 22 percent decoder load, 0 bytes dropped, free internal RAM flat at 58 KB. ADS-B log 1,221 rows over 51 aircraft, only long gaps are quiet skies, 0 rows dropped at close.
  • RAM: 75 KB free on receiver at boot. First WiFi or BLE visit costs 11 KB once because the C6 link stays up, leaving 64 KB. Later visits return to the same figure with low water mark at 43 KB.

Honest Limits Before You Build

  • Audio hasn’t been heard on hardware yet. Host tests pass, speaker load and sound quality are still open. FM is mono by hardware.
  • RDS is synthesized station tested only, not yet live air verified.
  • Only RTL-SDR Blog V4 is tested. Other dongles may enumerate but are unverified.
  • Only chip v1.0 hardware is tested. The rev3 image builds but has no hardware run yet.
  • Portrait is preview tool verified only. On kit orientation and touch mapping need confirmation.
  • WiFi is 2.4 GHz only by C6 hardware. No 5 GHz survey.
  • USB-A power is always on, so no software power cycle for a hung dongle.
  • No real time clock, so logs use seconds since power on and cards stamp files as 1980.

P4 SDR vs the Alternatives

Option Form PC needed Key strengths Best for
P4 SDR on ESP32-P4 kit Handheld 3.5 inch touch No after flash Real 2.4 MHz spectrum plus waterfall, ADS-B map, WiFi plus BLE, CSV logs, 5 looks Bench and field signal hunting on a budget
LakeShark on T-Display P4 Handheld AMOLED touch No after flash Onboard LR2021 SDR plus P25 voice, ADS-B, MeshCore, maps, Flipper head Pocket scanner with P25 and messaging
OrcSDR on M5Stack Tab5 Handheld touch No after flash Full RTL-SDR plus RF lab measurements Portable lab measurements
PortaPack H2 plus HackRF Handheld touch No TX capable to 6 GHz, many apps, large community Wideband TX experiments
Laptop plus SDR++ or SDRangel Laptop workstation Always Wide bandwidth, plugins, deep analysis Desk analysis and weak signal work
Bare RTL-SDR on PC USB dongle Always Cheapest entry, huge software choice Starting out or decoding on a computer

P4 SDR wins where a no PC spectrum display with credible ADS-B and ISM survey matters and parts stay cheap and replaceable. It concedes trunked digital voice, transmit, and wideband analysis to the other rows, and it documents that gap instead of hiding it.

Practical Field Uses for Hams

  • Band reconnaissance. Power on at 100.0 MHz, check broadcast FM for antenna sanity, then walk AIR, MARINE, NOAA, 2M, PMR and 70CM presets. Tap to centre, watch markers flag activity outside the passband, save hits to 8 memories for the day.
  • ADS-B site survey. Put a 1090 MHz whip with sky view on the dongle, open ADS-B, compare list versus map rings, then build MAP.BIN centred on the site for repeatable range tests.
  • RFI and occupancy survey. Use WiFi channel humps plus BLE counts to pick clean channels for hotspots, mesh nodes and club station links. Export CSV logs and graph RSSI by time in a spreadsheet.
  • Club demo table. Five looks plus portrait mode make a good crowd display. Studio for talks, Phosphor for nostalgia, Neon for night events. Touch to tune invites hands on use without keyboard fear.
  • Training nights. Link check, gain steps, range span, zoom FFT tradeoff, squelch quieting versus AM level: every core SDR concept is one touch away with live serial stats at 115200 baud for the curious.

Frequently Asked Questions

What hardware do I need for P4 SDR?
Waveshare ESP32-P4 Module DEV KIT, MHS 3.5 inch IPS screen, RTL-SDR Blog V4 with antenna, plus optional 8 ohm speaker and FAT32 SD card. Set H3 to HOST.

Does P4 SDR need a PC to run?
No. A PC flashes firmware once with esptool. Daily use, tuning, ADS-B, WiFi, BLE and logging all run on the handheld.

Which chip revisions are supported?
Prebuilt rev1 image boots v1.x kits and is hardware tested. Prebuilt rev3 image targets v3.1 and later but isn’t yet hardware tested.

Can it record what it hears?
Yes with an SD card. ADS-B, WiFi and BLE write timestamped CSV logs to LOGS while each mode is open for spreadsheet analysis.

Is P4 SDR free and open source?
Yes, GPL-3.0-or-later with third party parts listed in THIRD_PARTY. Map data credits go to OpenStreetMap contributors and Natural Earth.

Sources and Further Reading

73 de 9M2PJU

Post Comment