Giter Club home page Giter Club logo

si5351arduino's Introduction

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 SubscribeStar 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 frequency manually then make clock reference assignments to either of the PLLs.

Manually Selecting a PLL Frequency

Instead of letting the library choose a PLL frequency for your chosen output frequency, you can choose it yourself in the set_freq_manual() method. This method is similar to set_freq(), but the second argument is the desired PLL frequency:

si5351.set_freq_manual(19800000000ULL, 79200000000ULL, SI5351_CLK0);

If you use this method (or the other methods to tweak the PLL and multisynth settings manually), it is very important to remember that the library will no longer properly track the PLL and multisynth settings and that you alone will be responsible for keeping the synths tuned properly. Strange things can happen to your other outputs if they are already in use. Be sure to read the Si5351 datasheet and Silicon Labs AN619 before doing this so that you understand what you are doing.

When you are setting the PLL manually you need to be mindful of the limits of the IC. The multisynth (MS0 through MS5) is a fractional PLL, with limits described in AN619 as:

Valid Multisynth divider ratios are 4, 6, 8, and any fractional value between 8 + 1/1,048,575 and 900 + 0/1. This means that if any output is greater than 112.5 MHz (900 MHz/8), then this output frequency sets one of the VCO frequencies.

To put this in other words, if you want to manually set the PLL and wish to have an output frequency greater than 100 MHz (changed in this library from the stated 112.5 MHz due to stability issues which were noticed), then the choice of PLL frequency is dictated by the choice of output frequency, and will need to be an even multiple of 4, 6, or 8.

Further Details

If we like we can adjust the output drive power:

si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_4MA);

The drive strength is the amount of current into a 50Ω load. 2 mA roughly corresponds to 3 dBm output and 8 mA is approximately 10 dBm output.

Individual outputs can be turned on and off. In the second argument, use a 0 to disable and 1 to enable:

si5351.output_enable(SI5351_CLK0, 0);

You may invert a clock output signal by using this command:

si5351.set_clock_invert(SI5351_CLK0, 1);

Calibration

There will be some inherent error in the reference oscillator's actual frequency, so we can account for this by measuring the difference between the uncalibrated actual and nominal output frequencies, then using that difference as a correction factor in the library. The init() and set_correction() methods use a signed integer calibration constant measured in parts-per-billion. The easiest way to determine this correction factor is to measure a 10 MHz signal from one of the clock outputs (in Hz, or better resolution if you can measure it), scale it to parts-per-billion, then use it in the set_correction() method in future use of this particular reference oscillator. Once this correction factor is determined, it should not need to be measured again for the same reference oscillator/Si5351 pair unless you want to redo the calibration. With an accurate measurement at one frequency, this calibration should be good across the entire tuning range.

The calibration method is called like this:

si5351.set_correction(-6190, SI5351_PLL_INPUT_XO);

However, you may use the third argument in the init() method to specify the frequency correction and may not actually need to use the explict set_correction() method in your code.

A handy calibration program is provided with the library in the example folder named si5351_calibration. To use it, simply hook up your Arduino to your Si5351, then connect it to a PC with the Arduino IDE. Connect the CLK0 output of the Si5351 to a frequency counter capable of measuring at 10 MHz (the more resolution, the better). Load the sketch then open the serial terminal window. Follow the prompts in the serial terminal to change the output frequency until your frequency counter reads exactly 10.000 000 00 MHz. The output from the Arduino on your serial terminal will tell you the correction factor you will need for future use of that reference oscillator/Si5351 combination.

One thing to note: the library is set for a 25 MHz reference crystal. If you are using a 27 MHz crystal, use the second parameter in the init() method to specify that as the reference oscillator frequency.

Phase

Please see the example sketch si5351_phase.ino

The phase of the output clock signal can be changed by using the set_phase() method. Phase is in relation to (and measured against the period of) the PLL that the output multisynth is referencing. When you change the phase register from its default of 0, you will need to keep a few considerations in mind.

Setting the phase of a clock requires that you manually set the PLL and take the PLL frequency into account when calculation the value to place in the phase register. As shown on page 10 of Silicon Labs Application Note 619 (AN619), the phase register is a 7-bit register, where a bit represents a phase difference of 1/4 the PLL period. Therefore, the best way to get an accurate phase setting is to make the PLL an even multiple of the clock frequency, depending on what phase you need.

If you need a 90 degree phase shift (as in many RF applications), then it is quite easy to determine your parameters. Pick a PLL frequency that is an even multiple of your clock frequency (remember that the PLL needs to be in the range of 600 to 900 MHz). Then to set a 90 degree phase shift, you simply enter that multiple into the phase register. Remember when setting multiple outputs to be phase-related to each other, they each need to be referenced to the same PLL.

You can see this in action in a sketch in the examples folder called si5351phase. It shows how one would set up an I/Q pair of signals at 14.1 MHz.

// We will output 14.1 MHz on CLK0 and CLK1.
// A PLLA frequency of 705 MHz was chosen to give an even
// divisor by 14.1 MHz.
unsigned long long freq = 1410000000ULL;
unsigned long long pll_freq = 70500000000ULL;

// Set CLK0 and CLK1 to output 14.1 MHz with a fixed PLL frequency
si5351.set_freq_manual(freq, pll_freq, SI5351_CLK0);
si5351.set_freq_manual(freq, pll_freq, SI5351_CLK1);

// Now we can set CLK1 to have a 90 deg phase shift by entering
// 50 in the CLK1 phase register, since the ratio of the PLL to
// the clock frequency is 50.
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK1, 50);

// We need to reset the PLL before they will be in phase alignment
si5351.pll_reset(SI5351_PLLA);

CLK Output Options

Please see the example sketch si5351_outputs.ino

In most cases, you will most likely end up using the multisynth associated with a CLK output, but the Si5351 has some other options available as well. The reference clocks (both the crystal oscillator and the CLKIN signal) can be mirrored to any CLK output. Also CLK1 through CLK3 can mirror the MS0 (CLK0) output, and likewise the CLK5 through CLK7 outputs can mirror the MS4 (CLK4) output.

If you choose to use one or more of these output options, you first need to enable the fanout option for that particular signal:

// Enable clock fanout for the XO
si5351.set_clock_fanout(SI5351_FANOUT_XO, 1);

Once that is done, you can use the set_clock_source() method to choose the output option you desire. Since the CLK outputs by default are turned off, you may need to turn your CLK output on as well:

// Set CLK1 to output the XO signal
si5351.set_clock_source(SI5351_CLK1, SI5351_CLK_SRC_XTAL);
si5351.output_enable(SI5351_CLK1, 1);

Using the VCXO (Si5351B)

Please see the example sketch si5351_vcxo.ino

The Si5351B variant has a VCXO feature which can be used to provide voltage-tunable clock outputs, with a voltage control input on pin 3 of the IC. This functionality is provided on the PLLB oscillator internal to the Si5351, so you must assign any clock outputs that you wish to voltage control to PLLB.

The library has a method named set_vcxo() that allows you to set the PLLB frequency and the amount of pull range that you wish to use on that oscillator (from 30 to 240 parts-per-million). Using the VCXO is similar to manually setting an output frequency. First, call the set_vcxo() method:

#define PLLB_FREQ    87600000000ULL

// Set VCXO osc to 876 MHz (146 MHz x 6), 40 ppm pull
si5351.set_vcxo(PLLB_FREQ, 40);

Next, we assign the desired VCXO clock output to PLLB:

// Set CLK0 to be locked to VCXO
si5351.set_ms_source(SI5351_CLK0, SI5351_PLLB);

Finally, we use the set_freq_manual() method to set the clock output center frequency:

// Tune to 146 MHz center frequency
si5351.set_freq_manual(14600000000ULL, PLLB_FREQ, SI5351_CLK0);

Using an External Reference (Si5351C)

Please see the example sketch si5351_ext_ref.ino

The Si5351C variant has a CLKIN input (pin 6) which allows the use of an alternate external CMOS clock reference from 10 to 100 MHz. Either PLLA and/or PLLB can be locked to this external reference. The library tracks the referenced frequencies and correction factors individually for both the crystal oscillator reference (XO) and external reference (CLKIN).

The XO reference frequency is set during the call to init(). If you are going to use the external reference clock, then set its nominal frequency with the set_ref_freq() method:

// Set the CLKIN reference frequency to 10 MHz
si5351.set_ref_freq(10000000UL, SI5351_PLL_INPUT_CLKIN);

A correction factor for the external reference clock may also now be set:

// Apply a correction factor to CLKIN
si5351.set_correction(0, SI5351_PLL_INPUT_CLKIN);

The set_pll_input() method is used to set the desired PLLs to reference to the external reference signal on CLKIN instead of the XO signal:

