esp-sdr README

The project's README from github.com/ESPARGOS/esp-sdr. As one markdown file: README.md.

ESP-SDR firmware

ESPARGOS logo

ESP-SDR turns the ESP32's built-in 2.4 GHz Wi-Fi radio into a software-defined radio (SDR). It lets you capture the radio signal itself and process it in software, so you can view the spectrum and study signals beyond ordinary Wi-Fi packets. No separate SDR hardware is needed. The ESP32-C5 also supports reception in the 5 GHz band.

With the help of LLMs, we discovered an undocumented debug path that bypasses the chip's fixed-function Wi-Fi modem. This gives software access to raw radio samples, called I/Q samples, from the built-in receiver. ESP-SDR captures short bursts of these samples and sends them to your computer over USB or UART for analysis. It can also compute spectra on-device, including continuous RF capture on selected chips.


ESP32 radio architecture: an undocumented debug path connects the ADC/DAC to the CPU, bypassing the fixed-function Wi-Fi modem.

The diagram shows the hardware's receive and transmit paths; this firmware currently implements reception only.

Project overview · Browser SDR viewer · Browser firmware installer

Parts of the firmware code are AI-generated. While we have a very good understanding of how the IQ sampling functionality works on the ESP32-C61 chip (used in our ESPARGOS One array), making IQ sampling work on the whole range of ESP32 family chips would have been too much work without LLM support.

Chip support

Chip Status Native USB UART0 TX / RX Minimum flash Special modes / firmware
ESP32 ✅ — GPIO1 / GPIO3 2 MB —
ESP32-C2 ✅ (26 MHz crystal) — GPIO20 / GPIO19 2 MB —
ESP32-C3 ✅ Serial/JTAG GPIO21 / GPIO20 2 MB —
ESP32-C5 ✅ Serial/JTAG GPIO11 / GPIO12 2 MB —
ESP32-C6 ✅ Serial/JTAG GPIO16 / GPIO17 2 MB —
ESP32-C61 ✅ Serial/JTAG GPIO11 / GPIO10 2 MB —
ESP32-H2 ✅ Serial/JTAG GPIO24 / GPIO23 2 MB —
ESP32-H21 🚧 — — — —
ESP32-H4 🚧 — — — —
ESP32-P4 ❌ — — — —
ESP32-S2 ✅ USB-OTG CDC GPIO43 / GPIO44 4 MB —
ESP32-S3 ✅ Serial/JTAG GPIO43 / GPIO44 2 MB Continuous decimated I/Q over USB (15.625–250 kSa/s)
ESP32-S31 ✅ Serial/JTAG GPIO58 / GPIO59 2 MB High Speed USB / Ethernet streaming at up to 40 MSa/s (experimental)

✅ Supported · 🚧 Not yet supported · ❌ Unsupported (no integrated radio).

USB, UART, and flash requirements above refer to the standard firmware; see each special firmware variant for its board requirements.

Special Chip- / Board-Specific Modes and Firmware

ESP32-S31: Ethernet / high-speed USB streaming

Experimental: The S31 streaming mode is under development. Signal quality, including the remaining DC peak, still needs improvement.

The separate esp32s31-stream firmware targets the ESP32-S31 Function-CoreBoard with Gigabit Ethernet and native high-speed USB. It streams receive-only I/Q to SoapyESPSDR and includes an on-device web page for receiver controls and status, with rates up to 20 MSa/s over USB and 40 MSa/s over Ethernet using 8-bit I plus 8-bit Q. The ordinary esp32s31 firmware provides serial burst/FFT capture for ESP-WebSDR. See streaming build, architecture, and protocol.

Gqrx displaying an LTE signal at 2.63 GHz, continuously sampled at 40 MSa/s over Ethernet with an ESP32-S31 and SoapyESPSDR.

ESP32-S3: Continuous I/Q streaming over USB

The standard esp32s3 firmware includes an IQS mode for continuous, decimated I/Q streaming over native USB Serial/JTAG. The second core filters and decimates the 16 MSa/s capture stream by powers of two from 64 to 1024, giving output rates from 250 down to 15.625 kSa/s, with 4, 8 or 16 bits per I and Q component. This mode requires native USB; UART is not supported.

