Building a WSPR Beacon with a Game Boy Advance
Introduction
A while ago, a friend asked me if I could help with an old Game Boy she had rediscovered at her parents place. As usual, I could not pass up a broken electronic device without trying to fix it, so I went down the rabbit hole. The repair sparked some interest, and before I had even finished repairing her Game Boy, I had already won an eBay auction for ten broken Game Boy Advances.
That turned into a few weeks of messing around with this old hardware platform, and during my research, I found agb, a Rust library for writing software for the Game Boy Advance. The GBA link port also exposes a few GPIO pins that can be controlled from software.
Eventually, I ended up with the question: what else can I do with it? The Game Boy Printer already existed, so I needed to find something new that would be useful to me. Combining a programmable handheld, some GPIO, and my interest in amateur radio led me to the conclusion that I wanted to build a WSPR beacon powered by a Game Boy Advance.
This project is a proof of concept. I wanted to see whether the GBA could handle the WSPR encoding, timing, and control of an external frequency synthesizer.
Hardware
The basic setup is straightforward. The GBA does all computations related to WSPR and controls a Si5351 clock generator through GPIO pins on the link port. The Si5351 is already used in many homebrew WSPR beacons and can generate the closely spaced tones required by WSPR.
Hardware and signal flow of the GBA-powered WSPR beacon.
I initially experimented with generating the tones through the GBA sound hardware and feeding the audio into a radio. However, I ran into several hardware limitations and could not get a usable result. Someone more familiar with the Game Boy’s sound interface might be able to make that approach work, but using the Si5351 was much simpler.
Link Port Adapter
I needed a female version of the GBA link connector and did not want to sacrifice an original link cable for this project. Instead, I modified this 3D-printable connector housing so it could accept common jumper wires. This allowed me to start prototyping without waiting for a custom PCB or a special connector.