// Set PLLA and PLLB to use the signal on CLKIN instead of the XTAL
si5351.set_pll_input(SI5351_PLLA, SI5351_PLL_INPUT_CLKIN);
si5351.set_pll_input(SI5351_PLLB, SI5351_PLL_INPUT_CLKIN);

Once that is set, the library can be used as you normally would, with all of the frequency calculations done based on the reference frequency set in set_ref_freq().

Alternate I2C Addresses

The standard I2C bus address for the Si5351 is 0x60, however there are other ICs in the wild that use alternate bus addresses. In order to accommodate these ICs, the class constructor can be called with the I2C bus address as a parameter, as shown in this example:

Si5351 si5351(0x61);

Startup Conditions

This library initializes the Si5351 parameters to the following values upon startup and on reset:

Multisynths 0 through 5 (and hence the matching clock outputs CLK0 through CLK5) are assigned to PLLA, while Multisynths 6 and 7 are assigned to PLLB.

PLLA and PLLB are set to 800 MHz (also defined as SI5351_PLL_FIXED in the library).

All CLK outputs are set to 0 Hz and disabled.

Default drive strength is 2 mA on each output.

Constraints

  • Two multisynths cannot share a PLL with when both outputs are >= 100 MHz. The library will refuse to set another multisynth to a frequency in that range if another multisynth sharing the same PLL is already within that frequency range.
  • Setting phase will be limited in the extreme edges of the output tuning ranges. Because the phase register is 7-bits in size and is denominated in units representing 1/4 the PLL period, not all phases can be set for all output frequencies. For example, if you need a 90° phase shift, the lowest frequency you can set it at is 4.6875 MHz (600 MHz PLL/128).
  • The frequency range of Multisynth 6 and 7 is ~18.45 kHz to 150 MHz. The library assigns PLLB to these two multisynths, so if you choose to use both, then both frequencies must be an even divisor of the PLL frequency (between 6 and 254), so plan accordingly. You can see the current PLLB frequency by accessing the pllb_freq public member.
  • VCXO pull range can be ±30 to ±240 ppm

Public Methods

init()

/*
 * init(uint8_t xtal_load_c, uint32_t ref_osc_freq, int32_t corr)
 *
 * Setup communications to the Si5351 and set the crystal
 * load capacitance.
 *
 * xtal_load_c - Crystal load capacitance. Use the SI5351_CRYSTAL_LOAD_*PF
 * defines in the header file
 * xo_freq - Crystal/reference oscillator frequency in 1 Hz increments.
 * Defaults to 25000000 if a 0 is used here.
 * corr - Frequency correction constant in parts-per-billion
 *
 * Returns a boolean that indicates whether a device was found on the desired
 * I2C address.
 *
 */
bool Si5351::init(uint8_t xtal_load_c, uint32_t ref_osc_freq, uint32_t ref_osc_freq)

reset()

/*
 * reset(void)
 *
 * Call to reset the Si5351 to the state initialized by the library.
 *
 */
void Si5351::reset(void)

set_freq()

/*
 * set_freq(uint64_t freq, enum si5351_clock clk)
 *
 * Sets the clock frequency of the specified CLK output
 *
 * freq - Output frequency in Hz
 * clk - Clock output
 *   (use the si5351_clock enum)
 */
uint8_t Si5351::set_freq(uint64_t freq, enum si5351_clock clk)

set_freq_manual()

/*
 * set_freq_manual(uint64_t freq, uint64_t pll_freq, enum si5351_clock clk)
 *
 * Sets the clock frequency of the specified CLK output using the given PLL
 * frequency. You must ensure that the MS is assigned to the correct PLL and
 * that the PLL is set to the correct frequency before using this method.
 *
 * It is important to note that if you use this method, you will have to
 * track that all settings are sane yourself.
 *
 * freq - Output frequency in Hz
 * pll_freq - Frequency of the PLL driving the Multisynth in Hz * 100
 * clk - Clock output
 *   (use the si5351_clock enum)
 */

set_pll()

/*
 * set_pll(uint64_t pll_freq, enum si5351_pll target_pll)
 *
 * Set the specified PLL to a specific oscillation frequency
 *
 * pll_freq - Desired PLL frequency in Hz * 100
 * target_pll - Which PLL to set
 *     (use the si5351_pll enum)
 */
void Si5351::set_pll(uint64_t pll_freq, enum si5351_pll target_pll)

set_ms()

/*
 * set_ms(enum si5351_clock clk, struct Si5351RegSet ms_reg, uint8_t int_mode, uint8_t r_div, uint8_t div_by_4)
 *
 * Set the specified multisynth parameters. Not normally needed, but public for advanced users.
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * int_mode - Set integer mode
 *  Set to 1 to enable, 0 to disable
 * r_div - Desired r_div ratio
 * div_by_4 - Set Divide By 4 mode
 *   Set to 1 to enable, 0 to disable
 */
void Si5351::set_ms(enum si5351_clock clk, struct Si5351RegSet ms_reg, uint8_t int_mode, uint8_t r_div, uint8_t div_by_4)

output_enable()

/*
 * output_enable(enum si5351_clock clk, uint8_t enable)
 *
 * Enable or disable a chosen output
 * clk - Clock output
 *   (use the si5351_clock enum)
 * enable - Set to 1 to enable, 0 to disable
 */
void Si5351::output_enable(enum si5351_clock clk, uint8_t enable)

drive_strength()

/*
 * drive_strength(enum si5351_clock clk, enum si5351_drive drive)
 *
 * Sets the drive strength of the specified clock output
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * drive - Desired drive level
 *   (use the si5351_drive enum)
 */
void Si5351::drive_strength(enum si5351_clock clk, enum si5351_drive drive)

update_status()

/*
 * update_status(void)
 *
 * Call this to update the status structs, then access them
 * via the dev_status and dev_int_status global variables.
 *
 * See the header file for the struct definitions. These
 * correspond to the flag names for registers 0 and 1 in
 * the Si5351 datasheet.
 */
void Si5351::update_status(void)

set_correction()

/*
 * set_correction(int32_t corr, enum si5351_pll_input ref_osc)
 *
 * corr - Correction factor in ppb
 * ref_osc - Desired reference oscillator
 *     (use the si5351_pll_input enum)
 *
 * Use this to set the oscillator correction factor.
 * This value is a signed 32-bit integer of the
 * parts-per-billion value that the actual oscillation
 * frequency deviates from the specified frequency.
 *
 * The frequency calibration is done as a one-time procedure.
 * Any desired test frequency within the normal range of the
 * Si5351 should be set, then the actual output frequency
 * should be measured as accurately as possible. The
 * difference between the measured and specified frequencies
 * should be calculated in Hertz, then multiplied by 10 in
 * order to get the parts-per-billion value.
 *
 * Since the Si5351 itself has an intrinsic 0 PPM error, this
 * correction factor is good across the entire tuning range of
 * the Si5351. Once this calibration is done accurately, it
 * should not have to be done again for the same Si5351 and
 * crystal.
 */
void Si5351::set_correction(int32_t corr, enum si5351_pll_input ref_osc)

set_phase()

/*
 * set_phase(enum si5351_clock clk, uint8_t phase)
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * phase - 7-bit phase word
 *   (in units of VCO/4 period)
 *
 * Write the 7-bit phase register. This must be used
 * with a user-set PLL frequency so that the user can
 * calculate the proper tuning word based on the PLL period.
 */
void Si5351::set_phase(enum si5351_clock clk, uint8_t phase)

get_correction()

/*
 * get_correction(enum si5351_pll_input ref_osc)
 *
 * ref_osc - Desired reference oscillator
 *     0: crystal oscillator (XO)
 *     1: external clock input (CLKIN)
 *
 * Returns the oscillator correction factor stored
 * in RAM.
 */
int32_t Si5351::get_correction(enum si5351_pll_input ref_osc)

pll_reset()

/*
 * pll_reset(enum si5351_pll target_pll)
 *
 * target_pll - Which PLL to reset
 *     (use the si5351_pll enum)
 *
 * Apply a reset to the indicated PLL.
 */
void Si5351::pll_reset(enum si5351_pll target_pll)

set_ms_source()

/*
 * set_ms_source(enum si5351_clock clk, enum si5351_pll pll)
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * pll - Which PLL to use as the source
 *     (use the si5351_pll enum)
 *
 * Set the desired PLL source for a multisynth.
 */
void Si5351::set_ms_source(enum si5351_clock clk, enum si5351_pll pll)

set_int()

/*
 * set_int(enum si5351_clock clk, uint8_t int_mode)
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * enable - Set to 1 to enable, 0 to disable
 *
 * Set the indicated multisynth into integer mode.
 */
void Si5351::set_int(enum si5351_clock clk, uint8_t enable)

set_clock_pwr()

/*
 * set_clock_pwr(enum si5351_clock clk, uint8_t pwr)
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * pwr - Set to 1 to enable, 0 to disable
 *
 * Enable or disable power to a clock output (a power
 * saving feature).
 */
void Si5351::set_clock_pwr(enum si5351_clock clk, uint8_t pwr)

set_clock_invert()

/*
 * set_clock_invert(enum si5351_clock clk, uint8_t inv)
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * inv - Set to 1 to enable, 0 to disable
 *
 * Enable to invert the clock output waveform.
 */
void Si5351::set_clock_invert(enum si5351_clock clk, uint8_t inv)

set_clock_source()

/*
 * set_clock_source(enum si5351_clock clk, enum si5351_clock_source src)
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * src - Which clock source to use for the multisynth
 *   (use the si5351_clock_source enum)
 *
 * Set the clock source for a multisynth (based on the options
 * presented for Registers 16-23 in the Silicon Labs AN619 document).
 * Choices are XTAL, CLKIN, MS0, or the multisynth associated with
 * the clock output.
 */
void Si5351::set_clock_source(enum si5351_clock clk, enum si5351_clock_source src)

set_clock_disable()

/*
 * set_clock_disable(enum si5351_clock clk, enum si5351_clock_disable dis_state)
 *
 * clk - Clock output
 *   (use the si5351_clock enum)
 * dis_state - Desired state of the output upon disable
 *   (use the si5351_clock_disable enum)
 *
 * Set the state of the clock output when it is disabled. Per page 27
 * of AN619 (Registers 24 and 25), there are four possible values: low,
 * high, high impedance, and never disabled.
 */
void Si5351::set_clock_disable(enum si5351_clock clk, enum si5351_clock_disable dis_state)

set_clock_fanout()

/*
 * set_clock_fanout(enum si5351_clock_fanout fanout, uint8_t enable)
 *
 * fanout - Desired clock fanout
 *   (use the si5351_clock_fanout enum)
 * enable - Set to 1 to enable, 0 to disable
 *
 * Use this function to enable or disable the clock fanout options
 * for individual clock outputs. If you intend to output the XO or
 * CLKIN on the clock outputs, enable this first.
 *
 * By default, only the Multisynth fanout is enabled at startup.
 */
void Si5351::set_clock_fanout(enum si5351_clock_fanout fanout, uint8_t enable)

set_pll_input()

/*
 * set_pll_input(enum si5351_pll pll, enum si5351_pll_input input)
 *
 * pll - Which PLL to use as the source
 *     (use the si5351_pll enum)
 * input - Which reference oscillator to use as PLL input
 *     (use the si5351_pll_input enum)
 *
 * Set the desired reference oscillator source for the given PLL.
 */
void Si5351::set_pll_input(enum si5351_pll pll, enum si5351_pll_input input)

set_vcxo()

/*
 * set_vcxo(uint64_t pll_freq, uint8_t ppm)
 *
 * pll_freq - Desired PLL base frequency in Hz * 100
 * ppm - VCXO pull limit in ppm
 *
 * Set the parameters for the VCXO on the Si5351B.
 */
void Si5351::set_vcxo(uint64_t pll_freq, uint8_t ppm)

set_ref_freq()

/*
 * set_ref_freq(uint32_t ref_freq, enum si5351_pll_input ref_osc)
 *
 * ref_freq - Reference oscillator frequency in Hz
 * ref_osc - Which reference oscillator frequency to set
 *    (use the si5351_pll_input enum)
 *
 * Set the reference frequency value for the desired reference oscillator
 */
void Si5351::set_ref_freq(uint32_t ref_freq, enum si5351_pll_input ref_osc)

si5351_write_bulk()

uint8_t Si5351::si5351_write_bulk(uint8_t addr, uint8_t bytes, uint8_t *data)

si5351_write()

uint8_t Si5351::si5351_write(uint8_t addr, uint8_t data)

si5351_read()

uint8_t Si5351::si5351_read(uint8_t addr)

Public Variables

struct Si5351Status dev_status;
struct Si5351IntStatus dev_int_status;
enum si5351_pll pll_assignment[8];
uint64_t clk_freq[8];
uint64_t plla_freq;
uint64_t pllb_freq;
uint32_t xtal_freq;

Tokens

Here are the defines, structs, and enumerations you will find handy to use with the library.

Crystal load capacitance:

SI5351_CRYSTAL_LOAD_0PF
SI5351_CRYSTAL_LOAD_6PF
SI5351_CRYSTAL_LOAD_8PF
SI5351_CRYSTAL_LOAD_10PF

Clock outputs:

enum si5351_clock {SI5351_CLK0, SI5351_CLK1, SI5351_CLK2, SI5351_CLK3,
  SI5351_CLK4, SI5351_CLK5, SI5351_CLK6, SI5351_CLK7};

PLL sources:

enum si5351_pll {SI5351_PLLA, SI5351_PLLB};

Drive levels:

enum si5351_drive {SI5351_DRIVE_2MA, SI5351_DRIVE_4MA, SI5351_DRIVE_6MA, SI5351_DRIVE_8MA};

Clock sources:

enum si5351_clock_source {SI5351_CLK_SRC_XTAL, SI5351_CLK_SRC_CLKIN, SI5351_CLK_SRC_MS0, SI5351_CLK_SRC_MS};

Clock disable states:

enum si5351_clock_disable {SI5351_CLK_DISABLE_LOW, SI5351_CLK_DISABLE_HIGH, SI5351_CLK_DISABLE_HI_Z, SI5351_CLK_DISABLE_NEVER};

Clock fanout:

enum si5351_clock_fanout {SI5351_FANOUT_CLKIN, SI5351_FANOUT_XO, SI5351_FANOUT_MS};

PLL input sources:

enum si5351_pll_input{SI5351_PLL_INPUT_XO, SI5351_PLL_INPUT_CLKIN};

Status register:

struct Si5351Status
{
  uint8_t SYS_INIT;
  uint8_t LOL_B;
  uint8_t LOL_A;
  uint8_t LOS;
  uint8_t REVID;
};

Interrupt register:

struct Si5351IntStatus
{
  uint8_t SYS_INIT_STKY;
  uint8_t LOL_B_STKY;
  uint8_t LOL_A_STKY;
  uint8_t LOS_STKY;
};

Raw Commands

If you need to read and write raw data to the Si5351, there is public access to the library's read(), write(), and write_bulk() methods.

Unsupported Features

This library does not currently support the spread spectrum function of the Si5351.

Changelog

  • v2.1.4

    • Fix warning "reg may be uninitialized"
  • v2.1.3

    • Correct error in si5351_example.ino sketch
  • v2.1.2

    • Correct error in si5351_calibration.ino sketch
  • v2.1.1

    • Add bool return value to init() indicating whether a device is on the I2C bus
  • v2.1.0

    • Add support for reference frequencies and corrections for both the XO and CLKIN
  • v2.0.7

    • Change set_freq() behavior so that the output is only automatically enabled the very first time that set_freq() is called
  • v2.0.6

    • Call set_pll() in set_correction() to ensure that the new correction factor is applied
  • v2.0.5

    • Remove PLL reset from set_freq() when not necessary
  • v2.0.4

    • Fix error in VCXO algorithm
  • v2.0.3

    • Fix regression in set_freq() that wiped out proper R div setting, causing errors in setting low frequency outputs
  • v2.0.2

    • Increase maximum frequency in set_freq() to 225 MHz
    • Change SI5351_MULTISYNTH_SHARE_MAX from 112.5 MHz to 100 MHz due to stability issues
    • Add explicit reset of VCXO param in reset()
    • Add I2C bus address parameter and default to class constructor
    • Update si5351_calibration example sketch
  • v2.0.1

    • Fix logic error in set_freq() which causes errors in setting multiple clocks >100 MHz
  • v2.0.0

    • Complete rewrite of tuning algorithm
    • Add support for setting CLK6 and CLK7
    • Add support for VCXO (on Si5351B)
    • Change interface of init() and set_freq()
    • Add set_freq_manual() method
    • Add reset() method
    • Added many new example sketches
  • v1.1.2

    • Fix error where register 183 is not pre-loaded with correct value per AN619. Add define for SI5351_CRYSTAL_LOAD_0PF (undocumented in AN619 but present in the official ClockBuilder software).
  • v1.1.1

    • Fix if statement eval error in set_clock_disable()
  • v1.1.0

    • Added set_pll_input() method to allow toggling the PLL reference source for the Si5351C variant and added support to init() for different PLL reference frequencies from 10 to 100 MHz.
  • v1.0.0

    • Initial release

si5351arduino's People

Contributors

frankboesing avatar imabug avatar nt7s avatar pwarren avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

si5351arduino's Issues

New/alternative method for exact solutions for PLL and multisync ratios

Is your feature request related to a problem? Please describe.
The current method for finding the PLL and multisync ratios for register values are based on some hardcoded values that leads to (rounding) errors between the desired frequency and what gets set. Enclosed is a computationally cheap approach to find values for the dividers that (1) allow you to set the integer bit on the output divider and (2) give you the exact values needed for a given frequency. It works for one or two clocks on a PLL.

Describe the solution you'd like
Either update the functions the calculate the PLL and multisync values, or add a new function for "enhanced_accuracy_set_freq" or something like that.

The current method sets the PLL to 800 MHz then finds approximate values for the A+B/C output divider ratios to set the correct frequency by setting C=RFRAC_DENOM. That can work for many situations, but introduces error on the order of Vxtal/RFRAC_DENOM. For the same computational effort, you can find exact solutions. Below is a demonstration of how using a single clock on a PLL, then I'll show with 2 clocks per PLL.

Single Clock per PLL, exact solution, set integer divide bit on multisync output divider

Fundamentally, this is the equation that governs the 5351:

600 MHz < Fout*x1/y1 = Fxtal*x2/y2 < 900 MHz

I just use x1/y1 instead of A +B/C for simplicity. x1,y1,x2, and y2 are all integers, and y1, y2 < 1,048,575. We're also told that we should try to make as many output dividers integers (even better if they are even integers so we can set the integer bit!) So let's rewrite it as:

600 MHz < Fout*A1 = Fxtal*x2/y2 < 900 MHz

Where A1 is the output divisor that we'll make sure is an even integer. Here's the pseudocode that is explained in more detail below:

A1 = floor(900e6/Fout0)

COMMON_SCALING_FACTOR=gcd(Fout, Fxtal) // greatest common denominator
// see text below for a computationally faster way, you don't really need the gcd, any common factor will do.

y2 = min(Fxtal/COMMON_SCALING_FACTOR, 1048757)
// The above accounts for requesting Fouts such that y1,y2 > 1048757. Only happens when Fout's precision is on the order
// of 3 Hz. So it should rarely happen.
// However, if you want the exact solution: follow steps below for "fractional divide" below.

x2 = Fout*A1*y2/Fxtal

PLL Feedback Equation:
A+B/C
A=floor(x2, y2)
B = x2 % y2
C = y2

Multisynth Output Divider
A+B/C
A = A1
B = 0
C = 1
You can set the even integer divide bit!

Example

In this example, we'll make an output at Fout=7.1MHz using a Fxtal=27 MHz crystal.

  1. Find A1. A1= round down to the nearest even integer (900MHz/Fout). To do that, first pick your Fco. Let's say close to 900 MHz (Si does that for their clockbuilder pro, so we can too).
A1 < 900MHz/7.1MHz
A1 < 126.76
A1 = 126
  1. Next, we find y2 using y2 = Fxtal/COMMON_SCALING_FACTOR where COMMON_SCALING_FACTOR is any integer that goes into Fxtal and Fout an integer number of times. Doing that guarantees that y2 is an integer and that Fout*y2/Fxta=x2 is an integer. How do you find that? Two ways:
    1. Fast way: make COMMON_SCALING_FACTOR=10^something such that you just drop out all those zeros you don't need. In our case. Fxtal = 27,000,000 and Fout=7,100,000, so make COMMON_SCALING_FACTOR=10,000 so you get two integers when you divide Fout and Fxtal by COMMON_SCALING_FACTOR: 7,100,000/COMMON_SCALING_FACTOR=71 and 27,000,000/COMMON_SCALING_FACTOR=270. Then y2 = Fxtal/COMMON_SCALING_FACTOR=270
    2. Slowest computationally, but you can exactly find the maximum COMMON_SCALING_FACTOR - which is also known as the greatest common denominator between the two. But it's slow. y2 = Fxtal/gcd(Fout,Fxtal) where gcd is the greatest common denominator using tricks like Euclidian Expansion. In this case, gcd = 10,000, just a coincidence that it's what we choose above.
  2. Now you can find x2 = Fout*A1/(Fxtal/y2)=7.1e6*126/(27e6/270)=8946
  3. Finally, you care write the exact solution!
PLL feedback ration values:
A+B/C = x1/y1 = A1 = 126
A = 126 (we can set the integer divide bit!)
B = 0
C = 1

Multisynth equation
A+B/C = x2/y2 = 8946/270
A = floor(8946, 270) = 31
B = 8946 % 270 = 36
C = 270
A+B/C = 31 + 36/270

You have to make sure that y2<=1,048,757. If it doesn't, see the next section

Single Clock per PLL, exact solution, fractional divide on multisync output (if you really want Hz level precision)

  1. You have to make sure that y2<=1,048,757 If a Fout was chosen such that y2>1,048,757 (that happens if you want a lot of precision in your output frequency), you can either:
    1. just go and put a hard cap on y2 = 1,048,757 and accept the tiny error (on the order of 3 Hz)
    2. or you get an exact solution, but lose out on using the scaling multiplier for A1. In that case, you don't need to find a COMMON_SCALING_FACTOR anymore. Instead just do the following:
y1 = Fout/INTEGER_FACTOR1
x1 = 900e6*/INTEGER_FACTOR1  <-- needs to be an integer. If you choose INTEGER_FACTOR1 to be 10^something, this will be an integer too!
Multisynth output equation:
A+B/C
A = floor(x1, y1)
B = x1 % y1
C = y1

where INTEGER_FACTOR1 is any integer that also makes y1 an integer such that y1 < 1,048,757 and is wholly divisible into 900 MHz. That makes it easy - you can pick 10^something. And you can do the same thing with the feedback equation

y2 = Fxctl / INTEGER_FACTOR2
x2 = 900e6*/INTEGER_FACTOR2
PLL feedback equation:
A+B/C
A =floor(x2, y2)
B = x2 % y2
C = y1

where INTEGER_FACTOR2 is any integer that also makes y2 an integer such that y2 < 1,048,757 and is wholly divisible into 900 MHz. That makes it easy - you can pick 10^something.

Multiple clocks per PLL, exact solution, at least 1 integer divide multisync output (maybe both if you are lucky!)