Use esp-sdr-bridge to connect the receiver to SDR++, SDR#, Gqrx or GNU Radio through SpyServer / rtl_tcp. For custom clients, IQS 0 64 8 6 starts a 250 kSa/s stream with 8-bit I and 8-bit Q until the host sends a byte to stop it. Frames include sample indices, gap flags and CRC32 checksums; host stalls or processing overruns can cause sample loss. See the continuous I/Q protocol for command options, sample formats, filtering and frequency-offset tuning.

On-chip spectrum streaming

The firmware can compute FFTs on the device and send compact spectra instead of raw I/Q. The viewer queries each device's supported rates, FFT sizes and transport before offering this mode.

Chip Continuous RF capture with on-chip FFT Snapshot FFT
ESP32 — 256–2048 bins; 16/40/80 MS/s; UART
ESP32-C2 — 256–2048 bins; 80/40/16 MS/s; UART
ESP32-C3 — 256–2048 bins; 80 MS/s; USB or UART
ESP32-C5 — 256–2048 bins; 4/8/10/20/40/80 MS/s
ESP32-C6 256 bins; 80 MS/s; native USB 512–2048 bins over USB; 256–2048 over UART
ESP32-H2 — 256–2048 bins; 6.4/10.667/16/32 MS/s; USB or UART
ESP32-C61 256 bins; 4/8/10/20/40/80 MS/s; native USB 512–2048 bins over USB; 256–2048 over UART
ESP32-S2 — 256–2048 bins; 16/40/80 MS/s; USB or UART
ESP32-S3 256–2048 bins; 16/40/80 MS/s; native USB —
ESP32-S31 256–2048 bins; 4/8/10/20/40/80 MS/s; native USB Same FFT sizes and rates over UART

Continuous capture keeps the RF writer running, but the CPU analyzes only selected FFT windows. It does not deliver every sample or guarantee that every short RF event will be visible. Snapshot FFT stops reception between captures; the viewer labels these gaps explicitly. Raw I/Q capture remains available separately.

The original S3 Turbo Mode was developed by Zoltan Doczi from Z2Labs. The shared implementation extends it with C6/C61 bank rotation, S31 dual-core SIMD processing with continuous bank rotation, and portable snapshot FFTs. See spectrum protocol and hardware validation for the wire format, limitations and test results. The S3 ring diagnostic host tool is tools/s3_ring.py.

GPIO outputs can be controlled from the browser’s GPIO section or the serial protocol. Firmware reports available pins; each supports high impedance (Z), low (0), or high (1). See GPIO controls.

Commands and transport

Connect over native USB or a 3.3 V USB-to-UART adapter with crossed TX/RX and common ground, using the pins above. Both interfaces carry the same request/response protocol: send newline-terminated ASCII commands and read text replies. Capture replies also include a binary I/Q payload.

Query INFO and CAPS to identify the firmware and supported features. VERSION? reports the Git revision and UTC build date/time; see firmware version reporting. LIMITS? reports receive-control limits, RANGE? reports the tuning range, and TRANSPORT? identifies the active interface. Configure reception with FREQ <MHz>, BANDWIDTH <MHz> and GAIN commands.

Request a snapshot with CAP16 <samples> <rate-index> for signed 8-bit I/Q or CAP20 <samples> <rate-index> for packed signed 10-bit I/Q. The reply is DATA <samples> <crc32-hex> <capture-microseconds>, followed by exactly ceil(samples × bits-per-component × 2 / 8) binary bytes. Verify the payload CRC32 before using the samples. Rate indices 0–6 select 80, 40, 20, 10, 8, 4 or 16 MS/s respectively; use only rates advertised by LIMITS?.

Finish reading each reply before sending another command. Failures return ERR <reason>. SYNC <nonce> echoes the nonce to let clients resynchronize after an incomplete transfer. One client controls the radio at a time; RELEASE or five seconds of idle time releases it, while other clients receive ERR busy.

