Definitely not a tube project.

Lately I have been having lots of fun working on a variety of different bench projects, all involving very different technologies, switching between them as parts arrive and time allows. I have been experimenting with space charge tubes, with the goal of building a low voltage regen receiver. Also in progress is a classic VXO controlled CW transmitter, using standard through-hole components. I have had a copy of W1FB’s “QRP Notebook” for two decades, but it is only in the last year or so that I have felt capable enough of trying some of these classic projects. It would be really cool to build a CW transmitter capable of operating on more than one crystal controlled frequency. This might evolve into an actual transceiver some day, who knows?

But very recently I became intrigued when I heard of NT7S, Jason Milldrum`s Indiegogo campaign to crowd fund a breakout board for the SI5351 clock generator chip. This chip has been getting a lot of ham radio press lately. It is capable of generating up to three simultaneous, high precision RF signals, in a range of 1 – 160 MHz. It is easily controlled by any microcontroller or computer which can communicate using the I2C bus standard.

I2C is widely supported, and in particular by the Arduino family of microcontroller boards, and the Raspberry Pi among others. This makes building a DDS VFO totally a snap, and the range of other projects possible is pretty vast.

I jumped in with a contribution for a kit. The campaign exceeded its goals by a wide margin, and soon (beginning of March I think) my board kit arrived. At the time, I was working on some of those other projects, and my only Arduino board was permanently embedded in a completed project (The DFR), so I put the kit aside until I could get my hands on another Arduino to start experimenting.

I decided to commit this new Arduino to permanent, breadboard duty. I will use it for development, and then transfer any code and hardware to a permanent installation with another Arduino, preferably the smallest, cheapest board that will run the code. So, for my breadboard I went all out and bought a Mega 2560. This bad boy has 256kb flash memory, and 4kb SRAM, not likely I will run out of room in my sketches like I did with DFR on the Uno. However, for the SI5351 project I am definitely going to stay to the small-resource end of the line; hopefully the code I wind up with will run on an inexpensive Nano.
(Update: now that the code is done, I got it small enough to run on any Arduino with 32kb flash memory. This includes most of the ATmega328 based boards, but regrettably not the Nano.)

My breadboard is built on an eco-sensitive, sustainable, bamboo cutting board that cost about $5 at our local supermarket. I didn’t know it at the time, but it turns out that bamboo drills very nicely, and is very rigid for its thickness. It makes a very stable platform for the Arduino and surrounding lash-up. On of the things that was a bit annoying working on the DFR project was having the Uno with a tangle of wires going to a separate breadboard – the slightest jostling caused jumpers to fall off, and I dragged the whole thing off the desk more than once by snagging a wire. No, having all the bits anchored to one solid platform makes things much easier.

I recently came across, quite by accident, an article in the December 2013 QST, “Modern Breadboarding Tools and Techniques”  by Richard Barnett, N9NP, where he talks about various breadboarding techniques. I have always thought those plug-in plastic breadboard blocks were basically unusable at RF frequencies, because of all the stray capacitances, but Richard suggests mounting the blocks on copper clad PCB board to provide a good ground plane, and ground the dickens out of it. Also, keep the components connections separated by two or three rows to minimize capacitance from the connectors.

Sounded good to me, so my bamboo breadboard sports two breadboard blocks mounted on PCB. The two sections are well grounded and interconnected by a bridge of PCB which runs under the Arduino. At the time of this writing, I haven’t tried any RF circuits on the breadboard blocks yet, so all the returns are not in. It looks cool, though.

My goal for the SI5351 was to set up a 3-band VFO, with a user interface that would allow selecting the band, and using an encoder to adjust the frequency. This would give a kind of 3 register “memory” effect – each channel on the SI5351 would retain the last frequency setting and jumping between frequencies would just be a matter of pressing a button to select the channel.

One of the really cool things about software defined radio, is that you can write the software without actually having the hardware for the radio. So, even though I hadn’t built the SI5351 breakout board yet, I started right in on the UI with the Arduino breadboard. The user interface would consist of one button to cycle through the three channels, a rotary encoder to adjust the frequency of the current channel up or down, and using the built-in switch on the rotary encoder, a selection of how fast the frequency changes per pulse on the encoder. This would allow easy large excursions, and precise small ones. Nothing is more tedious than moving from 7.0 MHz to 7.2 MHz in at 24 Hz per revolution.

The UI would also have to include some kind of display. I found two inexpensive candidates on Amazon – a 2 line x 20 character LCD, and a tiny but very legible, graphics-capable  OLED display (128×64 pixels), which also uses the I2C bus. I wound up going with the OLED display – it only takes 4 wires to interconnect, as compared to 10 for the LCD (a  parallel rather than serial interface.) Here you can see the entire lash-up including the SI5351 board:

Arduino prototyping board in action.

Arduino prototyping board in action.

Code for the UI came from several sources. I decided to manage the switches by polling them in the Arduino code loop. There is not too much going on in the Arduino in this application, so the code loop doesn’t have to operate too fast. A 50 millisecond loop time was more than sufficiently responsive for the button presses. An additional reason for polling the buttons is that I have some library code developed for the DFR that wraps all the debouncing and polling logic. This code can also distinguish between a short press and a long press on each button – initially I did not plan to make use of this feature, but later decided to add two functions – classic feature creep.

Rather than poll the encoder, I decided to use hardware interrupts to read it. This gives much better resolution and allows handling the encoder at a faster rate than the main code loop. The code I wrote for it was a distillation of several example sketches I found online – it seems to work well in this context with no dropped counts. The encoder I used came from Mouser; it cost less than $2 per piece, and seems to work well. I found a reference to it in another project: N6QW Pete Juliano’s “Belthorn III QRP SSB Transceiver”, (video here) and decided to give it a try. It works very well.

Code for driving the ssd1306  OLED display comes from two Adafruit open source libraries. These libraries also support a wide variety of graphical effects, which I did not take advantage of in this sketch. The only caveat using these libraries is that the code initializes the display with the Adafruit logo – you have to explicitly clear the device before writing anything to display. It was easy to figure out the display calls, looking at the example sketch which pretty much exercises everything in the library.

A note for you programmers out there: interestingly the Adafruit library code does not include the guard macros commonly found at the beginning of the .h include files. These macros prevent redefinition errors if the include file is included in the source code more than once. If you inadvertently do include the Adafruit headers more than once, you will get compile errors that look something like this:

Error when Adafruit ssd1306 includes appear more than once in a sketch

Error when Adafruit ssd1306 includes appear more than once in a sketch

The simple fix is to find and remove all but one set of Adafruit includes.

One other note on the Arduino sketch: I structured this code to make it easy to replace the libraries for driving the display and the SI5351, if you wish to try something else. Reference to all of the third-party code is accomplished via an abstract base class, and an implementation class. For example, the main sketch points to a class called VFODisplay, which defines all of the display functions, but the actual calls to the Adafruit library are in a class derived from VFODisplay called ssd1306_VFODisplay. So, if you if you wanted to use a different display library, or a different type of display altogether, all you need to do is derive a new class from VFODisplay with the appropriate code for your setup defined for each display function.

Okay, if you are not an Arduino programmer, and that last paragraph didn’t make any sense, just ignore it. If you use the same hardware and libraries I used, all will be well.

You can purchase the SI5351 breakout board kit from Jason’s company, etherkit.com. Documentation, and links to the library code for the board kit can be found on this page. Code for the SI5351 chip comes from Jason. It is well documented and it is clear how to drive the chip. Integration into my UI was easy, and the entire set up is working nicely as breadboarded.

Here is a Youtube video with a short demonstration of the “rig”

The code for my sketch hosted on github You can download it here. The easiest way to install it is to download the zip file. Extract the zip file on your computer, and copy the sketch and library folders to your Arduino sketchbook. My code is released under a GPL 2.0 license, you are free to use it and modify it as you like, but anything you do with it must remain open source.

My github repository does not include the other libraries you will need to run the sketch. You can find the device libraries at their respective download locations:

Si5351Arduino from etherkit.com
Adafruit_SSD1306

This really is amazing technology. The path from parts to a very sophisticated VFO has never been shorter.

73,
de N2HTT

This entry was posted in Arduino, Ham Radio and tagged , , , , , , , , , , , , , , , , . Bookmark the permalink.

12 Responses to Definitely not a tube project.

  1. Pingback: More software, less radio. | 73, de N2HTT

  2. Pingback: Triple Frequency VFO on a Bamboo Breadboard | Hackaday

  3. adjoshi says:

    Hi OM N2HTT
    Working on a simple 3 band DCR for new hams of our local Pune club and want to use your 3 band si5351 vfo but with simple 16×2 lcd display. Can you please guide me with the necessary corrections required in the sketch ? Just want to make it a little cheaper for new comers !
    Is it possible to have +5 v BPF switching out put as per band selected on spare arduino pins ?
    Can use i2c 16×2 display also.
    Thanks for a good article , 73 and waiting,
    ashok vu2ash

    • n2htt says:

      Hi Ashok,

      The changes you want to make should be pretty straighforward. There already is code in the sketch to remove the header line from the display. Look in file si5351vfo3b.ino (the main sketch), lines 181 – 182. Change:

      //#define DISPLAY_HEADER_LINE NO_HEADING
      #define DISPLAY_HEADER_LINE SHOW_HEADING

      to read:

      #define DISPLAY_HEADER_LINE NO_HEADING
      //#define DISPLAY_HEADER_LINE SHOW_HEADING

      and that will remove the heading line from the display. You can then squeeze another line out by changing the number of VFOs to 2. Do this by changing line 206 of the same file to read:

      #define NUMBER_OF_VFOS 2

      If you do reduce the number of VFOs, you will have to change the initialization code as well, see the setupVFOs() function in Deviceinitializations.h. Remove the block of code from lines 52 – 57, which configure the third VFO. That should take care of the display.

      You can switch to using the standard LCD parallel interface if you wish – I think the Arduino supplied libraries will work for that. The down side is that the LCD parallel interface consumes a lot of pins, (7 I think,) so you might have an issue with the total pin requirement (unless you run on a Mega). Also, you would have to write an implementation of VFODisplay for the built-in libraries, to use instead of class LCD2004_LCDLib_VFODisplay, which uses the I2C interface. If possible I would stick to the I2C interface, only two pins and no coding required.

      You certainly could control a relay shield for switching in bandpass filters, there are lots of these available that are inexpensive and only require one pin per relay. The VFO switch logic, lines 311 – 328 in the main sketch would be the place to add code to select the relay corresponding to the BPF for that VFO.

      BTW I did some work with another ham trying to squeeze down the code size to get the sketch to run on an Uno using the OLED display, which takes up a lot more code room than the LCD. We finally got it by removing the VFO disable functions at lines 330-341 and 368-382 in the main sketch. If you add relay switching code and start to run out of space, you might consider doing the same.

      Thanks very much for your interest in the sketch, and good luck with your project. Let me know how it goes,

      73
      Mike N2HTT

      • adjoshi says:

        Hi Mike
        Thank you very much for the suggestions, will try them in the sketch and will let you know.
        How ever, would have loved to have third band as well !!
        BTW – I had down loaded your complete zip file, but when I try to compile the main sketch on my uno with 2004 lcd enabled , it stops at line 250 of main sketch for
        “VFODisplay*pDisplay” saying “does name a type” !
        Am I missing some thing ?
        Sorry to bother you, am still learning arduino !!
        Thanks and 73
        ashok vu2ash

  4. adjoshi says:

    Sorry Mike it says “does not name a type ” !

  5. n2htt says:

    HI Ashok,
    This can happen if all the source files are not in the sketch folder – the Arduino IDE is very picky about where everything is located.
    Make sure all of these files are in the sketch folder along with si5351vfo3b.ino:

    DeviceInitializations.h
    FrequencySelection.h
    LCD2004_LCDLIB_VFODisplay.h
    si5351_VFODefinition.h
    SimpleDigitalInputPin.cpp
    SimpleDigitalInputPin.h
    SimpleDigitalPulse.h
    SSD1306_U8GLIB_VFODisplay.h
    VFODefinition.h
    VFODisplay.h

    Also, if there are any subdirectories in the sketch folder itself, they should be removed.

    Let me know how this works out

    73,
    Mike

  6. Yusni says:

    Hi Mr. Mike.
    I am very interested with your sketch.
    I want to ask. How to control the frequency via 4×3 matrix keypad?
    I cant find the frequency control in loop function. So…
    I try to set it via frequency_delta, i set frequency to 0 then multiply via rotary encoder 😀 and i failed. I dont even know how to do that.
    Sorry for my english.
    And sorry again, i m still learning arduino.
    Thanks and 73
    I am Yusni;
    And i from Indonesia

    • n2htt says:

      Hi Yusni,
      Take a look at this tutorial:
      http://forum.arduino.cc/index.php?topic=57627.0
      which shows the solution to reading a number from a keypad.
      If you put in a keypad, I would take out the encoder code – you won’t need it. You can leave out the file FrequencySelection.h, which has the enocoder code in it. Also, I don’t think you will need the frequency multiplier at all, if you are using a keypad to enter the exact frequency.
      Good luck with your project and have fun!
      73
      Mike

  7. Ricardo Trujillo Velez says:

    Hello Mike,
    While trying to compile the sketch, I get the following error:
    Arduino: 1.8.3 (Windows 10), Board: “Arduino/Genuino Uno”

    In file included from F:\Users\RTRUJILLO\Desktop\Ham Radio\VFO\si5351-3-band-vfo-master\si5351vfo3b\si5351vfo3b.ino:161:0:

    sketch\si5351_VFODefinition.h: In member function ‘virtual void si5351_VFODefinition::loadFrequency()’:

    si5351_VFODefinition.h:107: error: no matching function for call to ‘Si5351::set_freq(long long unsigned int, long long unsigned int&, si5351_clock&)’

    si5351.set_freq(((unsigned long long)frequency)*SI5351_FREQ_MULT, si5351PLL, si5351Clock);

    ^

    I understand that from version 1 to 2 of the library, the method has changed, but I can’t get what the new streamlined method is.
    Thanks,
    Ricardo, AB3ZW

    • Ricardo Trujillo Velez says:

      Mike,
      I fell back to version 1 of the library and that did the trick.
      Thanks and 73,
      Ricardo

      • n2htt says:

        Hi Ricardo,
        Yes, a number of folks have run into this, the change from v1 to v2 of the Etherkit library breaks the old code. I will be pushing changes up to the GitHub code that is affected, and will publish a quick note on the blog when the updates are in place.

        Thanks for your interest in the project
        73
        Mik3

Leave a Reply

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

WordPress.com Logo

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

Facebook photo

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

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.