Si5351 VFO

By | January 3, 2019

Here is an older project of mine – another variant of a VFO. This time with the popular Si5351 clock generator, allowing to create a complete solution for a superhet, including both the VFO and BFO oscillators.

This project is an evolution of the older AD9850 based VFO (here and here). However, this time I wanted to build a superhet receiver and AD9850 has only a single output, so the BFO would need to be separate. Si5351 has up to 8 outputs (depending on version), covering all the common radio needs easily.


The VFO has the following features:

  • Independent VFO and BFO oscillators
  • RIT/XIT offsets
  • Tx signal input – used to let the microcontroller know when to apply the XIT offset
  • Same display layout as the AD9850 VFO
  • Revised controls – gone are the complicated button combinations, there is now a menu for configuring things such as the IF and BFO frequencies, operating mode, IF mode, etc.
  • Output limited to 1MHz-30MHz (but easily changeable in the code)
  • Supports both 3.3V and 5V LCD modules
  • Easy to adapt to different IF filter frequencies and setups
  • Arduino compatible
  • 2019/11/9 – EEPROM persistence for the settings and frequencies


The VFO uses a standard ATMega328P-AU (in TQFP-32 package), running from the internal RC oscillator at 8MHz. The frequency generation is provided by Si5351a, running from a 25MHz crystal, with all 3 outputs routed to the edge of the board (should fit an SMA connector). In my case the loading capacitors C6, C7 weren’t necessary because my crystal needs only few pF of capacitance – the parasitic capacitance of the PCB is sufficient there.

The user interface is provided by 4 tactile switches (SW1, SW2 & SW3 + RESET) and a clickable rotary encoder (SW4). The output uses a standard 1602 LCD module1. Both 3.3V and 5V (most common) LCDs are supported – select the desired voltage by shorting the corresponding pads of the J4 jumper.

The device is powered from from two LD1117S50TR and LD1117S33TR linear regulators – everything except the LCD module is running directly from 3.3V rail, avoiding the need for voltage translation.

Firmware programming is possible either through the standard 6pin AVR ISP connector (J7) or using a serial bootloader on a 3 pin UART header (J8).

In case of use in a transciever it is possible to connect the external Rx/Tx switching circuitry to the J5 header – if the line /RIG_TX is pulled low, the microcontroller will switch to transmit mode.


Figure 1: VFO Schematic (click to enlarge)


The board was designed in KiCAD 5.0.2, the complete project is included below. The board is double sided, meant to accomodate everything including connectors, the LCD module and all controls.

Most of the passives are 0805 sized, except of C9, C10 which are 1206 sized. Everything should be relatively easy to hand-solder, the special larger “HandSoldering” footprints were used where applicable.

The most tricky component Si5351a comes in a tiny (3x3mm!) MSOP-10 package with 0.5mm pin pitch but it is still doable with a bit of care and careful inspection (use a magnifier!).

Don’t forget to short the correct side of the J4 voltage selection jumper for the LCD or the display will not work!


Figure 2: Top side (click to enlarge)


Figure 3: Bottom side (click to enlarge)


Figure 4: Populated board driving a simple 40m receiver


Figure 5: Populated board driving a simple 40m receiver

I still have a few spare unpopulated boards, if someone is interested in having one (or more), contact me.


The firmware is written in C++ using the Arduino framework for simplicity.

The UI part contains a small template library using both the CRTP pattern to avoid the overhead of virtual functions (saves code memory and a bit of runtime overhead) and compile-time evaluation with variadic templates to permit strong compiler optimizitation. In fact, the version 2.0 of this code used regular inheritance, virtual functions and no templates – and was about 2kB larger. Quite a difference in a micro controller with 32kB of code memory. The drawback is that the code is not exactly easiest to follow and read without some experience in template metaprogramming.

If someone is interested in learning how this works, some good resources are here:

The code does not depend on the standard library because that is not commonly available for AVR. That is also why I had to include minimal implementations of an array and tuple containers. Those don’t claim to be complete or bug-free by any measure, they are meant to be only used for the purposes of this UI library.