Build and flash

firmware-targets.json lists the supported firmware variants and pins their ESP-IDF commits, including the preview SDK for S31. Check out the matching SDK, initialize its submodules, run install.sh <target>, and source export.sh.

Use a separate build directory and configuration for each chip:

idf.py -B build-s3 -DIDF_TARGET=esp32s3 \
  -DSDKCONFIG=sdkconfig.s3 \
  -DSDKCONFIG_DEFAULTS=sdkconfig.defaults.esp32s3 build
idf.py -B build-s3 -p /dev/ttyACM0 flash

Substitute the target and paths for your chip. S31 also requires idf.py --preview.

The C2 firmware uses a 26 MHz crystal, as on the tested ESP8684H board. For a 40 MHz board, select CONFIG_XTAL_FREQ_40=y in menuconfig and rebuild; the packaged browser image requires 26 MHz. C2 uses UART0 at 2 Mbaud by default. With a CH340 bridge, use the viewer's Switch to 1 Mbaud warning when transfers lose bytes; baud changes are session-only. C2 provides raw IQ8/IQ10 captures, hardware/manual gain, and snapshot FFTs. Continuous capture is not advertised; approximate analog bandwidth covers 12–20 MHz. See C2 backend and validation.

The esp32h2 firmware uses the Bluetooth PHY capture engine and supports both native USB Serial/JTAG and UART0. It supports 32, 16, approximately 10.667 and 6.4 MS/s hardware sampling, plus approximately 4–11 MHz analog bandwidth control. See H2 backend and validation.

Source layout

The application component and UART configuration stay in main/. Target SDK defaults stay at the repository root for the build tools and ESP-IDF defaults lookup. The firmware uses the burst protocol over UART/native USB; the separate main/targets/esp32s31/streaming/ application implements the receive-only Ethernet and vendor USB streaming firmware.

Run python3 -m unittest discover -s tests for host checks. Build every firmware variant with tools/build_firmware.py and its pinned SDK before distributing a change; the CI matrix does this automatically. Preserve the target SRAM guards and gain-table linker wrappers when moving or refactoring receiver code.

Receive controls

Hardware AGC is the default. GAIN MANUAL <index> sets manual gain; GAIN HARDWARE restores AGC. LIMITS? reports available gain indices, bandwidths, sample rates and bit depths. BANDWIDTH <MHz> sets approximate analog bandwidth; zero selects the widest setting.

All supported burst targets accept tuning attempts from 100–6000 MHz in 1 MHz steps. The viewer shows an informational warning outside 2400–2483.5 MHz, with 5150–5895 MHz also treated as the supported 5 GHz Wi-Fi band on C5. The warning never blocks tuning. These are software attempt limits, not a guaranteed reception range. ESP32, S2, S3, C2, C3 and C6 automatically use the experimental 5/6 LO mode from 1842–2209 MHz, extending reception down to about 1.84 GHz on the tested boards. No extra command or browser setting is needed. An equivalent divider mode is not yet verified on C5, C61, H2 or S31. C61 and S31 instead recover failed low-band PLL calibration automatically, with reception verified down to 2.18 GHz and 2.15 GHz, respectively, on the tested boards. This uses hardware capacitor calibration and also applies to S31 streaming; the achievable range depends on the individual chip.

Captures have gaps; nominal sample rates exceed sustained serial throughput. Gain and power are uncalibrated. Extended tuning does not guarantee PLL lock or reception; the viewer uses the ISM-band warning described above.

See receive-control details.

Contributors

Florian Euchner
Florian Euchner
Zoltan Doczi
Zoltan Doczi
14sea
14sea

Special thanks to h0m3us3r for providing eSpDR, whose 5/6 LO investigation informed our lower-frequency tuning implementation.

License

ESP-SDR is licensed under the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version (GPL-3.0-or-later). See LICENSE for the full terms. It is provided without any warranty, including implied warranties of merchantability or fitness for a particular purpose.

