10 Milliwatt Si5351A WSPR Beacon


It’s fun to experiment with propagation by seeing how far you can get a signal to travel with a transmitter in the milliwatt range (this is known colloquially as QRPp). For quite a while, this esoteric pursuit was done with flea-powered CW signals, until the invention of the WSPR modulation scheme by Nobel laureate Joe Taylor, K1JT. WSPR is now a very popular method with hams around the world for HF propagation experiments; aided greatly by the WSPRnet online database, which allows hams to get detailed information about where and when their signals are being heard.

Although a fair amount of computation (for a microcontroller at least) is used to encode a WSPR message, the actual modulation scheme is relatively simple 4-FSK, which means that four different symbols can be encoded by transmitting on one of four discrete equidistant frequencies (spaced approximately 1.46 Hz apart). For any method of signal generation with a decent amount of frequency resolution such as a PLL or DDS, this is easily implemented. The Etherkit Si5351A Breakout Board combined with the Si5351Arduino library provides a low-cost, wide range PLL with excellent frequency resolution for a task such as this.

The tricky part is timing the transmissions correctly. WSPR requires transmissions that start on the first second of an even minute. Any transmission that deviates more than about one second either too soon or too late will not be decoded, so it is most important to be sure that you have an accurate clock when attempting to transmit with WSPR. Traditionally, this has been accomplished by using a PC synchronized to an internet time server to act as the controller for the WSPR transmitter (and often it is transmitted as AFSK via USB mode on a radio). As mentioned above, the WSPR modulation scheme is very easily realized in microcontroller code, but timing becomes a bit more of a challenge. The on-board oscillator for a microcontroller simply does not have the ability to keep accurate time for very long, even if it is initially set accurately. An external RTC module is slightly better, but will still drift too far out of spec for WSPR after a short time. This has typically left a GPS module as the only viable solution for a microcontroller-based WSPR transmitter. While this is the ideal approach, plenty of experimenters don’t have GPS modules sitting around ready to be plugged into their Arduinos.

However, by using the Arduino Time library and a internet connected PC, a simple WSPR transmitter can be built that does not require a GPS module for timing nor a separate “big rig” radio with upper sideband capability. The Time library can use various synchronization sources, including grabbing a Unix time string over the Arduino’s USB-UART bridge. First, the PC must be accurately synchronized to a NTP time source. If you are using a Linux or Unix based OS, there are a variety of different methods for doing this, so search for documentation for your particular OS distribution. For a Windows PC, you’ll need to use a third-party program such as Dimension 4. In all cases, do not rely on the settings in your operating system’s time control panel for internet time. Typically, these services do not maintain good clock discipline and it’s not uncommon for your PC clock to drift far enough out of sync for your WSPR frames to be invalid after a few weeks.

The sending of the Unix time string to the Arduino can be handled by a variety of different programming and scripting languages. Python is the preferred scripting language for such tasks here at Etherkit, so we’ll provide a simple example Python script below, but the same thing could be accomplished in many different ways. The firmware in the Arduino will send an ASCII bell character to the host PC when it needs to get a Unix timestamp for synchronization, so the program simply needs to open the serial port of the Arduino’s USB-UART bridge, wait for an incoming ASCII bell, and then send back a properly formatted Unix timestamp. When the Arduino is properly synchronized, it will light up the LED on pin 13 to let you know. Typically you just need to plug the Arduino into your PC, execute the time synchronization script on your PC (python ntpserial.py), and then the pin 13 LED should light up within a few seconds to let you know that the beacon transmitter is ready to go.

Before loading the firmware onto the Arduino, be sure to change the callsign (6 characters or fewer) and locator (exactly 4 characters) variables to the proper values for your station (and perhaps the dBm if you use an amplifier). Set the frequency to any one that you like within the tuning range of the Si5351 by setting the freq variable. You’ll also want to be sure to have properly frequency calibrated your Si5351 and use the correction factor in the CORRECTION define near the top of the firmware file. The Etherkit JTEncode library takes care of generating the correct WSPR symbols for you, so there’s no need to have the PC use the wsprcode application for this. The if block at the end of the loop() function determines when the beacon will transmit. It is set to transmit every 10th minute of the hour, but this can be tweaked by changing the modulo math in that if statement.