Now we have 2 Fouts (you can extend this to as many Fouts per PLL that you'd like, follow the same exact proceedure):

600 MHz <  Fout0*x0/y0 = Fout1*x1/y1 = Fxtal*x2/y2 < 900 MHz

We'll guarantee that at least 1 output can set the multisynth even integer divide bit (where Fout0 < Fout1)

600 MHz <  Fout0*A0 = Fout1*x1/y1 = Fxtal*x2/y2 < 900 MHz

We go through the same process as above

A0 = floor(900e6/Fout0)

Find the COMMON_SCALING_FACTOR between Fout0, Fout1, Fxtal either by:
SLOW method: COMMON_SCALING_FACTOR=gcd(gcd(Fout0,Fout1),Fxtal)
FAST method: COMMON_SCALING_FACTOR = 10^something that gets us the right significant figures
such that COMMON_SCALING_FACTOR wholy divides into Fout0, Fout1, and Fxtal

y1 = min(Fout1/COMMON_SCALING_FACTOR, 1048757)
y2 = min(Fxtal/COMMON_SCALING_FACTOR, 1048757)
The above accounts for requesting Fouts such that y1,y2 > 1048757. If you need precision, follow the above steps using INTEGER_FACTORX for each Fout and Fxtal instead of a single COMMON_SCALING_FACTOR.

x1 = Fout0*A0*y1/Fout1
x2 = Fout0*A0*y2/Fxtal

PLL Feedback Equation:
A+B/C
A=floor(x2, y2)
B = x2 % y2
C = y2

Multisynth 0 Output Divider
A+B/C
A = A0
B = 0
C = 1
You can set the even integer divide bit!

Multisynth 1 output Divider
A+B/C
A= floor(x1, y1)
B = x1 % y1
C = y1
If B = 0, you can set the even integer divide bit here too! (basically, it's a harmonic or copy of Fout0)

Everything integer multiples

Maybe this can be an extra function, but we can say you want everything integer multiples (PLL feedback divider and multisync dividers all integers). Here's the required condition:

Fout0*A0=Fout1*A1=Fxtal*A2=Fvco

For this to work, you need Fvco to be a integer factor times the least common multiple, and between 600-900 MHz.
They are a little limiting, but possible. Here are some examples

One output, 1 PLL:
Fout0 = 7 MHz
Fxtal = 25 Mhz
lcm(Fout, Fxtal) = 175 MHz
Fvco = ceil(600 MHz / lcm(Fout, Fxtal) )* 600 MHz = 700 MHz
A0 = 700/7 = 100
A2 = 700/25 = 28

One output, 1 PLL:
Fout0 = 7 MHz
Fxtal = 27 Mhz
lcm(Fout0, Fxtal) = 189 MHz
Fvco = ceil(600 MHz / lcm(Fout, Fxtal) )* 600 MHz = 756 MHz
A0 = 756/7 = 108
A2 = 756/27 = 28

Two outputs, 1 PLL:
Fout0 = 6 MHz
Fout1 = 4 Mhz
Fxtal = 25 Mhz
lcm( lcm(Fout0, Fxtal), Fout1) = 300MHz
Fvco = ceil(600 MHz / lcm(Fout, Fxtal) )* 600 MHz = 600 MHz
A0 =600/6 = 100
A1 = 600/4 = 150
A2 = 600/25 = 24

Two outputs, 1 PLL:
Fout0 = 6 MHz
Fout1 = 7 Mhz
Fxtal = 25 Mhz
lcm( lcm(Fout0, Fxtal), Fout1) = 1.05 GHz
Fvco = ceil(600 MHz / lcm(Fout, Fxtal) )* 600 MHz = 1.05 GHz
Not possible! The fastest we can go is 900 Mhz!

Describe alternatives you've considered
A bunch, but mathematically this is the purest and computationally the simplest.

Hang on init

Hi!
i'm trying a simple sketch...but it hang (no error in compiling sequence) when i init the si5351

si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);

the arduino just sit there.
Any idea?

Nullify spread spectrum

Describe the bug

On some chips the frequency seems wrong. In fact when checking the registers spread spectrum was activated. Probably from the factory.

Correction

I added code in the reset() function

void Si5351::reset(void) {
...
	si5351_write(SI5351_SSC_PARAM0, 0);
	si5351_write(SI5351_SSC_PARAM1, 0);
	si5351_write(SI5351_SSC_PARAM2, 0);
	si5351_write(SI5351_SSC_PARAM3, 0);
	si5351_write(SI5351_SSC_PARAM4, 0);
	si5351_write(SI5351_SSC_PARAM5, 0);
	si5351_write(SI5351_SSC_PARAM6, 0);
	si5351_write(SI5351_SSC_PARAM7, 0);
	si5351_write(SI5351_SSC_PARAM8, 0);
	si5351_write(SI5351_SSC_PARAM9, 0);
	si5351_write(SI5351_SSC_PARAM10, 0);
	si5351_write(SI5351_SSC_PARAM11, 0);
	si5351_write(SI5351_SSC_PARAM12, 0);
...
}

High End Frequency Setting Errors v2.0.0

Greetings,
I have encountered a couple of issues which I think may be bugs in the library. I have gone through the library update procedure with the library manager and it indicates I am now using version 2.0.0.

  1. Frequency setting accuracy is lost with at least some high end frequency settings.
  • With the limited tests I performed I did not noticed any frequency setting errors when all three output frequencies were set to below vaguely 66 MHz. However if even one of the output frequencies was set to frequencies above vaguely 100 MHz then in most cases all three frequencies appeared to become skewed. I decided the most concise way to describe this issue is by providing a specific, repeatable example which is given below.

  • I don't think these issues are caused by my control program as I also send the frequency data sent to the Si5351 to the Arduino serial monitor. The data appears correct on the monitor. It is fairly certain that the data is OK as it is known in one case to work fine after reset but then fail in subsequent attempts following a higher frequency setting failure. However as I am using an ESP8266 Arduino port these issues should be confirmed by replication of the errors using an AVR controller.

  • Specific Example:

  • an attempt to set port 0 to 140 MHz; port 1 to 105 MHz; port 2 to 95 MHz results in output frequencies of approximately 133.33 MHz, 100 MHz & 90.47 MHz respectively.

  • After attempting the 140/105/95 MHz failure setting and prior to a re-initialization from a reset a subsequent attempt to set the frequencies to 66, 45 and 29 MHz also failed with output frequencies of approximately 62.86, 42.86 and 27.62 MHz respectively. However after reset re-initialization the 66/45/29 MHz output frequency settings all appeared to work OK. This suggests once a failure occurs the erroneous behavior seems to stick and erroneously influence all subsequent frequency settings until re-initialization.

  1. The library appears to ignore frequency requests over 150 MHz. The Si5351 is specified for a maximum of 200 MHz. I wonder if there is a reason for this maximum frequency limitation?

VA7TA

pll_calc()

I keep looking at this and I can't figure out what it's used for. Seems to just be code taking up space?

Middle of the above named function there is this code

    // Find best approximation for b/c = fVCO mod fIN
    denom = 1000ULL * 1000ULL;
    lltmp = freq % ref_freq;
    lltmp *= denom;
    do_div(lltmp, ref_freq);

    rfrac = lltmp;

In the ARM compiler this tells me that rfrac is initialized but never used. I actually comment out that last line with no ill effects... but it dawned on me that the entire block above it isn't used for anything, but is doing some nasty 64bit math and taking up those cycles?

Am I missing something?

VCXO on Si5351B

I just found an annoying bug, but I don't know what the fix it. If you build from a cold start the VCXO example, and run it, it will work the first time... but if you change anything that breaks it (e.g. because out 5351 is clocked from a TCXO, I set the capacitance to 0PF, then rebuilt, and nothing, no output, changed back to 8PF and nothing. Let the 5351 set unpowered until all the capacitors are fully drained and it will run again. I think there is some setup in the VCXO configuration that isn't being done that could clear and error from a problem. I'll spend some time, looking at it, but figured I'd let you know as well as I'm sure you have way more experience with the library/part than I do... Hoping you find the issue :)

set_clock_disable

Jason, I think you may want to make these changes to the set_clock_disable routine. It looks like you copy & pasted and forgot to change some if, ifelse

void Si5351::set_clock_disable(enum si5351_clock clk, enum si5351_clock_disable dis_state)
{
uint8_t reg_val = 0, reg = 0;

if (clk >= SI5351_CLK0 && clk <= SI5351_CLK3)
{
    reg = SI5351_CLK3_0_DISABLE_STATE;
}
else if (clk >= SI5351_CLK4 && clk <= SI5351_CLK7)
{
    reg = SI5351_CLK7_4_DISABLE_STATE;
}

reg_val = si5351_read(reg);

if (clk >= SI5351_CLK0 && clk <= SI5351_CLK3)
{
    reg_val &= ~(0b11 << (clk * 2));
    reg_val |= dis_state << (clk * 2);
}
else if (clk >= SI5351_CLK4 && clk <= SI5351_CLK7)
{
    reg_val &= ~(0b11 << ((clk - 4) * 2));
    reg_val |= dis_state << ((clk - 4) * 2);
}

si5351_write(reg, reg_val);

}

library integration on ESP32

Hi , I am integrating Si5351Arduino on an ESP32 micro using arduino IDE.
I get erratic behaveures when using the set_freq and set_freq_manual methods; in particular:

  1. the status is always as following
    SYS_INIT: 1 LOL_A: 1 LOL_B: 1 LOS: 1 REVID: 0
  2. when setting more then one CLK with set_freq no out is generated; with a single clk it works
  3. when setting frequencies > 10 Mhz the actual value obtained is completely wrong
  4. by using the set_freq_manual it works pretty good on a single clock
  5. by using the set_freq_manual with 2 or 3 clocks does not work...

can you please help to fix these issues ?

Thanks in advance for any help and thanks for the wonderfull work done ...

Mike

factory programed Si5351

Hello Jason,
I am using your Si5351 library for several of my HAM projects and it's a "great job" - THANKS a lot!
Was not informed about different versions of Si5351A-Bxxxx-GT and bought factory programed chips, which does not want to work with previous wrote applications !? Examples of library generates the following message on monitor:
SYS_INIT: 0 LOL_A: 1 LOL_B: 1 LOS: 0 REVID: 0
and CLK0...CLK2 are generating frequencies programed into NVM....
My question is - how I can reset and overwrite registers with my code ? In other word - how i can use the same code with blank and factory programed Si5351 using your labrary ?
Best regards,
Georgi

Erratic frequency Si5351A Arduino Uno

Hi,
Just run the Example sketch and the results is 42.XXXMhz. not the expected 14.XX Mhz
Changing the CLK0 output to 10 MHz
with " si5351.set_freq(1000000000ULL, SI5351_CLK0);" and I will get 10.Mhz.!!
The same with an input of 12 will give 12Mhz.
Between 13 and 29 will give irrelevant values. Restarting at 30 is then OK ??
I have clean re-install libraries and even try from another computer, same results.
If I use the Adafruit sketch I can get all frequencies normally from A or B on that board.

Two si5351s on the same I2C bus

In the interests of separating three clocks in a receiver project, I'm considering a configuration with two si5351s on the same Arduino controller and I2C bus. Currently Wire.BeginTransmission() uses SI5351_BUS_BASE_ADDR (x60). If this #define constant was changed to a private attribute that defaulted to SI5351_BUS_BASE_ADDR, and a public setter added, I could explicitly set the target device's address before making library calls. And 99% of the library's users with only one si5351 would never know! Just a suggestion.

Apparently the Wire library uses interrupts. Everything stops when I use a hardware interrupt.

Been searching for an I2C library to replace the Wire library. Need a solution that does not prevent me from using my own hardware interrupts. Would prefer to use a hardware interrupt to detect a keydown.

I was hoping that SoftWire or SoftwareWire would do the trick, not sure if they use interrupts. But I have not been able to convert the si5351.cpp and si5351.h code files so that they will compile, let alone try them in my own code.

Any thoughts? I've been using the Si5351Arduino library on a Pro Mini and an UNO.

Feature Request: Store Si5351 register values to array, Write to Si5351 from array.

Use Case: Higher symbol rate modulations, where the symbol length is not >> calculation + programming time (currently about 0.5ms on a 16MHz ATMega).

Possible implementation:

  • An alternate function to set_freq, which writes register values to an array.
  • A 'program from array' function, which takes an array pointer, and programs those bytes into the appropriate registers in the Si5351

From there, it should be fairly easy to write some 'userland' code which 'sets up' a modulation scheme (i.e. 32-FSK for Olivia32/1000), stores those register values into an array, and then reads from the array and programs to the Si5351 at to transmit.

Output enable behavior

In using the output enable function in the library I noticed that the Si5351 output would be re-enabled by a subsequent.si5351_set_freq call after being disabled with si5351.output_enable (SI5351_CLK0,0). Per PM this behavior is intentional, assuming that users would want the output turned on automatically when issuing set_freq() commands.

I understand the reason for this but it took some trial and error to determine that output.enable() does not control the output the way I thought it would. So per PM I'm listing it here for future considereration, even though we agree there is merit in both approaches.

Bob

Frequency Set Failure with Sequential Setting of Clk0 and Clk1

Frequency set failures occur when I try to change both Clk0 and Clk1 in a single command.
It only appears to happen when initially Clk0 is set < 100 MHz and Clk1 is set > 100 MHz.
If Clk0 is initially set higher than Clk2 it doesn't happen. This one was tough to get a handle
on and took me 30 test cycles until I think I finally understand when it happens.

I don't believe it happens as long as only one clock frequency is changed at at time.

Apparently if one of the frequencies is >100 MHz it must be lowered first to avert the failure.

Failure only seems to happen when Clk0<Clk1 to start with.

examples:
With initial MHz setting clk0=60, clk1=145; then clk0=160, clk1=45; then clk1 is set OK but clk 0 is not set to 160 first attempt, but sets OK on second attempt.

With initial MHz setting clk0=160, clk1=45; then clk0=45, clk1=145; OK first attempt.

Test Sequences for your replication:

step Clk0, MHz clk1, MHz Comment
Set Result Set Result
1 60 60 145 145 OK
2 160 60 145 145 No Change OK
3 160 60 45 45 Clk0 did not change Clk1 OK
4 160 160 45 45 OK - 2nd try
5 160 160 145 45 No Change OK
6 60 60 145 145 OK
7 160 60 145 145 No Change OK
8 160 60 45 45 Clk0 did not change Clk1 OK
9 160 160 45 45 OK - 2nd try
10 145 145 60 60 OK
11 145 145 160 60 No Change OK
12 45 45 160 160 OK - 1st try both clks
13 145 145 60 60 OK
14 45 45 160 160 OK - 1st try both clks
15 60 60 145 145 OK
16 60 60 45 45 OK
17 160 160 45 45 OK
18 160 160 145 45 No Change OK
19 160 160 45 45 OK
20 160 160 145 45 No Change OK
21 160 160 45 45 OK
22 60 60 145 145 OK
23 160 60 145 145 No Change OK
24 160 60 45 45 Clk0 did not change Clk1 OK
24 160 160 45 45 OK - 2nd try
25 60 60 145 145 OK
26 160 60 45 45 Clk0 did not change Clk1 OK
27 160 160 45 45 OK - 2nd try
28 60 60 145 145 OK
29 160 60 45 45 Clk0 did not change Clk1 OK
30 160 160 45 45 Clk0 did not change Clk1 OK
31 60 60 145 145 OK

Frequency cal enchancement

Seems like there is a small difference in calfactor when calibrating at LF compared to both 10MHz and 200MHz. As far as I can tell, this difference must be due to somthing in the Si chip, its not visible when probing the oscillator. Its also present when using the C version with external reference. All instruments used were locked to cecium, so there should be no frequency variation over such small timescale.

Proposing to change to a more advanced method of calibration, where the cal frequency can be spesified as parameters for a 3. order polynoma.
The proposed cal value would then be applied for each frequency step by calculating: cal = AF^2+BF+C.

Also, it would be nice if the library in the next version isn't locked to using 25 or 27MHz oscillators. The math should work with close to any input frequency for the Si5351A series.

Strange issues with SI5351A-B-GM and ABM8G-25.000MHz-4Y-T3

Hi! I am testing the library with the SI5351A-B-GM version of the chip. It's the A version with 8 clock outs.

I am using a 25Mhz crystal, specifically this one:
https://www.mouser.mx/ProductDetail/815-ABM8G-25-4YT3

The problem is that when I run a very simple sketch that initializes and sets a freq, I get around 1.5 times the frequency I set. For example in your calibration example, the initial freq I see in the oscilloscope is 15Mhz and it should be 10Mhz, and each time I try to set a freq I see this kind of factor in the output.

If I hit any key in the calibration sketch, I don't see any changes in the original frequency.

Do you have an idea where the problem can be?

Thanks!

set_correction() Doesn't appear to work

From the 'jason' branch, I run the calibration example, with a correction of 22, and my board output's 10MHz, to the limit of my counter (1Hz).

Then if I run, a simple sketch that sets the clock as per the calibration example, with no set_correction() call. get_correction() returns -1, and the output is 22 Hz above 10MHz

Am I doing it wrong, or not understanding how the set_correction() works? Should I do set_correction(22); with each sketch I write?

Request

Will one daythis library could be ported to Raspberry?

5351 init - additional capacitance

I was working with the 5351 and a TCXO and came across a potential issue with your library.

There are some reserved bits in the additional capacitance register that need to be preserved according to the manual programming document from Si.

0b010010 = 0x12 needs to be in the low order bits before you add or change the additional capacitance.

I believe that the section of code at the beginning of the init routine should be modified as follows.

    // Set crystal load capacitance
    uint8_t tload = 0x12; // 0b010010 reserved value bits
    tload |= xtal_load_c;
    si5351_write(SI5351_CRYSTAL_LOAD, tload);

Also, with a TCXO, if you are just using the XA osc input, you shouldn't need the additional capacitance and so, while not documented, in review of the SI clock builder app, it appears that a value of

#define SI5351_CRYSTAL_LOAD_0PF (0<<6)

Would be of use here. That line would be added to the 5351.h file.

Note, I've not tested either yet, but will be later, but fairly sure they are needed and correct. Please see the programming manual for references as needed.

Delay between CLK0 and CLK1

Describe the bug
I am not quite sure this is a bug related to the library or not.

I was setting both clocks 0 and 1 @ 80 MHz with the same phase (0) and saw that CLK0 is in advance of 45 degrees.

Since my code does configure the Si5351 I was wondering if it was done the right way.

So I tried the example sketch "si5351_phase.ino".
At first it seemed the two clocks are delayed by 90°.
But in fact if you set both clocks at phase = 0 you will see that there is a remaining delay. CLK0 is in advance of about 10°.
It gets worse @80 MHz.

To Reproduce

  • Use the sketch "si5351_phase.ino"

  • Change the parameters
    unsigned long long freq = 8000000000ULL;
    unsigned long long pll_freq = 80000000000ULL;

  • Set phases to "0"
    si5351.set_phase(SI5351_CLK0, 0);
    si5351.set_phase(SI5351_CLK1, 0);

  • Upload the sketch

You can see that CLK0 is clearly in advance of CLK1

Wrong output frequency (in a few cases)

Hi,
Using your library I found that in some cases I obtain the wrong output frequency (whereas in all other cases that I tested it is working fine). More specifically, I found that the following two combinations of PLL multiplier and frequency divider gives 75MHz (when it should be 150 MHz and 120 MHz respectively).
I tested this on two independent sets of Arduino + Si5351 clock generator, both times with the same result.
Below the code that I used in both cases.

/* wrong frequency - should be 150 MHz: */
clockgen.setupPLLInt(SI5351_PLL_A, 24);
clockgen.setupMultisynthInt(0, SI5351_PLL_A, SI5351_MULTISYNTH_DIV_4);

/* wrong frequency - should be 120 MHz: */
clockgen.setupPLLInt(SI5351_PLL_A, 24);
clockgen.setupMultisynth(0, SI5351_PLL_A, 5, 0, 1);

No output over 125 MHz

Multiple people have reported getting no output when setting the output frequency over 125 Mhz.

xtal_freq .vs. correction

I have measured my crystal freq and entered it at the init( invocation. I expected that any error there would be the same at all frequencies. So I went back to 25.000000 MHz and set the correction to zero. The 10.000000 output was 10.000174 so I set the correction (unfortunately in Hz not cHz) and the freq was corrected at 10 MHz. When I switch to 20 MHz the error was 2x of 10. At 40MHz it was 4x and at 5 MHz it was 1.2x. I thought I read somewher that when I put in the correction it would correct all frequencies.

So, I thought since the correction was only in Hz, not cHz, I would add my own correction. That correction was added to the desired frequency and again worked fine at one freq but did not track linearly as the freq was changed.

I hope someone can set me straight here. I used a similar technique with ad98xx parts and it worked fine.

Richard W5SXD

Burst of noise instead of sine

Just some incoherent notes when fault finding a issue here:
From time to time I see a burst of noise output from the Si5351B with VCXO control. It does not appear to happen each time the Si5351 is powered up. Disconnecting, then re-connecting power seems to restore it to propper operation.

Not sure if its due to my implementation, or if its a library issue at all.

Need to determine if this is a HW issue or FW, and if its reproducible.
Should determine if the Si5351 reports the correct data, if not try a reset() to see if that fixes it.

Thomas.

Speed of switching frequencies?

I'm trying to build a naive FSK transmitter, by sending 1ms long 'zero' (27.145.900MHz) or 'one' (27.143.000MHz) "bits", and am using the test case:
si5351.set_freq(2714590000ULL, SI5351_PLL_FIXED, SI5351_CLK0); // zero bit
delayMicroseconds(5000);
si5351.set_freq(2714300000ULL, SI5351_PLL_FIXED, SI5351_CLK0); // one bit
delayMicroseconds(1000);
But it seems like the minimum time in my pulses is 4ms output. When checking with 3MHz and 7MHz (to take two random, far-apart frequencies that my 16Msps scope can handle) I see that the minimum time for one pulse (or burst of the same frequency) is a little over 3ms, regardless of how low I drop the delayMicroseconds.

Is there a clever way to switch frequencies, considering that I only have one output that I will be using, and only two fixed frequencies (or one base frequency with +/- of some kHz) that will be sent?
Is set_freq itself a slow routine and not meant to be used for this purpose, but some other trickery to change the output faster, once the PLL frequency has been set?

Si5351A - drive strength not changing

Hello,

I'm using Si5351A and trying to change drive strenght, but with no effect.
Arduino compiles the code, everything is fine, but on RF meter I don't see the change.

Here is the initialization code for Si5351A...

// Initiating the Signal Generator (si5351)
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA);
// Adjusting the frequency (see how to calibrate the Si5351 - example si5351_calibration.ino)
si5351.set_correction(CORRECTION_FACTOR, SI5351_PLL_INPUT_XO);
// The drive strength is the amount of current into a 50Ω load. 2 mA roughly corresponds to 3 dBm output and 8 mA is approximately 10 dBm output (2,4,6 i 8)
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
si5351.set_freq(vfoFreq, SI5351_CLK0); // Start CLK0 (VFO)
si5351.set_freq(bfoFreq, SI5351_CLK1); // Start CLK1 (BFO)
si5351.update_status();
// Show the initial system information
delay(500);

Is this a bug issue, or maybe IC issue?
Is there any other way to change drive strenght?

set_freq documentation issue

The header for the set_freq method is as follows:

/*

  • set_freq(uint64_t freq, enum si5351_clock clk)
  • Sets the clock frequency of the specified CLK output.
  • Frequency range of 8 kHz to 150 MHz
  • freq - Output frequency in Hz
  • clk - Clock output
  • (use the si5351_clock enum)
    */
    uint8_t Si5351::set_freq(uint64_t freq, enum si5351_clock clk)

Specifically it says that the 'freq' is the output frequency in Herz. This is incorrect. The value of the parameter should be given in units of 0.01 Herz.

Interrupted clock during tuning changes

When using the library in a receiver, there are reports that the CLK output has a discontinuity when the frequency is changed, causing an audible popping in the audio.

It is known that this is the result of the PLL reset in the tuning code, which is sometimes needed to ensure that the output is on the correct frequency. What is needed is a way to minimize these PLL resets to avoid this problem as much as possible.

Library writes to EEPROM.

It may be bad practice to have the library write directly to an (undisclosed) address in the EEPROM.

si5351.set_correction(-900); should apply the factor, but the constant should be read from the eeprrom when the correction is set, making this string to be: si5351.set_correction(EEPROM.read(address));
By this, the eeprom value can be changed, by actual usage of the string si5351.set_correction(-900); no information should be written to the eeprom.

This requires a bit more formal coding when initiating the library, but then the user have control over the address range in the eeprom.

I know this is a minor issue, comments to this appreaciated.

Jittering output frequency

Hi.
I bought a SI5351 dev board from amazon loaded in this libary and started running the example script. The serial output clearly sais to me that the PLLs are locked and the chip is ready to go, but when I connect my oscilloscope to one of the outputs (so far I tested CLK0 and CLK1), I only see a jittery frequency (about +- 1MHz). So far I managed to get a fixed frequency by accident, but as soon as I restarted the arduino the frequency was jittery again. I already measured the Input Clock, which is perfectly stable. I also tried to change the input capacitences in the init function. Nothing seems to fix the error. I hope someone with a little more understanding about this chip can help me :)

