ESP-SDR: an ESP32 turned into a receive-only SDR
ESP-SDR uses the undocumented raw I/Q capture functionality of ESP32 family chips to turn them into (low-duty-cycle) Software Defined Radios
At a glance
- What is it?
- ESP-SDR is GPL-3.0 firmware that pulls raw I/Q samples out of the Wi-Fi and Bluetooth receiver already inside an ESP32 and streams them to a computer. It is a genuinely useful hack with three sharp edges: the PLL only locks near 2.4 GHz, gain is not calibrated, and only some chips can capture without gaps.
- Who is it for?
- ESP-SDR suits engineers and hobbyists who already own ESP32 boards, want raw I/Q or a live spectrum in the 2.4 GHz band, and can accept a narrow tuning range and uncalibrated gain. It does not suit anyone who needs wideband reception, calibrated power levels, or gapless data over UART.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why an existing Wi-Fi chip can stand in for an SDR dongle
ESP-SDR is firmware that turns the radio already inside a common ESP32 board into a receive-only software defined radio. According to the project, the firmware captures raw I/Q samples from the chip's own receiver and sends them to a computer over USB or UART, so no separate SDR hardware is required. The audience is a hobbyist or engineer with a spare development board who wants to see what is happening in the 2.4 GHz band, watch a live spectrum, or hand samples to a program such as Gqrx or GNU Radio without buying a dedicated receiver. The README also states plainly that the capture mechanism is undocumented and that parts of the firmware are AI generated, and the supported chips table admits the PLL only locks near 2.4 GHz. Those three limits shape every decision that follows.
The undocumented debug path that bypasses the Wi-Fi modem
The normal route for samples inside an ESP32 is short and fixed: the receiver feeds them straight into the fixed-function Wi-Fi modem and the CPU never sees them. The project found an undocumented debug path that lets the CPU read those same samples instead, and docs/how-it-works.md walks through the mechanism register by register. The source layout mirrors how much of the code is chip specific. main/targets/<chip>/ holds the per-chip receiver, tuning and capture memory guard, main/families/c5_c6_c61/ holds one receiver shared by the C5, C6 and C61, and main/common/ carries serial transport, gain, limits, bandwidth, spectrum and ring capture. main/diagnostics/ contains optional register probes that are explicitly not part of release builds, and platform/esp32s2/ is a patched copy of the ESP-IDF USB CDC console needed for the S2. The memory guard deserves attention: raw capture on a chip with little internal RAM is a bounded operation, so the code has to defend that boundary explicitly.
Flashing from the browser, then building twelve variants from source
Two web pages cover the quick start. The firmware installer at espargos.net/espsdr/app/flash.html flashes the build, and the viewer at espargos.net/espsdr/app/ connects to the board once it is running. The quick start section describes exactly two steps: flash the firmware, open the viewer and connect. For continuous streaming into Gqrx and GNU Radio, the project points at an ESP32-S31 with SoapyESPSDR or an ESP32-S3 with esp-sdr-bridge. Building from source needs the ESP-IDF commit pinned in firmware-targets.json, after which install.sh <target> and export.sh prepare the environment and each chip is compiled in its own build directory, using a matching sdkconfig.defaults file such as sdkconfig.defaults.esp32s3. Separating the SDK configuration from the build output is what lets one tree cover so many parts:
idf.py -B build-s3 -DIDF_TARGET=esp32s3 \
-DSDKCONFIG=build-s3/sdkconfig \
-DSDKCONFIG_DEFAULTS=sdkconfig.defaults.esp32s3 build
idf.py -B build-s3 -p /dev/ttyACM0 flashThe S31 additionally needs idf.py --preview. Release images are produced the way CI produces them, and there are host side tests plus a hardware check that walks every spectrum profile of a connected board:
tools/build_firmware.py --profile <id>
python3 -m unittest discover -s tests
tools/check_spectrum.pyBecause the ESP-IDF commit is pinned, an upgrade is a deliberate act rather than a pull.
The tuning range is accepted on paper and limited on air
Every supported chip accepts a tuning command from 100 to 6000 MHz, but the radio path is narrower than that range suggests. The PLL only locks in a limited range around 2.4 GHz, plus 5 GHz on the C5. Below that band the picture gets more specific: the ESP32, C2, C3, S2 and S3 reach down to about 1.85 GHz using a 5/6 LO divider, and the C6 only to about 1.95 GHz. The C2 carries its own crystal caveat, since the documented sample rates assume a 26 MHz crystal and the firmware must be rebuilt for 40 MHz. The ESP32-H2 is listed at lower rates of 32, 16, 10.667 and 6.4 MS/s because it uses the Bluetooth radio instead. The practical consequence is that a frequency request can be accepted by the parser and still fail to lock, which is a different kind of failure from a hard error and one that a newcomer tends to misread as a broken antenna.
Gapless capture exists, but only a small share of it gets analyzed
The README separates two ways of getting data out of the chip. A burst capture holds up to 16,380 samples, which is 8,190 on the C2 and 12,284 on the S2, so consecutive bursts leave gaps. Over UART every spectrum is built from separate captures like that, and the viewer then reports that reception has gaps between captures. Continuous capture removes those gaps, but only over native USB, and only on the C6, C61, S3 and S31. The chip keeps recording while it computes spectra, yet it cannot transform everything it records: only a small share of the signal, often a few percent or less, reaches a spectrum, and the viewer exposes that share as FFT coverage. The mode exists at 256 FFT bins on the C6 and C61 and at all sizes on the S3 and S31. On the S3 the second core filters and decimates the 16 MS/s stream down to 15.625 to 250 kS/s and sends it gapless. The separate and experimental esp32s31-stream firmware pushes 8-bit I/Q at up to 20 MS/s over high-speed USB or 40 MS/s over Gigabit Ethernet. A gapless stream and a fully analyzed stream are different products, and only the S3 and S31 give you both.
A 2 Mbaud line protocol with three hardware gotchas
Talking to the firmware is a line-based protocol over native USB or UART at 2 Mbaud, with binary payloads protected by CRC32. The commands are short, and the documented examples cover a query and a capture request:
INFO
FREQ 2442
CAP16 4096 0The full reference lives in docs/protocol.md. Three hardware details decide whether a session works at all. A UART adapter has to hold 2 Mbaud reliably, and slow bridges such as some CH340 boards can fall back to the viewer option called Switch to 1 Mbaud. Power matters more than it looks, because the radio draws current spikes when it starts and a board fed from the 3.3 V pin of a USB-UART adapter can brown out and reboot in a loop, so a proper supply is the fix. On Linux, ModemManager may probe Espressif USB devices and reset them, and the project suggests stopping it or telling it to ignore the device when a board resets unexpectedly.
Where the host side tool, and the GPL-3.0 licence, change the decision
The alternatives are not equally suited to the same job, and the difference is one of approach rather than brand. The project's own framing is that no extra SDR hardware is needed, so the receiver already sitting in a development board becomes the receiver. Inside the project, the host side path matters as much as the radio path. The browser viewer consumes burst captures over native USB or UART and works with every supported chip, and it remains the only path for the standard firmware on parts without native USB. The S3 can also run a gapless decimated I/Q stream, and the S31 has a separate streaming firmware. SoapyESPSDR and esp-sdr-bridge sit between the board and Gqrx or GNU Radio, so a continuous stream is available only where a board and a host tool line up. Two further facts bear on adoption. Gain is not calibrated in dB, so absolute level readings should not be trusted. The licence is GPL-3.0, so anyone shipping firmware derived from this one takes on the same obligations.
Editorial conclusion
ESP-SDR suits engineers and hobbyists who already own ESP32 boards, want raw I/Q or a live spectrum in the 2.4 GHz band, and can accept a narrow tuning range and uncalibrated gain. It does not suit anyone who needs wideband reception, calibrated power levels, or gapless data over UART. Before adopting it, verify three things on your own hardware: that the PLL locks at the frequencies you intend to use, that the transfer path sustains 2 Mbaud without resets, and that your board has native USB if you need continuous capture. The last push was on 2026-10-17 and the repository publishes no GitHub releases, so the tree itself is the artifact you would track.
Frequently asked questions
Which ESP32 chips does ESP-SDR support?
The supported set covers the ESP32, C2, C3, C5, C6, C61, H2, S2, S3 and S31, each marked as supported in the project table. The H21 and H4 are marked as not yet supported, and the P4 is marked as not possible because it has no radio.
Does ESP-SDR capture without gaps?
Continuous capture over native USB exists on the C6, C61, S3 and S31, but only a small share of the signal is turned into spectra, often a few percent or less. Every spectrum over UART is built from separate burst captures with gaps in between.
How do I flash ESP-SDR firmware onto my board?
The project points to a browser firmware installer at espargos.net/espsdr/app/flash.html, followed by the browser viewer at espargos.net/espsdr/app/ to connect. Building from source instead means checking out the ESP-IDF commit pinned in firmware-targets.json, then building and flashing each chip with idf.py in its own build directory.
Which license is ESP-SDR released under?
The repository is licensed under GPL-3.0, so firmware derived from it carries the same license obligations. The repository publishes no GitHub releases, and the last push was on 2026-10-17.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/espargos-esp-sdr)Was this useful?