An RTL-SDR receiver for the Sony PSP. The PSP connects over WiFi to an
rtl_tcp server on a PC, streams raw 8-bit I/Q, and renders a live
spectrum + waterfall on the 480x272 screen. It also includes a mono
WFM (broadcast FM) demodulator with audio out.
Tested in PPSSPP and on a PSP-2000 (ARK-5, 6.61, WPA2).
RTL-SDR ──USB──▶ PC (rtl_tcp) ──WiFi/TCP──▶ PSP
├─ FFT ──▶ spectrum + waterfall
└─ WFM demod ──▶ 44.1 kHz audio
| Path | What |
|---|---|
psp/ |
PSP homebrew client (C, pspdev SDK) → psp/EBOOT.PBP |
psp/src/net.c |
WiFi (sceNetApctl) bring-up and a small TCP client |
psp/src/rtltcp.c |
rtl_tcp protocol: header, tuning commands, I/Q stream |
psp/src/fft.c |
Float radix-2 complex FFT + Hann window |
psp/src/viewer.c |
Spectrum/waterfall rendering (oslib) and input |
psp/src/wfm.c |
FM discriminator, decimation, de-emphasis, resampler |
psp/src/demod.c |
Demodulator thread fed by an I/Q ring buffer |
psp/src/audio.c |
44.1 kHz mono output thread (stereo duplexed) |
psp/src/ui.c |
Settings screen and status messages |
tools/ |
Build/install helpers |
The PSP client is built with the pspdev/pspdev Docker image:
tools/pspbuild.sh # -> psp/EBOOT.PBP
tools/pspbuild.sh cleanInstall to a real PSP (USB mode) or PPSSPP's memstick:
tools/install-psp.shStart rtl_tcp on the PC (bind to all interfaces so the PSP can reach it):
rtl_tcp -a 0.0.0.0 -p 1234 -f 102500000 -s 250000The PC firewall must allow inbound TCP 1234.
Copy EBOOT.PBP to ms0:/PSP/GAME/RTLPSP/ and launch it. On first run the
settings screen asks for the server address; settings persist to
ms0:/RTLPSP/config.txt.
| Screen | Input | Action |
|---|---|---|
| Viewer | ← / → | Tune ±100 kHz |
| Viewer | L / R | Tune ±1 MHz |
| Viewer | X | Toggle gain auto/manual |
| Viewer | Triangle | Toggle WFM audio |
| Viewer | Start | Pause / resume |
| Viewer | Select / Circle | Settings |
| Settings | ↑ / ↓ | Move field |
| Settings | ← / → , L / R | Change value |
| Settings | X | Edit text / toggle |
| Settings | Start | Save and connect |
| Any | HOME | Quit |
- Tune — the client opens TCP 1234, reads the 12-byte
RTL0header, and sendsset_frequency,set_sample_rateand gain commands. - Stream — rtl_tcp sends interleaved unsigned 8-bit I/Q. The client drains the socket into a ring and consumes the newest data.
- Spectrum/waterfall — a 1024-point FFT of a Hann-windowed frame gives 1024 bins, FFT-shifted so the tuned frequency is centred. Magnitudes are mapped to a 256-entry palette; the waterfall is a scrolling 5650 image.
- WFM audio — I/Q is decimated to ~256 kHz, run through a polar discriminator, low-passed by three cascaded boxcars (rejects the 19 kHz pilot and 38 kHz stereo subcarrier), de-emphasised (75 µs), and resampled to 44.1 kHz. The demodulator runs on its own thread so it never starves audio scheduling.
Working
- Live spectrum + waterfall from rtl_tcp in PPSSPP and on real hardware.
- Mono WFM audio.
- Settings persisted on the memory stick; live tuning while streaming.
Limitations
- Bandwidth. The PSP's 802.11b link caps throughput at roughly 4 Mbit/s, so the sample rate must stay around 250 kSps. At 1.024 MSps rtl_tcp cannot keep up and drops samples. 250 kSps is enough for WFM but gives only a 250 kHz-wide waterfall.
- Weak signals. Auto gain can settle low; use manual gain for weak stations.
- Mono WFM only — no stereo decoding or RDS.
ms0:/maps to the memory stick root. Under PPSSPP that is~/.config/ppsspp/(soms0:/RTLPSP/config.txtis~/.config/ppsspp/RTLPSP/config.txt, not underPSP/).- Homebrew runs at 222 MHz unless it calls
scePowerSetClockFrequency. - On the PSP, doubles are software-emulated and FPU divides are slow — keep the hot DSP path in single precision and avoid divides/modulo.
- The demodulator's I/Q decimation and the audio boxcar cascade are what keep the 38 kHz stereo subcarrier from aliasing into the audio band; a single boxcar is not enough.
- rtl_tcp serves one client at a time, and PPSSPP and a real PSP cannot share it simultaneously.
- PPSSPP shares one emulated CPU across all threads, so a heavy DSP loop shows up as a low emulated frame rate and can overflow the audio queue.
MIT