Otherwise the code depends on the Etherkit Si5351a library (not the Adafruit one, that one didn’t work for me), Brian Low’s Rotary encoder library and Bounce2 button debouncing library. Install those either using the Arduino library manager or manually, as described on their Github pages.

The functionality is very similar to the AD9850 VFOs, however I didn’t implement the automatic saving and restoring of the last state to/from the EEPROM. I have rarely used that feature and it only complicated the code and was wearing the microcontroller out (EEPROM has a limited number of writes). The code is prepared for it, if someone needs it, it shouldn’t be too difficult to add this back.

The serial port is also unused in the current version (apart from debugging). It could be used either for remote control or e.g. for band switching in the future if someone wants to implement it. The connector is there.


When uploading the firmware, do make sure to select a board variant that supports 8MHz internal oscillator (normal Arduino Uno uses 16MHz crystal/resonator).

The instructions how to add a custom board configured for the internal 8MHz RC oscillator are, for example, here.

Basic controls

Encoder left/right Tuning, menu navigation, changing values
Encoder button Change tuning step, confirm selection
Button A Hold down to enter “cursor” mode where you can rapidly dial in the desired frequency decade by decade
Button B Set RIT offset (XIT when /RIG_TX is active as well)
Button C Enter/exit the settings menu

The numeric settings (such as the IF and BFO frequencies in the settings) are changed by clicking the encoder, scrolling the cursor to the decade you want to adjust, clicking again to confirm and then rotating the encoder to change the value. Click to confirm again. The mode is exited by moving the cursor completely to the left of the display and clicking the encoder button again.


Operating mode – for the offsets see below

AM BFO off
LSB BFO freq = BFO center + BFO SSB offset
USB BFO freq = BFO center – BFO SSB offset
CW BFO freq = BFO center – BFO CW offset

IF mode

Off Frequency on display is the frequency output
F+IF VFO outputs the displayed frequency + the configured IF (additive IF)
F-IF VFO outputs the displayed frequency – the configured IF (subtractive IF)

IF & BFO frequency

IF and BFO center frequency, useful for peaking filters, etc. The default in the code is 8987.5kHz because that is the center frequency of a surplus Yaesu filter my receiver is using.

Invert sidebands

A small hack that reverses the meaning the LSB/USB modes when active. Rarely useful, mostly for debugging and testing.


Everything that is configurable is collected in the file definitions.h. The following values are likely the ones that will need to be customized depending on your radio (filters, etc.):

Variable Initial value Meaning
VFOFreq 7100000 Initial frequency of the VFO in Hz
IFFreq 8987500 Initial IF frequency in Hz
BFOFreq 8987500 Initial BFO frequency in Hz. BFO center frequency in Hz. Frequency from which the offsets are subtracted/added.
BFOSSBOffset 1250 How far to offset the BFO from the center when receiving SSB. Normally it should be 1/2 of the bandwidth of your IF filter.
BFOCWOffset 600 How far to offset the BFO from the center when receiving CW.
TuningIncrements 100000, 10, 50, 100, 500, 1000, 2500, 5000, 10000 Available tuning steps in Hz
RitIncrements 10, 100, 1000, 1 Available RIT/XIT tuning steps in Hz
TuningIncrementIdx 4 Initial tuning step (500 Hz in this case)
RitIncrementIdx 0 Initial RIT tuning step (10 Hz in this case)
Rit 0 Initial RIT in Hz
SidebandsSwap false Initial value of whether to swap the meaning of LSB/USB mode setting
FreqLimitUp 30e6 Upper frequency limit for the VFO (30 MHz)
FreqLimitDown 1e6 Lower frequency limit for the VFO (1 MHz)
SI5351Addr 0x62 I2C address of the Si5351a – according to the datasheet it should be 0x60 but chips with 0x62, 0x6f are common too. Try to change if the VFO is not tuning.
SI5351Correction 2004 Frequency correction for the Si5351 crystal – if you have accurate counter you could try to tweak this to calibrate the frequency of the VFO


