Saturday, January 24, 2015

Si5351 simple VFO hardware setup

I see that there is a need for a simple Si5351 sketch to get hams started using this great little cheap chip. I started by downloading, Przemek Sadowski, SQ9NJE 's code and his Si5351 library and was able to get it to work with very little problems. Przemek's code comes with a library called 'Rotary' (written by Ben Buxton) which is used to provide an interrupt driven rotary encoder for tuning. I eventually used the rotary library with Jason's (NT7S) Si5351 library but kept the bulk of Przemek's Arduino sketch. Just be careful if you try both si5351 libraries as they have the same name. This will cause a problem if you try and load them both into the Arduino Libraries folder :).

You will need: (I've listed Adafruit items but you can get them almost anywhere)

Arduino Uno
10K contrast potentiometer
LCD (compatible with Hitachi HD44780 driver) + contrast pot
Rotary encoder with push-button switch
Adafruit Si5351 Breakout Board

Here is the layout:
I use clk0 for the vfo and clk2 for the bfo.
*Your LCD may have a current limiting resistor already installed between pin 15 and the back light, In that case, you can supply +5v to directly to pin 15.

Use this updated sketch and library from this page that will allow for IF offsets, X4 output or Direct Conversion receivers
If you've never used Arduino before go here to the Programming Electronics Academy and watch the first the first and second videos (watch the second one first!). It can't be stressed how important it is to do a proper install of the Arduino IDE(Integrated Developement Environment) so that your programs and your downloaded libraries stay separate from the location of the Arduino IDE and the libraries that are included with each new version of a new IDE download. 


  1. Nice series of posts. I got the libraries and code per your instructions and hooked up stuff per your diagram and now it seems to be running. This was my first experience fooling with user libraries, so I'm taking the opportunity to learn how to write my own. 73 - Nick, WA5BDU

  2. Hi Nick,
    Glad you were able to get something out of these posts. Good luck with writing your own libraries - it can be a lot of fun.
    Check out the code used in the Minima and the Ten Tec Rebel. Even though it is not all based on the same signal producing device it is still Arduino based. I've taken lots of good programming information from both sites. (you will have to join)
    73, Tom, ak2b

  3. Hi Tom.

    I have just completed your si5351 vfo. and it is working "kinda sorta". I have output on the proper frequencies but no change in frequency when the encoder is turned. the step button is working and so is the display.

    any help would be appreciated.

    Paul, WA7SDI.

  4. Hi Paul,
    If you aren't getting any errors when compiling, I would guess that your wiring may need checking. Make sure the center pin of the rotary encoder goes to ground. My encoder keeps popping out of the breadboard and I sometimes have to hold it down :).

  5. Hi Tom.

    Thanks for getting back to me so fast. I went over the wiring several times looks ok to me. one thing I think is off is that only one of the two encoder pins "2-3" is high, is that the way it is supposed to be? just for luck I hooked up some pull up resistors and had the proper wave form when I turned the encoder but still no change in frequency. just to make sure I hooked up another Arduino Uno and had the same results.

    While observing on the scope I could see that one input pin was changing state while the other was staying at 0 volts. the way I gather is that there must be two signals from the encoder so the code can decide the direction of rotation.

    I looked over the code and could not see where the code sets the input pins high. I am not a computer guy so must have over looked something.

    any ideas? Paul.

  6. Hi Paul
    It's important to note that the encoder is interrupt driven and equally important to note is that only pins 2 and 3 of the Uno are the interrupt pins. If you deviate from this, it won't work. You should see both pins of the encoder changing state at various times. If they are not, you may have a bad encoder. (try switching pins 2 and 3 with the encoder pin that is changing to verify the Uno is ok.) You do not need the pull-ups on the two encoder pins nor do you need to set them to anything. This code takes care of this:

    PCICR |= (1 << PCIE2); // Enable pin change interrupt for the encoder
    PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); //assigns pins 2 and 3 of the Uno to be interrupts.
    Click on the "Ben Buxton" link at the top of this post for an explanation of encoders and his 'Rotary' library.

  7. Hi Tom.

    well I did some detailed circuit testing and I found a bad jumper wire. now the display is responding to the rotary encoder but as soon as it is moved the output of the si5351 stops. I can do a reset and everything starts to work but as soon as the encoder is moved the same thing happens again. the display is working fine.

    what do you think now?


  8. Hi Tom.

    A quick update to my last post. there is actually an output from the si5351 and it does respond to the encoder but the frequency does not match the display. the frequency on the display is showing 5.2 mhz. and the actual signal is at 14.2 mhz.

    I will keep digging around and keep you posted.


  9. Hi Tom.

    I am showing my ignorance. I figured out that the display is showing the clk frequency + or - the I.F. looks like all is working now.

    Is there a provision in the code to store the last frequency used and call it back up when power is restored?

    Thanks for all your help.


    1. There are a number of pins on the Arduino board that are not used in this project; looking at the diagram, I see pins 4, 12, 13 as well as 4 of the analog inputs. It would be fairly easy to add a pushbutton on one (or more) of those pins, to add a "store frequency" feature. Another button could allow you to scroll through a number of stored frequencies to select one and use it. The possibilities are only limited by the memory space in the Arduino, and your imagination + skills. :) I'm just getting started, and I love the Arduino! This looks like a project that I really should try! :) Another idea would be to use one of the pins for an analog output (PWM) to send a voltage to some varactor diodes, to tune your front end for better image rejection and sensitivity. (Also to tune filters to drive the transmitter with a purer signal.) Fun stuff! :)


  10. Hi Paul,
    Glad you got it working.
    No, there is no provision for saving the last frequency but it poses a good question. When do you save the frequency since the program has no way of knowing when you are going to kill the power? Do you periodically save it to EEPROM? If so, how often? And, how many times can you write to Arduino EEPROM before it revolts?
    Recalling the saved frequency wouldn't be much of a problem.
    At the moment this program is pretty simple, intended to allow those unfamiliar with Arduinos and programming, to get up and running using the si5351. The next step is to actually put it into a receiver. From there, to add a simple transmitter. There are all kinds of mods that can be made to the software and hardware as what I did in this video
    The main reason I wanted to learn how to program was that I would be able to do the things I wanted.

  11. Hi Tom.

    well at least I have a working vfo and code now to play around with.

    I have changed the I.F. frequency and B.F.O. to match my test superhet. and I will be hooking it up soon. for testing.

    The old V.F.O. is an AD9850 controlled by Arduino. it works! but the transmit signal is pretty dirty. and I don't want to put it on the air. that is why I wanted to play with the si5351 hopefully the signal will be easier to clean up.

    Thanks for all your help Tom.

    73 Paul.

  12. Hey Tom,

    Thanks for the code and the wiring diagram, I got my custom build breakout board up and running.


    1. Hi Amogh,
      I'm glad you were able to get it work. I checked out your web page - nice work.

  13. Hi Tom.

    Is there a way to fine tune the xtal oss. on the si5351 brake out board? the difference between the display and the tuned signal on my receiver is around 200 hz. no big deal, it just kinda bugs me.

    73 Paul.

    1. Hi Paul,
      Yes, by using si5351_set_correction();
      si5351.set_correction(140); //used for setting the difference between what you see and what you // really have
      As you can see mine is +140. You can use minus numbers if need be. Put this statement at the beginning of your setup() before si5351.init(SI5351_CRYSTAL_LOAD_8PF)


    2. ...If your correction seems to be working out ok, comment out the line i.e
      you can put in the following line if you want to see if the correction has stayed the same after recycling power to the Arduino:
      int cor = si5351.get_correction;
      put the code lines in setup();

  14. Hi Tom.

    thanks for the info. I haven't had a chance to plug it in yet but I will soon.

    73 Paul.

  15. Hi Tom, thanks for the nice project. I've assembled it using an I2C interface to the LCD:
    The changes to the sketch were easy.
    Then I tried this higher resolution rotary encoder:
    It costs about the same as the rest of the parts combined, but the experience is pretty close to a "real" VFO.
    The sketch doesn't skip pulses when I turn it fast, but there is a bit of lag before the frequency changes all the way.
    73, Mike AF7KR

  16. Hi Mike,
    I2c is a more convenient way to use an LCD as it saves a few pins (sometimes this is critical).
    It seems your encoder is suffering "from encoder overflow".
    What library are you using with the encoder and are you using interrupts? The encoder library used in my sketches is the one by Ben Buxton and can be used with or without interrupts.
    73, Tom

  17. Tom, Just finished assembling the VFO, and it works great. I will be using it in my upcoming receiver project. Thank you for your efforts.
    73, Steve WA7JTU

  18. Hi Steve,
    Glad you got your VFO up and running. I would like to see pictures of your rx.
    73, Tom

  19. Hello Tom
    Thank you
    My vfo worked perfectly .The blog if the information is good .

    Beto Baleia

  20. Hi Tom,
    I tried your code using Nano, and an adafruit BoB for the Si5351, but I'm not getting any output from the BoB.
    I tried the I2C scanner and it works, shows me the correct I2C address. The Code compiles properly and installs on the Nano, but just no Output.

    Any help.


    1. Hi Charudatt,

      I would open the example sketch from whatever library you are using for the si5351. If you are using Jason's library then go to:
      File --> Examples-->Si5351Arduino(or whatever your library name is)-->si5351example.
      Run the sketch and open "Tools-->Serial Monitor", set the baud to 57600 and you should see:

      SYS_INIT: 1 LOL_A: 1 LOL_B: 1 LOS: 1 REVID: 1

      repeated over and over. CLK0 output should be 14 MHz and CLK1 should be 20 MHz.
      Let me know if this works.


    2. Yes TOM it works what next. TU for the help and sorry, if you have repeated this a couple of time.

  21. Hi Charudatt,
    If you're using a Nano, change these lines to read:
    #define ENCODER_A 1
    #define ENCODER_B 32
    also, add this as the last line in "Setup()" below "display_radix();"
    changed_f = 1; //added to initialize si5351
    1 and 32 are the interrupt pins on the NANO. If it tunes the wrong way - reverse the pins.
    without the last line above in setup() the si5351 will not output unless the encoder is changes position.
    Try it and see if it works.

    1. Hello Tom, yes, I am working with the NaNo but the Encoder and the LCD works properly. I'll still try what you say and give you a feedback. Thank you.

    2. No Tom, it did not work, but with the encoder output connected to 2,3 it works properly, at least the display and other thing. I added this line "changed_f = 1; //added to initialize si5351" as mentioned but still no work. Will it not lock on to the default frequency i.e. 14.200 on start up. even if the RE is not connected. Which pin is 32 on NaNo ? BTW, I am using the latest IDE i.e. 1.6.5, hope there are no issues with that......

  22. Sorry about the pin out mistake. It was late :) Yes, you do not need to change the encoder pins.
    I don't know how to resolve your problem. What sketch are you using?
    The IDE won't matter. Most problems I get are related to libraries and locating them in the proper place.

  23. I am trying out "MultiFeaturedVFO" from

  24. Hi Charudatt ,
    I downloaded the sketch you mentioned from the blog and tried it with my Uno and had no problem.
    I don't know what to say at this point - something is not right! I don't have a Nano to test with but I don't see where it would be a problem.
    You might try adding this line in each "idfef" in setup() under si5351.set_freq():
    si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_8MA); //you can set this to 2MA, 4MA, 6MA or 8MA
    and see if this makes any difference.
    Other than that, make sure you don't have the library loaded into multiple locations. The folder containing si5351.h and si5351.cpp files should only be in the user directory in the "libraries" folder NOT in the "c:\program files\arduino folder". You can check where user installed libraries should be installed by looking at "File -> Preferences -. Sketchbook Location:" User libraries need to be in the subfolder "libraries".
    The main reason for this is if you upgrade the Arduino IDE version you will not write over libraries that you have downloaded in the past.
    Good luck

  25. Hello Tom, I tried your suggestion, deleted all libraries , here and there, followed your step about the libraries folder and burnt the code. and I could only get it working in "#define Direct_conversion //What you see on display is what you get" mode, output on CLK0, if I enable the IF option , I don't get any output , either on ClK0 or Clk2, any particular reason. Thank you for your patience in helping me out. I guess I'm close........ lol

  26. If you enable a #define by removing the "//" in front of it then you must put back the "//" in front of the others. You can have only one of these #defines at a time in the "-- Set Optional Features here --" section.
    The '//' in front of a line means that all the follows is a comment and won't be compiled.

  27. This comment has been removed by a blog administrator.

    1. N3ZI general Covarege Receiver kit for vfo ,bfo and ıf offset code sketch edit help me

  28. There is only one output on the N3ZI VFO. IF offset is already included. Contact N3ZI!

  29. Tom, I thought I'd post this.

    In your comments there is a reference that when using the *example* sketch with the Si5351a breakout that the following results are the correct ones

    SYS_INIT: 1 LOL_A: 1 LOL_B: 1 LOS: 1 REVID: 1

    I believe that to be incorrect. Yes it's what I get when I run the example sketch, but those simply can't be the correct values. If they are, that says that the Sys Init function is *always in initialize status*, and the LOL_A/B are unlocked. Which can't be the case if the device is working.

    I ported the cpp object to an arm with a known working i2c driver - I'm much more comfortable on the ARM platform.

    And I get SYS_INIT: 0 LOL_A: 0 LOL_B: 0 LOS: 1 REVID: 1 Polling the device on 1 second intervals. I believe those to be the correct values. The SysInit is complete, the LOL_A/B are locked. LOS isn't applicable to a 5351A so a 1 there doesn't matter and it would appear that the REVID is 1 .

    I've asked Jason what the correct results would be, but based upon this - I believe it should report a 0,0,0,1,1 instead of 1,1,1,1,1

    Let me know if you agree or if I've done something wrong. I used the example sketch and library on both a Nano and a Mega256 and both returned the 1,1,1,1,1. But if it's putting out frequencies I believe that init, loc_a and loc_b at the minimum should be 0,0,0.

  30. Hello.
    I try to run the sketch for arduino uno but I have a compilation problem. (No matching function for call to 'Si5351 :: init (int, int)'). I tried to see if this was not a bookmarking worry, but nothing did. I come to you to give me some advice. I am a novice in the world of progammation, and my knowledge in this field is very limited. Thank you for your help.

    73's ON4LAU

  31. Hi all.
    I'm getting the same compiling error as ON4LAU. Any assistance would be appreciated! Is there an update to a library or something that this sketch doesn't take into account?

    73 de KB1VNA

    1. Jason has a newer version of his library and I suspect you are using it.
      One difference is the statement:
      si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
      Which used to be just:
      si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
      The third parameter, is the correction factor. If you have no c orrection, or you would like to set it with ' set_correction()', just leave it at '0'

      The other change is the ' set freq()' method which now takes only 2 parameters which would change this statement:
      si5351.set_freq((vfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0);
      to this:
      si5351.set_freq((vfo * SI5351_FREQ_MULT), SI5351_CLK0); which removes the second statement regarding the PLL.
      All is documented here:
      just scroll down to the section: