Si5351Arduino
Library for the Si5351 clock generator IC in the Arduino environment
Install / Use
/learn @etherkit/Si5351ArduinoREADME
Si5351 Library for Arduino
This is a library for the Si5351 series of clock generator ICs from Silicon Labs for the Arduino development environment. It will allow you to control the Si5351 with an Arduino, and without depending on the proprietary ClockBuilder software from Silicon Labs.
This library is focused towards usage in RF/amateur radio applications, but it may be useful in other cases. However, keep in mind that coding decisions are and will be made with those applications in mind first, so if you need something a bit different, please do fork this repository.
Please feel free to use the Issues feature of GitHub if you run into problems or have suggestions for important features to implement. This is the best way to get in touch.
Thanks For Your Support!
If you would like to support my library development efforts, I would ask that you please consider purchasing a Si5351A Breakout Board from my online store at etherkit.com sending a one-time PayPal tip, or subscribe to me on Substack for an ongoing contribution. Thank you!
Library Installation
The best way to install the library is via the Arduino Library Manager, which is available if you are using Arduino IDE version 1.6.2 or greater. To install it this way, simply go to the menu Sketch > Include Library > Manage Libraries..., and then in the search box at the upper-right, type "Etherkit Si5351". Click on the entry in the list below, then click on the provided "Install" button. By installing the library this way, you will always have notifications of future library updates, and can easily switch between library versions.
If you need to or would like to install the library in the old way, then you can download a copy of the library in a ZIP file. Download a ZIP file of the library from the GitHub repository by using the "Download ZIP" button at the right of the main repository page. Extract the ZIP file, then rename the unzipped folder as "Si5351". Finally, open the Arduino IDE, select menu Sketch > Import Library... > Add Library..., and select the renamed folder that you just downloaded. Restart the IDE and you should have access to the new library.
Hardware Requirements and Setup
This library has been written for the Arduino platform and has been successfully tested on the Arduino Uno and an Uno clone. There should be no reason that it would not work on any other Arduino hardware with I2C support.
The Si5351 is a +3.3 V only part, so if you are not using a +3.3 V microcontroller, be sure you have some kind of level conversion strategy.
Wire the SDA and SCL pins of the Si5351 to the corresponding pins on the Arduino. Use the pin assignments posted on the Arduino Wire library page. Since the I2C interface is set to 100 kHz, use 1 to 10 kΩ pullup resistors from +3.3 V to the SDA and SCL lines.
Connect a 25 MHz or 27 MHz crystal with a load capacitance of 6, 8, or 10 pF to the Si5351 XA and XB pins. Locate the crystal as close to the Si5351 as possible and keep the traces as short as possible. Please use a SMT crystal. A crystal with leads will have too much stray capacitance.
Changes from v1 to v2
The public interface to the v2 library is similar to the v1 library, but a few of the most-used methods have had their signatures changed, so your old programs won't compile right out-of-the-box after a library upgrade. Most importantly, the init() and set_freq() methods are different, so you'll at least need to change these calls in your old sketches.
The init() method now has three parameters: the crystal load capacitance, the reference frequency, and the frequency correction value (with this last parameter being a new addition). You'll need to add that third parameter to your old init() calls, but then you can delete any set_correction() calls after that (unless you explicitly are changing the frequency correction after the initialization).
The set_freq() method is now more streamlined and only requires two parameters: the desired output frequency (from 4 kHz to 225 MHz) and clock output. In your old code, you can delete the 2nd parameter in set_freq(), which was the PLL frequency. In case you want to do things manually, there is now a new method called set_freq_manual() (see below for details).
Those two changes should cover nearly all upgrade scenarios, unless you were doing some lower-level use of the Si5351.
Example
First, install the Si5351Arduino library into your instance of the Arduino IDE as described above.
There is a simple example named si5351_example.ino that is placed in your examples menu under the Si5351Arduino folder. Open this to see how to initialize the Si5351 and set a couple of the outputs to different frequencies. The commentary below will analyze the sample sketch.
Before you do anything with the Si5351, you will need to include the "si5351.h" and "Wire.h" header files and instantiate the Si5351 class.
#include "si5351.h"
#include "Wire.h"
Si5351 si5351;
Now in the Setup() function, let's initialize communications with the Si5351, specify the load capacitance of the reference crystal, that we want to use the default reference oscillator frequency of 25 MHz (the second argument of "0" indicates that we want to use the default), and that we will apply no frequency correction at this point (the third argument of "0"):
i2c_found = si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
The init() method returns a bool which indicates whether the Arduino can communicate with a device on the I2C bus at the specified address (it does not verify that the device is an actual Si5351, but this is useful for ensuring that I2C communication is working).
Next, let's set the CLK0 output to 14 MHz:
si5351.set_freq(1400000000ULL, SI5351_CLK0);
Frequencies are indicated in units of 0.01 Hz. Therefore, if you prefer to work in 1 Hz increments in your own code, simply multiply each frequency passed to the library by 100ULL (better yet, use the define called SI5351_FREQ_MULT in the header file for this multiplication).
In the main Loop(), we use the Serial port to monitor the status of the Si5351, using a method to update a public struct which holds the status bits:
si5351.update_status();
Serial.print("SYS_INIT: ");
Serial.print(si5351.dev_status.SYS_INIT);
Serial.print(" LOL_A: ");
Serial.print(si5351.dev_status.LOL_A);
Serial.print(" LOL_B: ");
Serial.print(si5351.dev_status.LOL_B);
Serial.print(" LOS: ");
Serial.print(si5351.dev_status.LOS);
Serial.print(" REVID: ");
Serial.println(si5351.dev_status.REVID);
When the synthesizers are locked and the Si5351 is working correctly, you'll see an output similar to this one (the REVID may be different):
SYS_INIT: 0 LOL_A: 0 LOL_B: 0 LOS: 0 REVID: 3
The nominal status for each of those flags is a 0. When the program indicates 1, there may be a reference clock problem, tuning problem, or some kind of other issue. (Note that it may take the Si5351 a bit of time to return the proper status flags, so in program initialization issue update_status() and then give the Si5351 a few hundred milliseconds to initialize before querying the status flags again.)
A Brief Word about the Si5351 Architecture
The Si5351 consists of two main stages: two PLLs which are locked to the reference oscillator (a 25/27 MHz crystal) and which can be set from 600 to 900 MHz, and the output (multisynth) clocks which are locked to a PLL of choice and can be set from 500 kHz to 200 MHz (per the datasheet, although it does seem to be possible to set an output up to 225 MHz).
The B variant has an additional VCXO stage with control voltage pin which can be used as a reference synth for a clock output (PLLB must be used as the source for any VCXO output clock).
The C variant is able to take a reference clock input from 10 to 100 MHz separate from the standard crystal reference. If using this reference input, be sure to initialize the library with the correct frequency.
This library makes PLL assignments based on ease of use. They can be changed manually if needed, although that can introduce complications (see Manually Selecting a PLL Frequency below).
Setting the Output Frequency
As indicated above, the library accepts and indicates clock and PLL frequencies in units of 0.01 Hz, as an unsigned long long variable type (or uint64_t). When entering literal values, append ULL to make an explicit unsigned long long number to ensure proper tuning. Since many applications won't require sub-Hertz tuning, you may wish to use an unsigned long (or uint32_t) variable to hold your tune frequency, then scale it up by multiplying by 100ULL before passing it to the set_freq() method.
Using the set_freq() method is the easiest way to use the library and gives you a wide range of tuning options, but has some constraints in its usage. Outputs CLK0 through CLK5 by default are all locked to PLLA while CLK6 and CLK7 are locked to PLLB. Due to the nature of the Si5351 architecture, there may only be one CLK output among those sharing a PLL which may be set greater than 100 MHz (actually specified at 112.5 MHz by SiLabs, but stability issues have been found at the upper end). Therefore, once one CLK output has been set above 100 MHz, no more CLKs on the same PLL will be allowed to be set greater than 100 MHz (unless the one which is already set is changed to a frequency below this threshold).
If the above constraints are not suitable, you need glitch-free tuning, or you are counting on multiple clocks being locked to the same reference, you may set the PLL fr