detect if Si5351 is present at specified address

Currently it seems library does not check if its actually talking to si5351 and would not show any error if you are talking to an invalid address. It would be nice if init function would actually check if si5351 is present at that address by reading some register by which it could identify it ?

i am using 10MSSOP si5351A (3 clock outputs) and i try to set the frequency of first clock output to 24MHz.
after calling update_status SYS_INIT is 0, and both LOLs are 1 ... also REVID is 1 (which is suspicious as it should be 3 right ? ... chips were bought on digikey a week ago)

if i change the address to something random all the values above are 0

my full code:

    ESP_ERROR_CHECK( nvs_flash_init() );
    ESP_LOGI("main", "starting main app ...");
    vTaskDelay(1000 / portTICK_PERIOD_MS);

    ESP_LOGI("main", "starting I2C ...");
    Wire.begin(25,26);

    ESP_LOGI("main", "configuring si5351 ...");
    si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
    si5351.set_freq(2400000000ULL, SI5351_CLK0);
    si5351.set_freq(2457600000ULL, SI5351_CLK1);
    si5351.output_enable(SI5351_CLK0, 1);
    si5351.output_enable(SI5351_CLK1, 1);
    ESP_LOGI("main", "si5351 configuration complete ...");

    while(true) {
        si5351.update_status();
        vTaskDelay(5000 / portTICK_PERIOD_MS);
        ESP_LOGI("main", "SYS_INIT: %d", si5351.dev_status.SYS_INIT);
        ESP_LOGI("main", "  LOL_A: %d", si5351.dev_status.LOL_A);
        ESP_LOGI("main", "  LOL_B: %d", si5351.dev_status.LOL_B);
        ESP_LOGI("main", "  LOS: %d", si5351.dev_status.LOS);
        ESP_LOGI("main", "  REVID: %d", si5351.dev_status.REVID);
    }