Schematic + PCB:

  • KiCAD 5.0.2 project, including the Gerber files (in the “gerbers” subdirectory), so no need to install KiCAD if you only want to have the PCBs manufactured. Just extract the gerbers and upload them to the board fabricator of your choice.
  • Bill of material

Firmware (GPL v3 licensed):



Some other designs use the cheap 0.96″ OLED displays – I didn’t want to use one of these because they are both very electrically noisy (not something desirable around a sensitive receiver) and I find them too tiny to be comfortably readable, despite the excellent contrast. Also the squarish aspect ratio looks odd on a front panel.

53 thoughts on “Si5351 VFO

  1. Ben

    Just wanted to say thank you for this. I just built this and it is working wonderfully. (I build your AD9850 version a few years ago.)

    1. Klaus


      I translate my English with google da …..

      Thanks for publishing it here on the net.
      For me the whole thing runs with an Arduino Nano and an external 1602 display.
      I will take it as a quartz replacement.

      73 de Klaus, DL2HAD

      1. Jan Post author


        Thank you and I am glad that it is useful for you!

        73 de Jan, OM2ATC

  2. Tony

    Hi Jan,
    I am rebuilding a hf man-pack (tr28) with a range of 1-8Mhz.
    I have tried many si5351 vfo’s which were just not right.
    Then I found your vfo and after lots of attempts I got it right…… learning Arduino etc.
    It is everything in one practical package .. brilliant!!
    As the man-pack has side-band filters I changed the mode to AM SSB CW. 1976 vintage
    Would it be possible to change the tuning-steps to a cursor under the relevant number ( same line)?
    Now I am pushing my luck———What about resetting the previous numbers to zero when changing the
    tuning-step eg 7,069,400 to 7,070,000 ?
    Once again great design!
    Tony ZR6ALG

    1. Jan Post author


      I am glad that the thing works for you.

      Re display of the tuning steps – you mean to display it as a list of numbers with the selected step underlined? I am afraid that wouldn’t fit on the display (there is only 16 characters per line!). But feel free to hack, the display is defined in vfo-screen.h, in the render_impl() function. It is commented and should be fairly obvious what needs to be modified if you prefer a different style of display.

      If you want to reset the frequency to the default one when changing the step (not sure why you would want to do that, though), you can easily change that yourself. In vfo-screen.h, search for the function handle_input_impl() (line 195) and you will see two if statements that change the step up or down depending on the sign of the ev.ay variable (the encoder rotation). If you want to reset the frequency, just add there:

      m_state.vfo_freq = Defs::VFOFreq;
      m_state.vfo_dirty = true;

      And recompile. That should do the job. You can replace Defs::VFOFreq with your own frequency if you don’t want to use the default starting frequency from definitions.h.

      1. Tony

        Hi Jan,
        Thanks for the prompt reply.
        I am sorry I did not explain my self properly re tuning-steps
        Instead of the freq being displayed on the bottom line in Hz is it possible
        to place the cursor under the appropriate digit on the main freq, eg if the
        tuning-step is 100Hz place the cursor under the 3rd digit, so you will see
        the step position at a glance, and not have the freq displayed below.
        The other query is if you are on 7.022500 Mhz and want to go to 7.070000 Mhz
        and select the 10000Khz step you will have (after tuning) 7.722500 Mhz.
        If the last 5 digits are reset to zero when the 10000 Khz step is selected you would have 7.070000 Mhz.
        This would save you from having to step back for each digit.
        My programming skills are still in the baby steps mode!! hi
        Thanks again
        Tony ZR6ALG

        1. Jan Post author

          Ah I see.

          Re cursor – feel free to add that yourself for your radio but I am certainly not going to add this. I am afraid it would just confuse people because they would think the cursor tuning mode is enabled. Furthermore, the tuning steps are not only powers of 10 (whole decades). How will you indicate e.g. a very common 500Hz or 2500Hz tuning step then?

          The question about resetting the frequency – I think what you want is to actually round the frequency to the nearest multiple of the tuning step (again, zeroing the digits is not enough – the tuning steps are not only whole decades!). Feel free to add this in the place I have indicated above but I am not going to add this into my code. Again, I think that would be confusing and annoying if the receiver jumps around/changes frequency merely because you have changed the tuning step.

          >My programming skills are still in the baby steps mode!!

          Well, good opportunity to learn something new! These modifications you are asking for are a good starting project, because they are relatively simple and you don’t need to go deep into the C++ “plumbing” of the code (especially the CRTP templates are tricky).

          1. Tony

            Hi Jan,
            Points taken, I will soldier on and keep you posted.
            An odd thing occurred when I powered up the the vfo, there was no freq displayed,and if I turned the encoder a freq of 1Mhz appeared and it would not save.
            I reloaded a clean copy same problem. I then reloaded a fresh bootloader and loaded the vfo s/w … problem solved. It appeared that the bootloader had got corrupted.
            Thanks for your help and patience!
            Tony ZR6ALG

  3. Jan Post author

    Feel free to get in touch if you have any questions.
    Re the weird problem you had – that could be also EEPROM corruption. If the data in the EEPROM are not what the program expects, all bets are off. If the EEPROM is erased/empty, it will detect that and initialize it properly but if there are some old data in there, anything could happen.

  4. misael

    me interesa su sketch como lo puedo correr en arduino nano, si5351a, lcd 16×2

    1. Jan Post author


      Sorry, my Spanish is non-existent but I assume you want to run this on an Arduino Nano. In that case the code should work as-is, but you will need to check that the pins I have used exist on a Nano and if not (or if conflict) change the code to use different ones.

      Otherwise it should work.

  5. misael

    hello jan my English excuses
    friend already made the project everything it was successful alone I should change the pines asinacion for the nano and the address of si5351 0x60 that it is the one that I use; thank you and alone a comment because double VFO doesn’t add him with a fifth ideal botton to be the project of radios made at home. 73s cordial

    1. Jan Post author

      Cool, congrats! The thing with the si5351 address is documented in the article, I have encountered chips with different addresses. It is strange, frankly – maybe there are fake chips around?

      If you want to add another button for dual VFO, well – if you have a free pin, adding a button is easy. What is less easy is extending the code to handle the state of two VFOs, especially if you want to keep track of more than just 2 frequencies (RIT/XIT, sideband, etc.) I am not planning on doing it because I don’t have need for it but if you do this, feel free to send me the patch or link to your version. I will add it to the post for others to find.

  6. John Greusel

    Hi Jan,

    I haven’t built the board yet but trying to test compile I’m getting these errors. The only one that seems problematic is the Rotary one. Also based on other comments it sounds like I’ll need to install the bootloader. I just did an AVR project that didn’t use that but rather just had me upload a hex file.

    John Greusel

    Warning: Board breadboard:avr:atmega328bb doesn’t define a ‘build.board’ preference. Auto-set to: AVR_ATMEGA328BB
    C:\vfo-si5351.2\vfo-si5351.2.ino: In function ‘void setup()’:
    vfo-si5351.2:54:11: error: ‘class Rotary’ has no member named ‘begin’
    encoder.begin(true); // enable encoder pull-ups
    Multiple libraries were found for “si5351.h”
    Used: C:\Users\John\Documents\Arduino\libraries\Si5351Arduino-master
    Not used: C:\Users\John\Documents\Arduino\libraries\Etherkit_Si5351
    Multiple libraries were found for “LiquidCrystal.h”
    Used: C:\Users\John\Documents\Arduino\libraries\LiquidCrystal
    Not used: C:\Users\John\Documents\Arduino\libraries\OLD_LiquidCrystal
    Not used: C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.42.0_x86__mdqgnx93n4wtt\libraries\LiquidCrystal
    exit status 1
    ‘class Rotary’ has no member named ‘begin’

    1. Jan Post author

      You have most likely an incorrect version of the Rotary library.
      Do make sure you use this one, linked from the article:

      You have also multiple version of the si5351 library installed, that’s not good because it will likely cause problems. Same as for the LiquidCrystal lib.

      1. John Greusel

        Thanks Jan,

        I did succeed in compiling and I generated a binary file.
        Interestingly it created two- one with bootloader and one without. I believe I may be able to use AVRDUDESS (or something similar and upload the binary file I’ve created? Alternatively I can us my USBtiny with the Arduino software and load it that way.


        1. Jan Post author

          That’s a bit weird that you have two binaries and one with a bootloader? Are you sure about that? I wonder how did you compile that because that’s not how the Arduino IDE works. Bootloader is flashed separately, it makes little sense for it to be bundled with the binary.

          If you have an Arduino with a bootloader (i.e. normal Arduino board), then you can upload it over USB, as a normal “sketch” using the built-in bootloader.

          If you don’t have an Arduino with a bootloader (i.e. a blank chip and not an Arduino board), then you can use USBTiny (programmer) and the ISP connection to flash it using the avrdude command line utility (AVRDUDESS is a graphic frontend for avrdude). But that is the same thing as clicking “Upload using Programmer” in the Arduino IDE.

  7. John Greusel

    I was surprised too. Making the binaries was more of “let”s see what happens.” Here are the file names that were created:


    I didn’t tel it to do that it just defaulted to making these two hex files.


  8. John Greusel

    Hello Jan,

    Works great. My SI5351 address was 0x60 so had to edit that. My encoder runs backwards for up/down frequency. Is there a setting for that in the sketch or should I reverse the pins?

    Thanks for another great project!


    1. Jan Post author

      Hello John,

      I am glad that it works for you.

      Re encoder – at the top of the main.cpp/main.ino file you will find the line:

      Rotary encoder = Rotary(2, 3); // Sets the pins the rotary encoder uses. Must be interrupt pins.

      Just change this to:

      Rotary encoder = Rotary(3, 2); // Sets the pins the rotary encoder uses. Must be interrupt pins.

      That should reverse the direction of the encoder. Of course, swapping the physical pins works too.

  9. Charudatt

    I am a bit surprised by the fact that you are referring to the same thing twice by different names having the same value. IF and BFO.
    I guess for computational purposes , both are the same.

    de VU2UPX

    1. Jan Post author

      Well IF and BFO are not the same thing! That they have the same value in the code is just initialization coincidence. IF is the intermediate frequency after mixing and BFO is the beat oscillator frequency. BFO is normally on the same frequency as your IF. However, you may want to offset the BFO, e.g. to select the upper or lower sideband or you may want to offset the center to deal with some peculiarity of your filters. That’s why there are separate values for each.

  10. John Greusel

    Is there a way to change the code so it defaults to VFO plus IF instead if VFO minus IF?


    1. Jan Post author


      Yes, for sure. Open the vfo-screen.h file and change the initialization of the ifmode field of the TVFOState struct from:

      struct TVFOState
      Defs::OperatingMode opmode = Defs::OperatingMode::LSB;
      Defs::IFMode ifmode = Defs::IFMode::F_MINUS_IF;

      int_fast32_t vfo_freq = Defs::VFOFreq;


      struct TVFOState
      Defs::OperatingMode opmode = Defs::OperatingMode::LSB;
      Defs::IFMode ifmode = Defs::IFMode::F_PLUS_IF;

      int_fast32_t vfo_freq = Defs::VFOFreq;

      And recompile.

      1. John Greusel

        Thanks so much Jan!
        That worked perfectly. I tried to find that configuration setting but didn’t look there.



    Hello. Cuando trato de compilar cualquiera de las dos versiones, me da error compilando para tarjeta. Q pudiera ser esto? No estoy muy ducho en temas de programación. Favor de escribirme a mi correo. No tengo muchas oportunidades de conectarme y estoy ansioso por ver trabajando este DDS. Gracias. God bless you.

    1. Jan Post author

      Hello Michel,

      I am sorry, but I don’t speak any Spanish 🙁 I understood that you have some compilation problem? It would help to see all error messages you are getting, otherwise it is impossible to help you.

      If the code isn’t compiling, you are probably missing some of the dependencies – the Etherkit Si5351 library, Bounce2 debouncing library or the Brian Low’s Rotary encoder library. The links to them are in the article.



        I will go to send you the mistakes messengers


        Hello friend. Finally, i could charge the firmware to the Atmega 328p. But, i have this question. I can used this firmware with a 16mhz external cristal without change nothing in the firmware? I hope you understand this, because i do not write in english very well. I wait your answer. God bless you.

        1. Jan Post author

          That’s great news, congratulations.

          And yes, you can run it with a 16MHz crystal – just make sure to select an Arduino Nano or Uno in the menu as the boards you are building for. That will take care of any differences in the Arduino clock frequency.

          The VFO output is unaffected by this because the Si5351 has its own 25MHz crystal.


  12. Apud

    Great project… works perfectly on arduino nano.
    although I don’t know C++ language, but it’s quite easy to customize because the explanation of the program is very detailed.

    This is what I tweaked:
    – IF/BFO lower limit (I changed it to 0)
    – lower limit freq. (I changed it to 100kHz)
    – customize menu display (blink cursor, menu title, checkbox, menu highlight, etc)

    My question is, is there any effect if I change the minimum value of IF and BFO frequencies to 0 ?


    1. Jan Post author


      Careful, you can’t have IF/BFO from 0Hz, that doesn’t work unless you are building direct conversion receiver (there your “IF” is effectively the audio).

      Also, the limits are there because in some combinations you could get invalid frequencies – Si5351 is not able to output completely arbitrary frequencies and there are upper and lower limits you must fit into or all bets are off.

      So do verify that you don’t get some negative numbers somewhere and that whatever is the resulting frequency that you are attempting to program into the Si5351 it is within the supported range.


      1. Apud

        ok thanks for the explanation, so far I don’t get negative numbers, because I separated the if/bfo frequency limit from the main frequency limit, by adding a new constexpr code, for the main frequency it is not affected, but it seems I still have to check again to make sure the frequency of si5351 is accurate.

        1. Apud

          solved, I’ve checked again, the lower limit of IF/BFO runs fine at 100kHz, (1e5).

          thank you sir

  13. Tito CO2KMK

    Hi Jan,
    I use this VFO with si5351 in some of my QRP,
    but in the vfo that I built with Atmega328P DIP, when I move the encoder
    the LCD 16×2 blink, others fact with arduino doesn’t have this problem,
    I am using the correct libraries,
    the vfo works very well, I am using it now, but when I move the encoder to syntonize
    the LCD 16×2 blink.
    I would thank their help with this, any suggestion or comment would help.
    73 co2kmk

    1. Jan Post author

      Hello Tito,

      Sorry but that is something wrong with your build, given that it works with an Arduino and not with a standalone chip. I can’t really help you without seeing what you have done, how is the device built/wired and what exactly did you program into the chip.

      Also, I am not sure what exactly do you mean by “the LCD 16×2 blink”. Is the backlight flashing/flickering? That sounds like a bad connection/cold joint somewhere. Is the content of the display flashing? That sounds like some display connection problem or maybe interference. Or maybe the encoder is bad/connected wrong?

      You need to debug this – start by elimination. Check wiring, check all connections, solder joints. Try another LCD module (it could be defective!). Try another encoder (it could be bad). Etc.


      1. Tito CO2KMK

        hello Jan
        thank you for their answer, really everything is new,
        what I am thinking the VCC is 5v and not 3V, the can the voltage
        to influence in VFO ? .In other projects the Atmega328P works with 5V
        the display is in white not ligh the display, is the characters disappear and they appear when moving the encoder.
        I send picture of the design of the PCB so that I understand me
        excuse me and thank for you time my friend.
        73 co2kmk

        1. Jan Post author

          Hello Tito,

          Unfortunately no picture of your board.

          Voltage doesn’t matter – the board has provision for running the LCD from both 5 and 3.3V (there is a jumper J4 for selecting the right one), so it can support both a 3V and 5V LCD module. The ATMega doesn’t care, so it is powered in my circuit from 3.3V. In that way no level conversion is required for the Si5351 (which is a 3.3V only part).

          What you are describing sounds like a bad contact somewhere that changes when you apply pressure on the board while moving the encoder. Or maybe your contrast pot needs adjusting/moves when you move the encoder. Even RF getting in through come capacitive coupling when you touch the encoder and causing interference/LCD blanking out is a possibility.


          1. Tito co2kmk

            Hi Jan
            I send you the pictute of my designer, or one video .
            Thank again.
            73 co2kmk.

          2. Jan Post author

            Hello Tito,

            Yes but where did you send it? You can upload the picture somewhere and post a link here or send it to my e-mail – it is on the contact page.


          3. Jan Post author


            I believe I have received your e-mail & video now. I have replied to it but in case you don’t see it – that flicker you see on the LCD is normal, that is just updating of the display.

            However, it is supposed to be a bit faster than that (and thus less flickery).

            Since this is happening only with a fresh chip and not on your Arduino board, do make sure you have cleared the CLKDIV8 fuse – that one is programmed from the factory by default and causes the clock to be divided by 8, thus making everything run 8x slower. The chips on the Arduino boards have this fuse cleared from the manufacturer already, that’s why you don’t see the issue there.


  14. Sunil A R

    // encoder
    encoder.begin(true); // enable encoder pull-ups …………………………

    in compiling time one error message is in this line ,
    exit status 1
    ‘class Rotary’ has no member named ‘please help how can correct it

    1. Jan Post author

      Sorry but without seeing the entire error message and knowing what exactly you did I am literally unable to help you.

      That error happens because the code is calling some functionality that does not exist. That could be either because you have a different, incompatible, version of the Rotary library installed or because you have some typo in the code. However, can’t say more without seeing the entire error report – if this is not the first, top-most error you are getting, it could be well a complete red herring caused by errors before it!

      Make sure you have no typo in the code and that you have the correct dependencies linked from the post installed.

  15. Fuds

    Perfect… a very complicated program but fun to learn. finally I was able to add automatic Band selection + BPF relays, IF values ??separate from VFO, display modifications, and some other modifications I needed. Right now I’m thinking of changing the LCD to OLED or graphic LCD, but it seems like a big change is needed while my knowledge is least. Hopefully later I can do that, I still have a lot to learn to understand the program. I think this program is the best because it is fully featured and shared for free. Thank you sir

    1. Jan Post author

      Nice, congratulations!

      However, concerning the OLED displays or graphic LCDs – beware, some of those are extremely noisy because of the internal switching voltage converters and if you are building a radio, that’s probably the last thing you want. Also for driving a graphic LCD/OLED you may need more memory than a poor ATMega328 has available. In such case I would advise porting the code to a beefier microcontroller.

      Good luck!

      73 Jan

  16. Jack Margolis

    What is the issue if compiling your si5351 script with a regular Nano?

    “When uploading the firmware, do make sure to select a board variant that supports 8MHz internal oscillator (normal Arduino Uno uses 16MHz crystal/resonator).”

    Where would there be a problem?

    73, Jack USA

    1. Jan Post author


      The comment is meant that if you are building my circuit (i.e. it doesn’t have an external crystal/resonator), then you must select a board supporting the internal 8MHz RC oscillator in the Arduino IDE or you won’t have a clock and the microcontroller won’t work.

      If you build this and use an actual Arduino Nano instead (i.e. there is an resonator/crystal for the MCU clock), then it won’t be a problem.

      73, Jan

  17. Apud (again)

    I’m using an STM32 board with LCD I2C and 24Cxx EEPROM, after going through a lot of trials, finally my attempt was successful and this DDS worked fine.
    Thank you sir.

    1. Jan Post author


      Congrats! You are probably the first one I know about who runs this code on an STM32 board. Nice job!

      I am glad it is working for you.

      All the best,



Leave a Reply

Your email address will not be published.