Since the Si5351 output is a square wave, make sure you properly low-pass filter the output before connecting it to an antenna for transmission (you can find tables for low-pass filter generation in a variety of places, including the ARRL Handbook). You may also wish to connect a current-limited LED to pin 12, as this pin will go high to indicate when the beacon is transmitting.

While 10 milliwatts is an awfully sparse amount of power, due to the robust WSPR scheme, you can get spots with that power level and an average HF antenna. As a demonstration at the NT7S shack, we set the beacon to transmit on 20 meters and let it run for 24 hours. Conditions weren’t great, but we did manage to get spotted, especially during the local twilight hours. The antenna here is a basic double (ZS6BKW) up about 12 meters or so.


As you can see, 10 milliwatts on 20 meters WSPR was about to reach out to an area about 3000 km distance, which isn’t bad, all things considered.


With some amplification to half a watt or so, it would be very easy to get spots, but there’s fun in seeing how far you can send a flea-powered signal and still have it be perfectly decoded (watch for our upcoming 500 mW linear amplifier, which would be a perfect accompaniment to this project). There’s plenty of areas where this project could be expanded, so have fun hacking this simple example into something even more useful.

Block Diagram

Bill of Materials

Item Quantity
Arduino Uno (can substitute other variants) 1
Etherkit Si5351A Breakout Board 1
Low Pass Filter 1
Amplifer (optional) 1
LED (optional) 1
470 ohm 0.25 W resistor (optional) 1
RF connectors of choice


A transmit LED indicator can be wired with a 470 ohm current limiting resistor in series by connecting to pin 12.

Terminal Arduino Uno Pin
Si5351 SCL A5
Si5351 SDA A4
Optional LED/resistor 12/GND
Si5351 5V 5V
Si5351 GND GND


Simply load the sketch onto your Arduino Uno, connect the power and I2C lines from the Uno to the Si5351A Breakout Board and then connect an appropriate low-pass filter to the output of the Si5351A Breakout Board CLK0 (or the output of the amplifier, if you are using one). Connect the output of the low-pass filter to a dummy load, then provide power to the Uno, Si5351A Breakout Board, and amplifier (if applicable).

Connect the Arduino USB to your PC and then run the provided Python time synchronization script:
python ntpserial.py
Once the Arduino is able to get a valid timestamp from the PC, the pin 13 LED will light and your beacon will be in transmission mode.

Use your favorite WSPR program and a PC-connected receiver to monitor your transmission in order to ensure that your setup is working correctly. Once you are satisfied that is the case, connect the output of the low-pass filter to an antenna in order to transmit your WSPR transmitter on the air. Don’t forget to change your callsign and the grid locator in the Arduino sketch before you put it on the air.

Extending the Transmitter

With only about 10 to 20 mW of output power, it will be tough to hear this transmitter barefoot, so some sort of amplifier would be very useful to bring the output level to a point where you can reasonably expect to be heard. In the near future, we intend to publish an example design for a linear amplifier that will bring the output power up to 500 mW, and will update this post with the link to it when it is ready.

If you have a GPS module with a serial UART available, you can bypass the PC connection entirely and have the Time library consume time data from the GPS. See the TimeGPS example sketch provided with the Arduino Time library for an example of how to do this.

Since this project uses a connection to an internet-connected PC, there’s no reason why it could not be used in an Internet of Things fashion and be controlled via LAN or over the Internet. This would give you the ability to be a remote control operator, so that you can be away from the transmitter and still maintain control over it.

Arduino Sketch and Python Script

Required Libraries

All of the required libraries are available through the Library Manager in recent versions of the Arduino IDE. This is the preferred method for obtaining the libraries, although the Si5351Arduino and JTEncode libraries can be manually installed by downloading ZIP files from the links below.



Si5351Arduino Library on GitHub
JTEncode Library on GitHub
Si5351_WSPR.ino sketch on Gist

You may also like...