"Lite" version?

I'm a noob to Arduino but the need for frequency control using the Si5351 has lit a fire under me! So first, thank you for your efforts! I really like the v2 updated library which I find much more intuitive to use.

My only request would be to create a downsized library where the combined libraries needed to control the Si5351 (e.g. "Si5151" and "Wire") could run on the ATTiny85-20. This is probably a tall order since it's only got about 6K left after the bootloader, but it would be very cool to be able to shrink the size of a frequency source to that of an old-style crystal using this 8-pin uC. Especially now that the last custom crystal maker has gone out of business.

If it were possible to slim down the library for this purpose, I'd be content with just the basic setup commands and the new set_freq() method - just the bare minimum. A simple sketch that uses just "Wire" takes a little over 2K of memory, which would leave 4K at most for "Si5351 Lite" and the user's sketch. For comparison, a fairly simple sketch using the current libraries runs about 12K.

Thanks and 73,
Bob W9RAN

si5351.set_correction(cal_factor);

Hi

I'm very new to Arduino , I have downloaded the latest lib and get the following error when
compiling the calibration sketch. Obviously I'm missing something very simple. Would appreciate
some advise

Regards in advance.

Alan

Si5351A- 3 CLK outputs

Hey,

Firstly, I am an amateur of GitHub and I really thank for the library. I am using the library for a Si5351 GUI project, and my Si5351 has 3 CLK outputs, but when I try to arrange the library for CLK0 and 1 to share PLLA and CLK2 to use PLLB, I am failing can you help, please.