The 3D-printed link-port adapter connected to the Si5351 module.
I used the following GBA link-port contacts:
| GBA link-port pin | Signal | Si5351 connection |
|---|---|---|
| Pin 2 | SO (Serial Out) | SCL |
| Pin 3 | SI (Serial In) | SDA |
| Pin 4 | VCC (3.3 V) | VCC |
| Pin 6 | GND | GND |
Time Reference
Precise timing is crucial for WSPR. Transmitters and receivers do not establish a connection or exchange timing information. Instead, they operate independently using synchronized UTC time slots. WSPR devices therefore commonly use GPS receivers as their time reference.
Adding GPS would have been possible, but I wanted to test an approach using an RTC chip, since these are available in some GBA cartridges. Games such as Pokemon used cartridge-mounted RTCs for timed events because the GBA itself has no real-time clock. For this project, I used a rewritable Chisflash v1.1 GBA flash cartridge containing a Seiko S-3511 RTC.
The RTC is connected through the cartridge GPIO registers, but it turned out not to be as reliable as I had hoped. It drifted quite a bit over time, which affected the timing of the WSPR transmissions. So I had to set the RTC once a day during my testing. I did this using GBA_RTCRead.
Amplifier and Filter
The Si5351 output power is quite low, so I added a 2 W amplifier kit from AliExpress. A simple homebrew low-pass filter at the output suppresses harmonics before the signal reaches the antenna.
Software
Writing software for the GBA was easier than I first expected. With agb, you get many of the modern conveniences of Rust, and the mGBA emulator makes testing code convenient as well. Of course, the platform still has strict limitations. The GBA uses an ARM7TDMI running at approximately 16.8 MHz and does not offer the kind of UI framework you would expect on a modern system. Still, getting the first Hello World running with the agb template was straightforward.
The software consists of five main parts:
- WSPR message encoding
- Software I2C and Si5351 control
- Frequency compensation
- RTC access and transmission timing
- User interface
Software I2C and Si5351 Control
The first important question was whether the GBA could communicate with the Si5351 at all. Without that, there would have been no point in continuing.
The Si5351 uses I2C, but neither the GBA link port nor the GBA itself provides a suitable I2C controller. I therefore implemented the protocol in software by bit-banging the link-port GPIO pins. Since I2C is well documented, I offloaded most of this task to an LLM and then tested the result on the hardware. I used the same approach for the initial Si5351 driver, with the datasheet as the reference. The generated prototype required some iteration, but it was enough to establish reliable communication with the module.
Frequency Compensation
The crystal frequency of the Si5351 is nominally 25 MHz, although some modules use a 27 MHz crystal. In practice, all Si5351 modules are slightly off, with some showing a much larger error than others. As a result, the generated base frequency will most likely also be off.
To compensate for this, the tool allows the base frequency to be adjusted in 1 kHz steps. I used a second radio to monitor the signal and changed the offset until the Si5351 was transmitting on the correct frequency. A better approach would be to calibrate the module against a known accurate reference and store the correction factor.
WSPR Encoding
There is a lot of information online about implementing WSPR, including The WSPR Coding Process, FSKview’s WSPR notes, and Dissecting wsprd. I did not want to reinvent the wheel, so I used the existing wspr crate to encode the messages.
A WSPR transmission contains 162 symbols, with each symbol selecting one of four tones. The useful part for this project is that the message only needs to be encoded once before transmission. Encoding therefore does not become a bottleneck on the GBA’s relatively slow CPU while the signal is being transmitted.
RTC and Transmission Timing
WSPR uses fixed two-minute UTC time slots. A transmission begins at second 00 of an even-numbered minute and lasts approximately 110.6 seconds. Receivers know when to capture and decode this interval, so no connection setup or handshake is required. Both sides only need to share an accurate time reference.
The program reads the Seiko S-3511 RTC through the cartridge GPIO registers and waits for the next valid transmission slot. I once again used an LLM to produce the initial RTC implementation and verified it against the hardware.
During a transmission, the program converts each of the 162 WSPR symbols into one of four frequencies spaced approximately 1.46 Hz apart. For each symbol, it updates the Si5351 multisynth divider while keeping the PLL fixed at 900 MHz.
Each tone is transmitted for 41 GBA VBlank periods, or approximately 0.683 seconds. Using VBlank provides a convenient hardware-based timing source without requiring a separate timer implementation.
User Interface
I am not a UI designer and never will be one. In fact, there are tools I have never published on GitHub because their interfaces are so bad. The fact that agb is optimized for games did not make this part any easier.
I ended up with a crude but functional text-based user interface. It uses agb’s tiled background and font renderer to display a handful of screens: a main status page, a settings page, a tuning page, and transmission/waiting status views.
The main page shows the selected band, frequency, callsign, grid locator, transmit power, and the status of the Si5351 and RTC. From there, the GBA controls open the settings page, change bands, adjust the frequency in 100 Hz steps, enter tuning mode, or start a WSPR transmission. The settings page allows the callsign, grid locator, and power level to be edited. During operation, separate status views show the RTC wait state, active transmission, and countdown to the next two-minute slot.

The main, tuning, transmission, and settings screens.
It is not a sophisticated interface, but it makes all important configuration and diagnostic information available directly on the GBA.
Testing
After several unsuccessful attempts with a simple wire hanging out of my apartment window, I decided it was finally time to go outside and test the cheap vertical antenna I had bought from AliExpress the previous year.
I set up the antenna in an open area in a nearby forest and tuned it for the 20 m band using my NanoVNA. After a few minutes, the first reception reports appeared.

The GBA-powered WSPR beacon connected to a vertical antenna.

The complete GBA-WSPR beacon setup in the field.
Overall, the beacon received 342 reports from 91 unique reporting stations. The furthest report came from ZL2P in grid RE79tb, at a distance of 18,527 km (11,512 mi).

Reception reports from the GBA-powered WSPR beacon on the 20 m band.
Conclusion
The experiment answered the main question: a Game Boy Advance can encode a WSPR message, maintain the transmission timing, and control a Si5351 well enough to produce a signal that can be received and decoded.
There are several obvious improvements. Using 2 W is much more than necessary for WSPR, especially since other operators have achieved much better results with far less transmit power. But it was the only portable amplifier I had at the time. The two Si5351 outputs could potentially be combined to increase output power without an external amplifier. The RTC was also unreliable, so replacing it with GPS or another accurate external time reference would be a major improvement.
But this was always intended as a proof of concept, and it proved the concept. I do not plan to put more work into it, at least for now.