We chose the GPL because we want improvements to ESP-SDR to make their way back to the community. When you distribute modified versions, the GPL requires you to make the corresponding source available to recipients under the GPL, so they can study, share, and build on those improvements. We encourage you to contribute changes upstream, but the GPL does not require upstream submissions or publication of private modifications. See the GNU GPL FAQ.

The discovery of the capture mechanism itself is not protected by copyright: copyright covers the code and other copyrightable expression, not the underlying facts, ideas, or methods. You are free to independently implement the mechanism in your own projects under a license of your choice.

Third-party components retain their own licenses and copyright notices, including the Apache-2.0 ESP-IDF compatibility code in platform/esp32s2/esp_usb_cdc_rom_console/, the pinned ESP-DSP component, and the derived FFT kernels in main/targets/esp32s3/s3_fft_rnd.S and main/targets/esp32s31/burst/s31_fft_rnd.S.

esp-sdr (ESPARGOS/esp-sdr)

Searching Database…

这是什么?ESP-SDR 是一套固件,它利用一条未写入文档的调试路径,直接从内置 Wi-Fi 接收器中取出原始 I/Q 采样,把 ESP32 Wi-Fi 芯片变成低占空比的软件定义无线电,让你无需任何额外的 SDR 硬件就能查看频谱、研究普通 Wi-Fi 数据包之外的信号。
这是刷进芯片的固件,还是桌面应用?它是你用 ESP-IDF 构建并刷入 ESP32 开发板的固件;另有一个配套的基于浏览器的 SDR 查看器和固件安装器在你的电脑上运行,用于配置设备和显示采集结果。
怎么构建和烧录?在 firmware-targets.json 中找到为你的芯片固定的 ESP-IDF SDK 提交,检出该 SDK,初始化其子模块,运行 install.sh 并 source export.sh,然后针对每个目标从单独的构建目录用 idf.py 构建(S31 需要 idf.py --preview)。
它实际能在哪些 ESP32 芯片上工作?支持 ESP32、C3、C5、C6、C61、S2、S3 和 S31;C2、H2、H21 和 H4 目前不受支持,P4 则永远无法工作,因为它没有集成射频单元。
采集结果有多可靠?采集存在缺口,因为标称的采样率超出了串行链路能承受的范围;增益和功率读数未经校准;在经过验证的 2400-2483.5 MHz(C5 上还有 5 GHz)频段之外调谐只是未经测试的软件尝试,无法保证 PLL 锁定。
GPL 许可证对使用它意味着什么?ESP-SDR 采用 GPL-3.0-or-later 许可:如果你分发修改后的固件,必须以 GPL 提供对应的源代码,但不要求向上游贡献;底层的采集方法本身不受版权保护,可以自由重新实现。
实际上怎么向无线电发送命令并获取采样?通过原生 USB 或 3.3V 的 USB 转 UART 适配器连接,发送以换行符结尾的 ASCII 命令,如 FREQ、BANDWIDTH、GAIN、CAP16 或 CAP20,并用 CRC32 校验每条回复的二进制 I/Q 负载。
它能调谐到什么频率范围?所有受支持的芯片都可以尝试以 1 MHz 步进在 100-6000 MHz 内调谐,但只有 2400-2483.5 MHz 的 Wi-Fi 频段(C5 上还有 5150-5895 MHz)经过硬件验证;更宽的调谐可能无法实现 PLL 锁定。
它能在设备上直接计算频谱,而不是传输原始采样吗?可以,一些芯片支持片上 FFT:有的通过原生 USB 持续输出频谱,有的则计算 256-2048 个频点的快照 FFT,以牺牲连续接收换取更大的频谱。
既然 ESP32 没有公开文档记载的 SDR 模式,这个项目为什么能存在?作者在 LLM 的帮助下发现了一条未写入文档的调试路径,可以绕过 ESP32 功能固定的 Wi-Fi 调制解调器,暴露出原始 I/Q 采样,让廉价的 Wi-Fi 芯片无需额外硬件就能充当基础的 SDR。
Creator
ESPARGOS
Size
4.8 MB
Stars
1K
Updated
CommitOct 17
Age
21d
Commits · 90 Days