multisynth_calc when r_div applied

In the multisynth_calc(uint64_t freq, uint64_t pll_freq, struct Si5351ARegSet *reg)

There is a test if the frequency is under Si5351A_MULTISYNTH_MIN_FREQ * Si5351A_FREQ_MULT and setting it to this min value.

This makes all output for frequencies under Si5351A_MULTISYNTH_MIN_FREQ * Si5351A_FREQ_MULT the same and wrong.

I think the code should be

if (freq < Si5351A_MULTISYNTH_MIN_FREQ * Si5351A_FREQ_MULT)
{
	freq = select_r_div(&freq) * freq;
}

Library reports dev_status even when device is not present

I have a program that initializes CLK0, sets frequency and then it periodically reads device status, and sends some results to Serial.

It appears that even when I remove the Si5351 module, the program still reads some "status" (LOL_A = 0);

Expected behavior
I would expect some kind of error, to recognize the device is not present.

Code

#include <Wire.h>
#include "si5351.h"

/* Si5351 module */ 
#define VFO SI5351_CLK0 
uint64_t vfoFreq = 702130000ULL ;
bool vfoOk = false ;
Si5351 vfo ;

void setup() {
  uint8_t idev ;
  uint16_t dw ;
  // blinker & serial //
  pinMode( PC13, OUTPUT );
  digitalWrite( PC13, LOW );
  Serial.begin(115200);
  delay(10);
  Serial.println("started.");
  digitalWrite( PC13, HIGH );
  // I2C setup 
  // Wire.setSDA(PB9);
  // Wire.setSCL(PB8);
  Wire.begin();
  Serial.println("I2C bus on PB8, PB9");  
  Si5351A initalization 
  Serial.print("Si5351 ");
  if( checkI2C( 0x60 ) != 0 ) Serial.println("not ");
  Serial.println("present");  
  vfoOk = vfo.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0) ;
  Serial.println( vfoOk ? "VFO OK" : "VFO ??" );
  vfo.set_freq( vfoFreq, VFO );  
  vfo.update_status();
  delay(1000);
}

uint8_t lastPllA = 0xFF ;
void loop() {
  Si5351Status st = vfo.dev_status ;
  vfo.update_status();
  if( st.LOL_A != lastPllA ) {
    Serial.printf( "VFO PLL A: %i\n", st.LOL_A ); 
    lastPllA = st.LOL_A ;
  }
  digitalWrite( PC13, LOW );
  vfo.output_enable( VFO, false );
  delay( 200 ); 
  readSerial();
}

void readSerial() {
  char text[40] = { 0 };
  byte inputSize = 0 ;
  if( Serial.available() ) {
    digitalWrite( PC13, HIGH );
    delay(100);
    inputSize = Serial.readBytesUntil( '\n', text, 39 );
    if( inputSize ) text[inputSize] = 0;
    Serial.print( "ECHO: "); Serial.println( text );
    delay(65);
    digitalWrite( PC13, LOW );
  }
}

uint8_t checkI2C( uint8_t addr ) {
  Wire.beginTransmission( addr );
  return Wire.endTransmission();
}

CLK1 & CLK2 Frequency Setting Interaction Errors when Sharing PLLB

The frequency setting of either CLK1 or CLK2 outputs significantly impacts the frequency of CLK2 or CLK1 respectively by 100 KHz or more when operating at HF frequencies. The CLK that is set last is accurately set but the previously set CLK sharing the same PLL is frequency shifted.

This problem only affects CLK outputs sharing the same PLL. Since there are two PLL's the issue is only significant for applications where 3 outputs are needed as two of the outputs must share a PLL.

(copied from @va7ta report on the AVR sister library NT7S/Si5351#11)

pll not recalculated ( 150 MHz boundary ?? )

Right after initializing ( so with default values for pll-source, plla )

Consider:

si5351.set_freq(8000000000ULL, SI5351_CLK0);
si5351.set_freq(15600000000ULL, SI5351_CLK0);
si5351.set_freq(8000000000ULL, SI5351_CLK0);

The second 80 MHz is not put out. Some debugging ( looking at the pll value ) showed that the pll is not recalculated.
Now this:

si5351.set_freq(8000000000ULL, SI5351_CLK0);
si5351.set_freq(15600000000ULL, SI5351_CLK0);
si5351.set_freq(14300000000ULL, SI5351_CLK0);
si5351.set_freq(8000000000ULL, SI5351_CLK0);

This works. The 143 MHz triggers recalculating the pll.

Workaround:

si5351.set_freq(8000000000ULL, SI5351_CLK0);
si5351.set_freq(15600000000ULL, SI5351_CLK0);
si5351.set_freq(8000000000ULL, SI5351_CLK0);
si5351.pll_reset(SI5351_PLLA);

Pll is recalculated and the 80 MHz is put out.

I can live with it, but took me some time to figure out.
Is this the si5351 or a glitch in the pll calcualtion?

Multi-band beacon

I have an issue I'm trying to understand and resolve. I've been working on a mulit-band beacon where for 50 MHz I use CLK1 @ 50 MHz, and 144 MHz I use CLK1 @ 144 MHz.

For 222 and 432 I use CLK0 as an LO to a mixer, and CLK2 as the IF to the mixer and the output = 222 or 432 MHz.

This works.

However, after I use the Si5351a for 222 and 432 MHz and the loop goes to do 50 MHz on CLK1 again it no longer outputs.

I keep thinking this may be an issue where something isn't being reset like the PLL's.

I've tried to set PLL's for each band, but I'm not 100% sure I'm doing it right.

I can set PLL for a single band ok and it seems to work.

I'm stumped. I can provide my sketch if that would be useful. I suspect it's something simple I've missed. But after a week of trying and researching I just can't seem to resolve the issue.

Can you help set me straight?

what is the default drive strength at startup?

Not an issue, but just a few questions:

It is possible to set the drive strength, for example to 4mA:
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_4MA);

Questions:

  1. What is the default drive strength at startup condition?
    (what is de drive strength when the command si5351.drive_strength() is never issued at all)?
  2. What parameter values for drive strength are accepted?

Allard PE1NWL

It would be nice to easily have CLK0 and CLK1 in phase....

Hi,
Ideally, I would like CLK0 to go at twice the frequency of CLK1, but have them in phase. That way I can drive the low and high order control bytes of a 4x1 analog MUX for doing SDR to end up with I and Q. (It counts 00, 01, 10, 11,..., where the low order bit is half the frequency of the high bit.) I think the restrictions that occur with a 90 degree phase delay between CLK0 and CLK1 do not occur with this setup because the phase delay is zero. It would be nice to let the library deal with the intricacies though. ;-) This scheme is used by Guido in the UCX-SSB, but he isn't using your handy library. I would like it to be easy for those who prefer the library route.
Thanks & 73,
Rob
KL7NA

Si5351B 127mhz<not working<150mhz

i am using si5351b and 25mhz crystal. I can't see the output between 127 MHz and 150 MHz.
si5351.set_freq(14600000000ULL, SI5351_CLK0);
and
si5351.set_ms_source(SI5351_CLK0, SI5351_PLLB); // or SI5351_PLLA si5351.set_freq_manual(14600000000ULL, 87600000000ULL, SI5351_CLK0);
I tried both methods.
is this an bug? What am I doing wrong? (v2.1.4 )

Cannot set low frequency clock accurately

Hi,
I just used the example sketch and tried to change the frequency to 10kHz.

// Set CLK1 to output 10 kHz
si5351.set_freq(1000000ULL, SI5351_CLK1);

The clock I have got was in range of 641kHz.
Does this code support kHz clock generation or there is some issue with the code?
Please advise.
Thanks!
Igor

Code errors when Arduino automatically updates to version 2

When the Arduino IDE automatically updates to version 2 from version 1 it seems to be getting different code than that which is currently on the master branch on Github. For example one error shows that the following line is included in the src/si5351.h file twice:

enum si5351_pll_input{SI5351_PLL_INPUT_XO, SI5351_PLL_INPUT_CLKIN};

This looks like it is from commit ad6005a.

In the latest commit ae86200 this has been fixed.

I manually copied the files from Github and overwrote the ones the IDE downloaded and the code now works as expected.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.