18 Responses

  1. Amogh says:

    Hi Jason, very interesting and lightweight bare bones project. I was wondering if we could take an 8 clock output SI5351 and turn it into a 8 band WSPR beacon ? I am handicapped by the coding part of this 🙁

    Great stuff !


    • NT7S says:

      Thanks Amogh!

      Theoretically one could do that, but there is a limitation at the CLK6 and CLK7 outputs of the B or C variants of the Si5351 can only output an integer divisor of the PLL, so that would probably make 8 different ham band outputs at the same time to be impossible. However, 6 simultaneous outputs could be done. My Arduino library doesn’t currently have support for the 8-output variants, but I am working on developing that.


  2. Hello Jason,

    I am trying to use your code Si5351JTDemo.ino. I have wired everything including SI5351and uploaded code to my UNO clone, but when I pressed button wired to D12, nothing seems to be happening. I was trying to test basic code so that I could use it with DS3231. All libraries are in place and IDE is 6.1.12.

    Any pointers from you would help me getting stared.

    Thank you for your time,

  3. david says:

    Anyone know where I can get an update INO this one does not work

  4. NT7S says:

    Sorry about that, I neglected to update this sketch when I revamped the Si5351 library. It should work now.

  5. Brian - K9WIS says:

    this is just what I need for a balloon project Im working..I am having some issues with the python script though..It can’t find the imports so Im guessing its something I have to find and download. Python is not one my stronger languages, Im a c C++ assembler sort of guy.

    The arduino side compiles and loaded ok, but I did get a warning about a string constant being degrecated to a char * at line 120. That was the TIME_HEADER parameter ie Serial.Find function call. Any tips or advice??

    • NT7S says:

      Which imports is Python complaining about? That should help me to tell you what to install.

      As for the warning, I’ll look at making it compliant, but it shouldn’t affect the operation of the sketch at this point.


  6. john k2ox says:

    I like the fact your design uses the PC for time sync.

    6 meters in the US appears to have a few wspr listeners, but no transmitters. I decided to put a beacon on the air based on your work.

    Unfortunately, it appears that a bug limmits the upper freq to 42 MHz. There is no signal when the freq is set above 43MHz. So no output on 6 meters.

    Hoping you have a solution.

  7. john k2ox says:

    I changed ‘unsigned long freq = 10140200UL;’ to ‘long long’ and now there is output on 6 meters. Unfortunately, the wspr signal won’t decode above 49MHz. I suspect too much jitter.

  8. john k2ox says:

    On a Keysight signal analyzer I can see the problem. At 50 MHz the two center tones jitter and look like a single tone in a 1Hz rbw. I basically looks like three tones instead of four. At 10MHz all four tones are clearly distinct. I have googled and have not found any evidence of anyone actually showing a working si5351 chip generating a good 6M wspr signal. Any ideas on a better combination of dividers to get this going on six?

    • NT7S says:

      Thanks for the report John. I will definitely look into this soon, as I’d like to know whether this will actually work correctly so that I can ship it with the upcoming OpenBeacon Mini. I’ll try to remember to reply here again, but also follow my blog for updates.

  9. EA1RX says:

    Thanks NT7S for sharing the project, I have it working and it is going quite well, in my case I have built it with an arduino nano and I observe some frequency variations, I have a GPS module NEO 6M that does not have a UART port but can be connected to the arduino Could the code be modified to obtain the data directly from the GPS and make a completely independent beacon? Thank you.

    • NT7S says:

      Hello, I can’t vouch for this 100%, but I think you could do it with TinyGPS++. I’m assuming since you aren’t using UART it must be something like SPI or I2C. I think that the TinyGPS++ library can consume any data that is inherited from the Stream class, so I think the other serial methods would probably work. It’s worth looking into.


      Good luck!

  10. mikele says:

    Hello Jason ,i m Mikele 9a3xz,i would ask you for help,as first i try feld hell beacon and works without problems but when i try wspr nothing,i compiling ino file and no problem but LED on the pin 12 never lights and i cant hear wspr signal on my rtx ….maybe you know what i am doing wrong ?thanks in advance

    • NT7S says:

      Hello Mikele, are you running the supplied ntpserial.py program on a PC connected to the Arduino? That’s what is used to trigger the transmission of WSPR.

  11. Mikele says:

    yes Jason and when i go to run module …i see only “cannot open serial port” and nothing else

  12. Mikele says:

    i think that now is ok….i change dev/ttyusb0/ to com4 and now working 🙂

Leave a Reply to Mikele Cancel reply

Your email address will not be published. Required fields are marked *