Arduino – Si5351 Powered Signal Generator

Arduino-Si5351 Signal Generator

Arduino-Si5351 Signal Generator

Device Description

For a long time I wanted a general purpose signal generator. Now Direct Digital Synthesizer hardware is available on a single programmable chip. The Analog Devices AD9851 is used in many ham radio projects, also widely used is the Silicon Labs Si5351. Either of these can be obtained from many sources such as Adafruit, Sparkfun, or on EBay and there’s lots of information on the internet. Even Amazon has them. A few dollars gets a DDS chip that will tune continuously from audio to VHF mounted on a small breakout board. I purchased an Si5351 board from Etherkit because they offer a version with a TCXO.

Silicon Labs makes the Si5351 in several variations. It’s intended use is as a multiple output clock generator with up to eight individually programmed frequencies. Most commonly available breakout boards though, use the A version with three outputs. Digikey has the bare chips for less than $1. Connectors are optional, most boards are set up for SMA female jacks. The signal generator I built brings out all three outputs but I used good old RCA phono jacks. SMA connectors are wonderful but the cables to use them are pricey. My box will be used to check and align receivers so precision impedance control is less important.

AD9851 chips have a real Digital/Analog converter on board, it uses an amplitude lookup table to produce a fair sine wave. The data sheet says:

“The AD9851 uses an innovative and proprietary angle rotation algorithm that mathematically converts the 14-bit truncated value of the 32-bit phase accumulator to the 10-bit quantized amplitude that is passed to the DAC. This unique algorithm uses a much-reduced ROM look-up table and DSP to perform this function.”

which sounds suspiciously like the quarter wave sine synthesis I experimented with a few years ago. I’ll have to revise my WordPress pages about quarter wave DDS techniques to include the phrase “angle rotation algorithm”. The price for pure sine wave complexity is, the device has only a single output. In contrast, the Si5351 outputs a square wave on all it’s ports – it is intended to serve as a programmable frequency clock source but for my purposes I don’t care and the available multiple outputs are attractive.
I breadboarded the Etherkit breakout along with one of Paul Stoffregen’s Teensy-LCs I had on hand for the controller. A Teensy-LC has an ARM Cortex M0 heart clocked at 48 Mhz. An ordinary 16 Mhz Arduino would probably work in this circuit but would have trouble with sweep. I used basic software from N6QW to get started and my oscilloscope soon showed it was working. Then a series of enhancements to the N6QW sketch followed:
  • expand to controlling all three outputs
  • setting up frequencies using rotary encoder and LCD menus
  • save and restore setup in EEPROM
  • add output power change to the menus
  • add  output OFF to the power menu
  • add sweep capability with menu control

The Box

A thin metal gift card box was cut up to form an enclosure for the generator. It is about a quarter inch larger than the usual Altoids tin in all three dimensions. I needed the extra volume to fit in a battery and charger removed from a cheap phone power pack. These booster packs usually contain a single 18650 cell and it just fits.

Arduino-Si5351 Signal Generator Interior

Arduino-Si5351 Signal Generator Interior

The components are, top to bottom, blue 16×2 LCD board supporting the Teensy-LC. The entire unit can be 5 volt powered either from the Teensy USB jack or from the battery charger, I added a fat diode to isolate the two sources.  Both the Teensy and the Si5351 board are using their on board voltage regulators. The LCD is five volt, but the Teensy-LC does not have 5 volt tolerant inputs. There are 2.2k resistors between the LCD data pins and the Teensy to smooth over that discrepancy, these would not be necessary if the LCD was a 3.3 volt unit. The pot below the Teensy adjusts the LCD contrast.
At left below the LCD is the Adafruit (Bourns) rotary encoder. It just clears the battery. Right of the encoder is a strip of perf board with the three output select pushbuttons mounted. The LCD, encoder and buttons are Adafruit parts.
At the top of the open box bottom is the salvaged 18650 cell. The measured drain of the whole circuit is less than 100 milliamps so the battery should last half a day at least. The gooey glob at the center is a 2.5 amp fuse. To the right of the battery is the on/off switch and isolation diode. The salvaged Lithium charge/boost circuit is the green board at bottom right. It has it’s own separate USB jack because the USB data leads are not accessible. To program the unit you have to plug into the Teensy USB jack.
Finally the blue board in the bottom is the Etherkit breakout. The actual Si5351 chip is at the left end, next to the TCXO. There are three RCA output jacks mounted in the left side of the box, the fourth jack next to the handle is for syncing the scope when sweeping.


On power up the unit reads saved frequency settings from EEPROM. The display then shows frequency, current port selected, and the output power setting.

Click one of the three buttons to change the port selected to display on the LCD.

