A custom FM-RDS transmitter for the Raspberry Pi using hardware PWM/DMA, based on PiFmRds. Built to suit the needs of BotWave.
Caution
This software directly accesses hardware DMA and clock registers. Running it incorrectly can crash your Pi, corrupt filesystems, or damage hardware. You have been warned. We accept no liability.
Warning
Transmitting over FM may be illegal in your country. Always consult local regulations before use.
bw_custom generates a complete FM multiplex signal and transmits it on GPIO4 (pin 7) using the Pi's internal clock generator. The signal includes:
- FM modulation at any frequency between 76–108 MHz
- RDS (Radio Data System) with PS name, Radio Text, PI code, and real-time clock groups (CT)
- Stereo audio (L+R / L-R multiplexing with 38 kHz subcarrier and 19 kHz pilot tone)
- Mono audio fallback for single-channel sources
The Makefile auto-detects your Pi model and compiles with the correct flags and memory addresses.
| Model | Architecture | PLL Freq |
|---|---|---|
| Pi 1 / Zero (v1) | ARMv6 | 500 MHz |
| Pi 2 / 3 / Zero 2 W | ARMv7 / ARMv8 | 500 MHz |
| Pi 4 | ARMv8 (aarch64) | 750 MHz |
sudo apt install libsndfile1-dev build-essential git -y
git clone https://github.com/dpipstudio/bw_custom.git
cd bw_custom/src/
makeThis produces the bw_custom executable.
Usage: bw_custom [options]
-freq <MHz> Carrier frequency, 76.0–108.0 MHz [REQUIRED]
-audio <file> Audio input: WAV file path, or "-" for stdin [REQUIRED]
-pi <hex> RDS Program Identifier code (default: 1234)
-ps <text> RDS station name, max 8 chars (default: BWC)
-rt <text> RDS Radio Text, max 64 chars
-loop Loop the audio file when it ends
-raw Read raw 16-bit signed PCM from stdin instead of WAV
-rate <Hz> Sample rate for raw PCM input (default: 44100, range: 8000–192000)
-channels <1|2> Channel count for raw PCM input (default: 2)
-h Print help
-v Print version
Transmit a WAV file on 107.9 MHz:
sudo ./bw_custom -freq 107.9 -audio music.wav -ps "MY FM" -rt "Hello from Pi!"Loop a WAV file indefinitely:
sudo ./bw_custom -freq 100.1 -audio music.wav -loopStream raw PCM audio from stdin (e.g. piped from ffmpeg):
ffmpeg -i input.mp3 -f s16le -ar 44100 -ac 2 - | sudo ./bw_custom -freq 103.5 -audio - -raw -rate 44100 -channels 2Mono raw PCM stream:
arecord -f S16_LE -r 22050 -c 1 | sudo ./bw_custom -freq 98.0 -audio - -raw -rate 22050 -channels 1| Feature | PiFmRds | bw_custom |
|---|---|---|
| WAV file input | ✅ | ✅ |
| RDS PS / RT / PI | ✅ | ✅ |
| RDS CT (clock time) groups | ✅ | ✅ |
| Stereo audio | ✅ | ✅ |
Raw PCM stdin (-raw) |
❌ | ✅ |
Configurable sample rate (-rate) |
❌ | ✅ |
Configurable channel count (-channels) |
❌ | ✅ |
Clock error correction (-ppm) |
✅ | ❌ |
Runtime PS/RT control via named pipe (-ctl) |
✅ | ❌ |
Traffic Announcement flag (TA ON/OFF) |
✅ | ❌ |
The signal comes out on GPIO4 (physical pin 7). Connect a short wire as an antenna, or, preferably, run a shielded cable directly to a nearby receiver. Do not connect a proper antenna, as this will radiate far beyond legal limits.
GPL v3. See LICENSE.
Based on PiFmRds © Christophe Jacquet, F8FTK.
bw_custom additions © 2025 douxx@douxx.tech.