March 7, 2016:
Revised: v1.0

Single Band si5351 Digital VFO

Just how small can you make a dual-output digital VFO/BFO? This version of the ZL2PD si5351 VFO uses an ATtiny85 8-pin controller to cut the si5351 VFO component count down to the minimum. It's a really teeny tiny VFO.
Li-Ion battery monitor board


It was hardly more than a couple of hours after I finished my full-featured si5351 VFO with its Nokia LCD display that the thought arrived. "OK, so my “do everything” VFO can run in an ATmega328. But what if I just need a single-band VFO? How about if I chop out the dual VFO features? Can I do everything necessary with just an 8-pin processor?" Just how small could I get an si5351-based VFO/BFO?

This design is the answer. It’s pretty darned small. In fact, if I use an SMD version of the ATtiny85 and the standard si5351 chip, it’ll all fit on the back of the compact 16 x 2 alphanumeric LCD. It measures about 50mm x 20mm.


The basic items we need in a (digital) VFO are a tuning control and the oscillator itself. The tuning control is, as usual, a low cost rotary encoder with integrated push switch feature. That switch selects the tuning speed (5Hz, 100Hz, 1kHz and 10kHz). This consumes three of the six available pins on the processor.

We also need a display for frequency and tuning speed information. A graphics display like the one used in my other si5351 VFO requires a relatively large amount of software. We’ve (only) got 8k in the ATtiny85 so that’s why I’ve used a two line 16 character alphanumeric LCD.

However, we don’t have enough I/O pins on the processor to connect a standard 16x2 alphanumeric LCD.  To get around this, and a couple of other problems, this design uses a similarly priced I2C version of that LCD. It has another really useful feature – Unlike normal 16x2 LCDs, it can operate with a 3.3V supply. That means the entire VFO can run at 3.3V and we can dispense, once more, with all of that unnecessary interfacing seen in most other si5351 VFOs. Reduces the parts count by about 30%, just like that.

The choice of an I2C LCD is also fortuitous – The si5351a oscillator uses an I2C interface as well, so the pins can be shared by both devices. And since the I2C requires two of the remaining 3 I/O pins, that leaves just one pin for everything else.


Figure 1: Here is the prototype VFO/BFO operating on 40m. There are less than 20 components in this VFO/BFO. The entire circuit fits in  roughly 50mm x 20mm excluding the display

You'll note there is an extra preset variable resistor mounted at the lower left corner of the board next to the S-meter input connector. This was added temporarily to test the S-meter during development and is not required in the final design.

Let's consider what we might do with that last free I/O pin. This is a single band VFO, so we also don’t need any pins for selecting external bandpass and lowpass filters. I could use that last pin as a PTT input. That could permit the si5351's VFO frequency to be changed when switching from receive to transmit. That might be useful in a few cases, but most transceivers now use a common IF frequency, or are SDR-based, and in either case, the VFO frequency doesn't need to change like this.

I looked at adding some pushbuttons to that last I.O pin to provide a few extra functions. Adding dual VFOs is one option, but those features quickly drove the software quite close to the 8k program memory limit.

What else could I add to use that last pin that everyone needs on a transceiver or receiver…..?

I decided on an S-meter input. Since the ATtiny85 has a flexible multi-channel analog to digital converter,adding an S-meter display to the LCD is reasonably easy. The LCD can consume a fair amount of front panel space, so building an S-meter into the VFO design avoids the need to reserve more space for a meter. In any case, meters are becoming harder to find and more expensive every day.

Since the S-meter bargraph display is not actually labelled on the LCD, this input could also be connected to the output of an RF level detector during transmit. This can then provide a dual-metering display for RF output power (while transmitting) and received signal level (during receive).

Feature Summary

The features of this basic VFO/BFO design include:

The current version of the software sets the VFO for 40m operation starting up at 7.100 MHz. It also assumes an IF of 8867kHz and high-side injection i.e. VFO=7.100+8.867MHz when power is applied.

Design Description

The ATtiny85 is a standard AVR processor squeezed into a compact 8-pin package. It has a bunch of features including 8k of flash program memory. The package provides just six I/O pins. Not surprisingly, this design uses every single one.

Let’s have a look at the schematic:

The 3.3V supply (about 30mA) is obtained with a tiny TO-92 sized low voltage drop regulator (IC3) and this is connected to the ATtiny85 (IC1), the si5351a oscillator (IC2) and the LCD display (LCD1). The unregulated input supply is also used to power the LCD backlight via R4.

As previously mentioned, the rotary encoder (SW1) and its integrated push switch (SW2) connect directly to the tiny85. Internal pullup resistors are configured on these inputs via software. The S-meter input (0 – 3.3V) connects to pin 1 via a protection resistor (R1). This should some brief protection if voltages above 3.3V are connected to the S-meter input by accident.

For pin 1 of the ATtiny85 to be used as an input all the way down to ground, the normal ‘reset’ function of this pin must be disabled. This is done AFTER the chip is programmed by configuring the programmable fuses appropriately in the ATtiny85.

The display and the si5351a are connected to the ATtiny85 using the two-wire I2C interface via pins 6 and 7.
The three available outputs from the si5351a are DC-isolated using 100n capacitors. Only two outputs are actually used in the VFO. The CLK0 output is for the VFO and CLK1 is for the BFO. The third output (CLK2) is not used. These outputs have an output impedance of 50 ohms and produce 3.3V square wave outputs. Additional output filtering will be required in some applications.

And that’s all there is. The rest, as they say, is in the software.


The software for this design is, as usual, written in Bascom-AVR, the Basic-like compiler for the AVR family. I find Bascom code development to be relatively quick and easy. Although the generated software is much larger than tightly coded assembly code, the time saved by using this high-level compiler is valuable, and most processors have more than enough space for the code regardless of the approach adopted. In addition, if changes are required to older software at a later date, it’s usually a relatively quick process for me because the code is generally quite readable.

Much of the functional code to drive the si5351 oscillator comes from my previous design. Most of the time, the software simply loops around looking for user inputs, in this case from the rotary encoder and the step switch. In addition, it periodically reads the S-meter input and updates the display accordingly.
Here’s a closeup of the operating display. Pretty simple, really. The top line is devoted to the VFO frequency (The BFO is simply programmed in the software). The lower line shows the current tuning step size on the left, and the current value of the S-meter input voltage on the remainder of the line. Full scale deflection is 3.3V.

Since the rotary encoder is most time-critical input, a background timer is used to continually checks its status. Any input change will result in a calculation of the new data. This is then converted to the correct sequence of about 20 bytes per oscillator output, the data send to the si5351, and the LCD updated to reflect the new status.

The core algorithm required to generate all of the data required by the si5351 is adapted from foundation work done by Jason Milldrum N6QW and others. They are credited in the source code available below. The I2C Bascom library for the LCD is adapted from a very useful piece of Bascom code obtained from a Japanese language website []

As usual, I’ve made the source code available for download below. Feel free to adapt it for your own non-commercial requirements. Just note the (minimal) obligations required under the Creative Commons license.


I built the VFO on a small piece of prototyping board. The LCD is mounted along one edge along with the four electrolytic capacitors required when it is powered from 3.3V. Those four capacitors take up a large proportion of the board real estate. Connections to the LCD are via the eight edge-mounted pins and via short wires to the backlight LED connections on the underside of the right hand edge of the LCD.

The si5351 is mounted on a 10-pin DIL adapter board to make assembly easier. The two outputs are connected to white and blue test pins on the right hand edge of the board.

The regulator is mounted on the left hand corner of the board. It does not require any heatsinking (and none is possible anyway with this TO-92 package) given the modest 30mA drain.

Bill of Materials

Here is a list of all of the parts used to build the VFO. With the exception of the si5351a, everything can be found from the usual online mass-supplier websites. As you can see, the total cost came to just USD13.20 (Priced in Q1/2016) which I think is an impressively low figure.

These prices assume the purchase of larger quantities of most parts than would be required for a one-off build e.g. Purchase of a pack of 20, 50 or 100 resistors etc.

Note that this design (and the software) expects the LCD is the Winstar WO1602I or Midas MCCOG21605B6W-BNMLWI. These are reasonably widely available in most markets (Europe, US, Asia) from the usual suppliers. Other LCD displays that use a “backpack” to convert I2C to parallel I/O will probably not operate correctly. One reason for this is that these latter types almost all operate on 5V. It is possible that minor changes might allow the Displaytronic ACM1602NI to also be used but I have not tested that LCD.

Configuration for Other Bands

The software defines a number of constants at the start of the program. These include:

const startfreq = 7100000    'VFO starting frequency
const ifoffset = 8867000    'IF frequency (0 for SDR or DC receiver)
const bfofreq = 8870000    'bfo/cio frequency

If another band is required, or another IF is used, then these values will need to be adjusted accordingly. For example, if you have a 20m transceiver with a 9MHz IF, and you wish to start the VFO at 14.070MHz then change these values to:

const startfreq = 14070000    'VFO starting frequency
const ifoffset = 9000000    'IF frequency (0 for SDR or DC receiver)
const bfofreq = 9930000    'bfo/cio frequency

The BFO frequency shown is just a suggested value. The actual value will depend on your filter and mixing arrangement. Speaking of which, around line 244, you’ll see…

'frequency offset routine
gfreq = gfreq + ifoffset    'high side injection
'gfreq = gfreq – ifoffset    'low-side injection required

The second line shown is “commented out” by the leading single quote mark. These lines select the arrangement between the frequency generated by the VFO (the variable called “gfreq”) and the IF frequency. As compiled, the IF is added to the VFO frequency.

For example, in the transceiver currently under construction here, the 40m VFO covers from 7.0 – 7.3MHz and the transceiver’s IF is 8.867MHz. Due to the filter and BFO settings, the first mixer expects the VFO to tune from 15.865 – 16.165 MHz i.e. high side injection (VFO is above the IF). That’s the reason the first line (gfreq = gfreq + ifoffset) is used. If the VFO was expected below the IF i.e. tuning from 1.565 – 1.865MHz, then the first line would be “commented out” and the second line of code used instead.

Further Software Development

At present, a full version of Bascom-AVR is required to adapt this software to suit your own requirements. To get around that, the next stage of software development might include the addition of:

User programming would require quite a bit of extra software, using the LCD and the rotary encoder to set and save all of the required parameters in the ATtiny85’s EEPROM. There’s plenty of space available there. The only limitation looks to be the available program space.

Final Comments

Given the excellent stability, dual oscillator outputs, modest size, low power consumption and low cost of this design, I’m likely to standardize on this basic approach in all my future RF work. The bulk of the software is complete, and I’m very happy with the way it works.

Actually, I cannot see any reason to return to any kind of analog VFO design, except perhaps for the occasional nostalgic example. The challenge of finding suitable variable capacitors and high-Q inductors, reduction drives and frequency displays, and the battle to achieve acceptable stability all make it very difficult to build a good analog VFO.

True, the noise floor performance of the si5351 VFO is not as good as can be achieved by a very good analog VFO, or by better and more complex digital designs, but those analog designs are becoming increasingly difficult, if not impossible, to build now, and significantly more expensive. And much (much!) larger to boot.

I think this design will be end up being quite useful around here. I hope you enjoy it too.


Software: The zip file available here includes the Bascom source code and I2C driver software for the specific type of I2C LCD display used. See notes in the test above. Be careful! Some other I2C LCDs may not operate correctly with this library.

Tiny85_si5351vfo: This file contains the Bascom source code and the HEX file for the current version of the VFO. It also includes the library file for the LCD.

The fuse settings for the ATtiny85 are:

LOCK Byte: 0ffh (No locks)

EXTd Byte: 0ffh (BOD disabled)

HIGH Byte: 05fh
          DWEN 1 DW not enabled
           SPIEN 0 SPI programming enabled
        WDTON 1 Watchdog timer off
        EESAVE 1 EEPROM not preserved in erase
  BODLEVEL2 1 Boot ROM size
  BODLEVEL0 1 No boot vector at startup

 LOW Byte:  0e2h
     CKDIV8 1 NOT divided by 8
      CKOUT 1 Not enabled
         SUT1 1 Slow rising power
         SUT0 0
     CKSEL3 0 8 MHz internal RC clock
     CKSEL2 0
     CKSEL1 1
     CKSEL0 0

Want to go back to the main page? Click here to return directly.