Front view of the VFO. The display is indicating the Receive and Transmit frequencies, the step size, and the current mode. Pushbuttons PB1, PB2 and PB3 are surface mount type soldered to a bit of circuit board material.
Here’s a full-featured VFO I built around the Si5351a synthesizer IC and an Arduino controller. I’ve written a manual describing its construction and features and I’ll excerpt bits of it below as a description. I’ll also link to the complete manual as well as the source code. It’s painfully obvious that I don’t know how to use this HTML editor, so please forgive the strange formatting changes and misaligned bits.
Nick Kennedy, WA5BDU
After getting the basic functions working I began to expand my software to add features necessary to meet my needs for a VFO to be used in a transceiver project. Those features include:
A keyed line input, so the controller can swap between TX and RX frequency outputs as required as the user keys and un-keys the transmitter.
A TX_Out output pin echoes the keyed line input, but doesn’t change state until the TX frequency registers have been sent, and changes back to key up before the RX frequency registers are sent.
An LCD display to show the frequency I’m on, menu options and so on.
A user settable CW Pitch value which is the amount that the VFO shifts between TX and RX states if in CW mode.
CW/Phone mode selection which functions to enable or disable the CW offset shift when the key line is closed.
LSB/USB selection. This chooses the direction of CW offset in CW mode, so the user can listen to a station on either side of zero beat. In CW it’s sometimes called NORMAL and REVERSE operation. There is also an output pin SB_Relay than can be used control a sideband select relay in the receiver. As of V1.7, this function also changes the phase relationship between the two outputs from 90 to 270 degrees, so you don’t have to do sideband switching in the hardware.
RIT control. This provides for separate TX and RX frequencies, with both displayed. The receiver can be tuned without disturbing the transmit frequency. RX and TX frequencies can be swapped and the offset can be zeroed without turning off RIT.
Frequency step selection. There are both a menu for selecting from seven step sizes and a quick pushbutton selected step change between fine (10 Hz) and fast (100 Hz).
Band selection with all ham bands from 3.5 to 144 MHz selectable.
A Save State menu option which writes most of the current parameters into EEPROM so the VFO will start in the same state the next time it is powered on.
Three miniature pushbuttons allow quick selection of often used functions while a menu controlled by the rotary encoder is used to access other functions. The pushbuttons operate with the familiar TAP and HOLD logic, giving two uses for each.
A sidetone which sounds when the key is closed. A menu option can enable or defeat this function.
Details of operation
The pushbuttons offer six actions, one of which opens a menu with additional actions. A brief press of a pushbutton is called a TAP and a long press (> 0.5 second) is a HOLD operation.
There is audio feedback in the form of a short beep immediately as a switch is closed, followed by two short beeps after it has been held long enough for the HOLD function.
Above is a listing of functions accessed via the pushbuttons. I tape a copy to the top of my VFO for reference.
There’s a great deal of detail to discuss concerning use of the functions of the VFO, but I’m going to refer the interested reader to the manual and try to keep the size of this page down. I do want to tell a bit about the hardware.
An Arduino board, such as a Nano or Uno
A Si5351a module
A rotary encoder
A standard 16×2 LCD display with Hitachi interface
Three N.O. pushbuttons
A few miscellaneous diodes, resistors capacitors and connectors
An Arduino might be $4 to $5 for a Nano or $9 or so for a Uno
A Si5351a module might be $5 or so. I like the module over the bare chip for avoiding difficult soldering and because it has a built in 3.3 V regulator and 5 to 3 volt logic level shifters for the data lines. You can power and talk to it from your 5 V Arduino.
My rotary encoder is a Bourns PEC11L-4020F-S0020 encoder with switch from Mouser. The switch isn’t used. Update: I’m switching to an optical encoder as these inexpensive mechanical ones do wear out and give erratic performance after a time.
Above is a schematic for the VFO. The USB/LSB select relay if used would be driven by A2.
Here’s a photo of the rear of the VFO. CLK0 and CLK1 are the two quadrature RF outputs. The KEY/PTT input will cause the VFO to swap between receive and transmit frequencies, it will also generate a sidetone if desired and actuate a Key Out circuit with which to key a transmitter.
Above is a photo of a Si5351a module connected to an Arduino UNO for testing. I think it’s impressive that with just four wires the system functions by coming up on the default frequency with quadrature outputs.
Here’s an oscilloscope trace of the two quadrature outputs. The output is about 3 Vpp open circuit and about 2.1 Vpp into 50 ohms.
A couple of variations
Some receivers have a divide-by-four logic arrangement in front of a circuit that develops I & Q signals. Since this VFO provides I & Q outputs already, there’s generally no need for an output of four times the indicated frequency. However, one friend wanted to use this VFO with his existing hardware which needed the X4 signal. So I added a flag which will cause the VFO to operate in the X4 mode. It requires editing one line in the source code. At startup, the LCD reminds you of which mode is being used.
The Si5351a can have up to three outputs. Friend #2 wanted to use that 3rd output to drive his transmitter while the other two were used for his phasing receiver. There’s no reason you couldn’t use one of the two quadrature outputs for the transmitter, since it already jumps between TX and RX frequencies. But my friend didn’t want to risk adverse loading effects by having both a RX and a TX stage driven off the same output. So I did another version which provides a third output on CLK2 for the transmitter. After some comedy of errors keeping it on the right frequency and making sure it didn’t QRM the receiver, I think I finally got it right.
Changes made in V1.8, released January 20, 2023 (also, V1.9)
I sometimes get feedback from users with fast rotary encoders, meaning they output a lot of pulses per revolution. This can cause the pulses to outrun the software leading to erratic stepping. I decided to change the input signal processing from a polling method to interrupt driven. Making this change required changing Arduino pin usage such that two pairs of wires need to swap places. Don’t install V1.8 if you don’t want to make these changes. They’re described in the manual.
The interrupt code accumulates step demand pulses in a queue and the main line code works them off as fast as it can. To speed things up, if the queue contains 10 or more demands, it increases the step size by a factor of 10 and does 10 demands in one pulse.
Some encoders can be very fast, making tuning too sensitive. Another change in V1.8 allows the user to compile the software to give one step per pulse, one step per two pulses, or one step for four pulses. (Now V1.9 allows any value from 1 to 255 as pulses per step.)
Variations in encoders have caused most of the problems reported to me. My own mechanical encoder has become pretty noisy. I’m hoping that switching to an optical encoder will smooth things out.
I also developed an Arduino program to allow troubleshooting encoder problems. It uses a separate Arduino to generate simulated Arduino pulse trains of varying length and direction and repetition rate. This is mainly to insure a clean pulse train when testing flaky software. Also it can be used to find out how fast the utilization software can process pulses. I may put it on line but if you are interested, email and I’ll send you the sketch and a manual of sorts in Word format.
Changes made in V1.7, released April 29, 2022
I fixed a few bugs you’ll see reported in the comments section, most of which were fairly minor. One more serious bug caused the 90 degree phase offset between the two outputs to be lost, ruining the quadrature relationship. This would occur while adjusting the frequency and crossing a certain threshold, such as going from 7142 kHz to 7143 kHz. That problem has been diagnosed and corrected. Thanks Tony Bertezzolo, IZ3EYY.
Also in some cases, enabling the RIT resulted in the RX and TX outputs being in different bands. Also corrected.
There’s also a new feature. A software switch now allows changing the phase difference from 90 degrees to 270 degrees. The existing control for selecting USB or LSB (tap PB3) will cause this toggle. The advantage is that you won’t have to design upper and lower sideband selection in your hardware – it’s now in the VFO.
Files you’ll want:
Links to the manual for the VFO and for the Arduino source code are given below. The manual is a PDF file. It includes information on processing the source code in the Arduino IDE and sending it to your Arduino. The file ‘si5351a_quad.ino’ is the Arduino source code, which is a plain text file.