Rotating the encoder knob will change the frequency digit under the flashing cursor. Press click the encoder knob to change the digit under the cursor, you can set the cursor to change digits from 1 Hz to 10 MHz.

Hold one of the port select buttons down and turn the encoder knob to change output power for that port. The chip has choices of 8 milliamps, 6 mA, 4 mA, 2 mA, and OFF. Silicon Labs’ spec for driver impedance is 50-85 ohms.

If any of the above settings are changed, the software waits ten seconds, then copies the current settings into EEPROM. In the event the unit gets confused, it can be restored to last saved settings by cycling the power switch. Also it can be returned to default settings by holding down all three port select buttons, while powering up.

Arduino-Si5351 Signal Generator Frequency/Power

Arduino-Si5351 Signal Generator Frequency/Power Setting


Sweep Function

Sweep is accessed from a separate menu. Press down the encoder knob for more than two seconds (a long press) and release to enter sweep parameters for the currently selected port.  A short click of the encoder knob will advance the menu through the sweep choices, currently +/-  0, 1000, 5000, 15000, 50000, or 150000 Hz. The unit sweeps from frequency minus that amount to frequency plus that amount so the total width of sweep is twice the setting. Sweeping is done by reprogramming frequencies in 20 steps between the limits.

A second long press of the encoder knob will return to the frequency menu. The letters “sw” appear on the LCD to indicate that that port is set up to sweep. All three ports can be set up but only the port currently selected in the display will be sweeping at any given time.

A pulse is available at a phono jack on top of the box to trigger an oscilloscope at start of each sweep iteration.

Sweep parameters are not currently saved in EEPROM.

Arduino-Si5351 Signal Generator Sweep

Arduino-Si5351 Signal Generator Sweep Setup Screen


The Software

I am using the Si5351 library from Etherkit. I added a function to completely disable the output drivers to save battery when a port is set to “OFF” so I will include the library in the zip file.
Most of the sketch, implementing multiple port and the menus, was straight forward. The one thing that gave me fits was the quadrature nature of the rotary encoder. This is a mechanical switch and it glitches. Not a problem if you are say, setting an analog output from 0 to 1023, you probably wouldn’t notice but if you need to change a digit by exactly one, glitches are intolerable.  Conventional debouncing a switch usually just waits a certain amount of milliseconds after a transition is detected, read again and proceed. There are debounce libraries for doing this. I had no luck. I finally found an post by Oleg Mazurov about treating the quadrature pulses as a Gray code. It helped a lot and I posted about my findings in the Adafruit Feather forum.
The Adafruit rotary encoder outputs four state transitions on each of it’s 24 rotary detent positions. To get one increment per detent, I tried skipping four state reads with a software counter but it was still glitching if the knob was inadvertently touched. What finally worked was changing the Gray code decode table to disallow all but one positive change and one negative change. The allowed changes remaining are in the middle of the detent so glitches near the resting position are unlikely.
Sweep is accomplished by reprogramming a port frequency on the fly. Tests indicate this is slow and the 20 step sweep takes about 65 milliseconds which limits the sweep rate to about 15 per second. I found a very good way to time something is to write a 1 to some output pin at the beginning, then write a 0 at the end. It’s easy to see exactly how much time the intervening code took by measuring the pulse on an oscilloscope. The send_frequency function takes 3.5 milliseconds. Looking at the Si5351 library, the set_freq code is long and complex. It might be possible to speed this up by using the set_freq_manual call but I’m not smart enough to do that. Porting this code to a 16 Mhz Arduino might make the sweep unusably slow.


A zip archive is available including sketch source, the Si5351 library, and a schematic
Jan 4, 2018 V1.1 including the sweep function
 Jan 5, 2018 V1.11 Sweep bug would not change freq while in sweep mode. Cleaned up schematic.
  1. Nice work! Looks like you used a Teensy 3.6 with 3v3 I/O. Presume the 2k2 resistors are for level shifting.

    I am thinking of bringibg out the 3 clocks on my next si5351 transceiver so that it can double as a sig gen for future projects. But a dedicated MCU and si5351 is a better idea.

    Like your mix of radio homebrew and fine woodwork!

    • It’s a Teensy LC I had on hand. Yes the 2.2k are for level shifting, I read somewhere on the PJRC site that would adjust the levels. I think it would be possible to declare the LCD without the R/W pin and it would never try to write on the data pins but I wanted to be conservative. Inhave a Teensy 3.5 and a 3.6 but havn’t done anything with them yet. Next project is a PID temp controller for a toaster oven. will use it for tempering tool steel and maybe soldering.

      • Yes the Teensys are cracking MCUs, I have a 3.6 but havent fired it up yet. I’ll watch your projects with interest.

  1. January 9th, 2018

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: