Git Product home page Git Product logo

si5351's Introduction

Si5351 Library for avr-gcc

This is a basic library for the Si5351 series of clock generator ICs from Silicon Labs for the avr-gcc development environment. It will allow you to control the Si5351 with an AVR microcontroller with a TWI peripheral module, 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. Also, since the Si5351A3 version is the one which seems most useful in amateur radio applications, this is where the current development will be focused. Once the Si5351A3 has a decent and mature feature set, hopefully we will be able to turn to the 8-output version, and perhaps even the B and C variants.

The library is currently in a minimalistic and bit of an untested state. Many of the features are not yet implemented. Unimplemented features will added according to usefulness in RF/amateur radio applications, as stated above. Please feel free to use the issues feature of GitHub if you run into problems or have suggestions for important features to implement.

Hardware Requirements and Setup

An 8-bit AVR microcontroller with the TWI peripheral is required for this library. It has currently only been tested with the ATmega328P microcontroller, but should be portable to at least the ATmega88 and ATmega168, although the code size is currently about 8 kB (due to the math in the PLL calculations), so you will most likely need at least 16 kB of program space.

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 AVR. Since the I2C interface is set to 400 kHz, use 1 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.

Usage

Include the si5351.c, si5351.h, i2c.c, and i2c.h files into your avr-gcc project as you would with any other standard project.

The "public" functions of the library are documented in the code. It should be fairly self-explanatory, but here's a very short introduction.

Before you do anything with the Si5351, you will need to initialize the communications and the IC:

si5351_init();

Now let's set the CLK0 output to 10 MHz:

si5351_set_freq(10000000, 0, SI5351_CLK0);

The second value passed in the above function is the desired driving PLL frequency. Entering a 0 will have the function choose a PLL frequency for you. If you would like to use a fixed PLL frequency to drive a multisynth (in order to ensure glitch-free tuning), set the desired PLL frequency first using the function below, then specify that frequency in the si5351_set_freq() function:

si5351_set_pll(900000000, SI5351_PLLA);
si5351_set_freq(10000000, 900000000, SI5351_CLK0);

The PLL frequency only needs to be set once. Any additional frequency changes only need to use the si5351_set_freq() function as long as you are using the same PLL frequency as before.

If we like we can adjust the output drive power:

si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_4MA);

Also, there will be some inherent error in the reference crystal's actual frequency, so we can measure the difference between the actual and nominal output frequency in Hz, multiply by 10, make it an integer, and enter this correction factor into the library to store in EEPROM for future use. Once this is stored, it should not need to be set again unless you want to redo the calibration. With an accurate measurement at one frequency, this calibration should be good across the entire tuning range:

si5351_set_correction(-900);

One thing to note: the library is set for a 25 MHz reference crystal. If you are using a 27 MHz crystal, please change the SI5351_XTAL_FREQ define in si5351.h.

Also, the si5351_init() function sets the crystal load capacitance for 8 pF. Change this value if you are using a crystal with a different load capacitance.

Oddities

The Si5351 datasheet specifies an I2C address of 0b1100000 (0x60), but this has not been the correct address on the samples used at the NT7S lab. Using the Bus Pirate's I2C address scan macro, we have determined that the address that the Si5351A wants to see is 0x6F (0xDE in 8-bit format), so that is what we use in the library. If you have trouble communicating with your Si5351, you may want to adjust this value in the si5351.h file back to the specified value (0xC0 in 8-bit format). Given the high number of errors we have found in the datasheet so far, this is unsurprising.

Update: It turns out that we were sent defective parts. Another batch was ordered from a different vendor and they work on the proper I2C address of 0x60. The code has been updated to reflect the correct address.

Right now, this code is focused solely on the 3-output 10-MSOP variant (Si5351A3). Since some of the code was derived from the Si5351 driver in the Linux kernel, it may be useable on with the other variants, but certainly many features won't work yet. With any luck, we will get the library to work with the other variants as well, or even better, maybe someone will take the initiative, write the code, and send me a pull request.

TODO

  • Status flag or return correction constant
  • Implement tuning below 1 MHz
  • Implement tuning above 150 MHz

Written with StackEdit.

si5351's People

Contributors

nt7s 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

Watchers

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

si5351's Issues

registers are write only.

Hi, I do not know if it is because I have an older version of Si5351, but most registers are write only (you cannot read them back).
This affect all the functions that set bits using read-update-write.

I have modified my version to include a register cache;
modified the si5351_read(), si5351_write() and si5351_write_bulk()

PLL reset is necessary

Sometimes, if used intensively, PLL goes out of locking and never returns to it.

Appnote "Si5351 – Modifying the Feedback Multisynth Dividers Silicon Labs Timing Knowledge Base Article # 311668" states that:
"any changes to the feedback Multisynth will require a PLL reset. PLLA and PLLB are reset by setting register 177 bits 5 and 7 respectively to 1."

Please add these resets to the code where the PLL multisynths are updated.

Two kinds of Si5351 exist

Trying to figure out why my Si5351a cannot generate frequencies more than 112.5 MHz, I've found that two different lots of Si5351a exist on the market. According to various specs and comparison tables, one of them has multisynth divider limits 8..2050, another one - 6..1800. There is no way to determine programmatically which one is in use. Also, I don't know a way to determine which one it is by its enclosure marking.

Therefore, I suggest to set multisynth limits to:

define SI5351_MULTISYNTH_A_MIN 8

define SI5351_MULTISYNTH_A_MAX 1800

Also, maximum output frequency should be limited to 112500000 Hz.

Portability issue

I'm successfully using your code for my antenna analyzer project (using the board based on STM32 ARM Cortex M3), but had to make some changes in si5351 code.
There are several platform-dependent definitions like TW_xxx used in si5351.c. It does not allow building the code for other platforms. All such checks should be moved to i2c.c which is platform dependent.

Menaingless check in si5351.c

Si5351/si5351.c

Line 138 in 1af6288

if(pll_calc == 0)

PLL parameters are never going to be written as this check is bound to fail: pll_calc (a function pointer) will always differ from the null pointer (0).

Either:

  • The check is not needed, and PLL parameters always need to be written (probable, serious fault)
  • The check is needed, but the wrong comparison has been used (possible, serious fault)
  • The check is not needed, and PLL parameters never need to be written (doubtful, redundant code)

ms calculation & precision improvements using continuous fractions

Jason,
First thank you so very much for all your effort in providing the si5351c library. This has been extremely helpful to me as I modify the 'all band' 0-2 GHz disciplined transverter I'm working to make available on my Open Source Hardware Pages and the 2nd gen general purpose disciplined reference extracted from it using the Si5351 C. 1st gen is already in TAPR's hands for production and deployment for HamSci and other uses which have already netted important new insights into the ionosphere and propagation within amateur radio through FST4W spectral spreading measurements. In moving from the A to C I immediately went to your library which saved me a great deal of time. I apologize that I haven't yet been able to fully read your documentation or comments on this forum yet, things worked so well and so soon that I have been able to address HW and other issues for these devices I'm making.

I'd like to offer a suggestion that I think would greatly improve the C implementation. That is to use Continued Fraction techniques to obtain far more precision than simpler frequency setting techniques. These presently limit resolution to approximately SI5351_PLL_INPUT_CLKIN/10^6 which amounts to about 40 ppb for a 25 MHz source.

The new measurements and discoveries we are achieving with high precision even on HF require small-mHz accuracy to measure ionospheric characteristics and Doppler shift in the small mHz or few-ppt (parts per trillion) precision. The current library can not provide this but I think there may be a direct way to improve it. Franco Venturi K4VZ has already written code to calculate these new values which I think can provide about six orders of magnitude improvement in precision. While I haven't yet tried it I have confidence that it will work.

If your library could be revised to use this technique, borrowing from Franco's code as is useful, I think the results could be phenomenal. The present few kHz setting errors currently produced at microwave frequencies could drop to a few mHz (milli-Hz) in situations where the Si5351 is providing reference clocking. Of course this improvement would apply to all the user outputs on the 2nd generation reference I now have prototyped and operating.

While I think I am able to extend your library to make the ms calculation accessible myself, you are a far better coder than I am and undoubtedly much more proficient than I and the improvements would then be directly available to everyone using your efforts.
Having wide geographic area very high precision transmitters and receivers can allow high precision time of flight measurements, propagation study, geopositioning and other benefits to amateur radio and even radio science in general.

If it could help you, I am willing to provide you prototype hardware on which to develop and test these modifications. It does require a test set up with very high GNSS, OCXO or local 10 MHz disciplining such as rubidium standards. If you contact me directly I think I can provide Franco's code if you are interested in pursuing this.
Again thank you so much for what you've done and the great contribution it is.

Glenn Elmore n6gn
Fort Collins, CO

Si registers initializations

Several important registers that make significant influence on generated signals are at undefined state after powerup, namely, FANOUT register (187) and Spread Spectrum Parameters register (149). If, occasionally, fanout or spread spectrum will be enabled at powerup, the device will output unexpected signals.
These registers must be initialized explicitly.

Avoid malloc / free

There is no reason at all to use malloc for a 30 Bytes buffer.

The implications of using malloc and free on microcontrollers is quite severe - a simple 32 byte array should be used instead.

Probably the other issue reporting a memory leak leads to the same problem.

Rational approximation is misused

In current code, rational_best_approximation() almost always returns the same values of b and c that were passed to its input as rfrac and denom. The function has no numerical space for approximation: it can only perform GCD leaving ratio exactly the same. This approximation is useless and can be totally omitted, leaving the code with noticeable frequency setting errors.

The solution is to multiply both rfrac and denom by 4000ul to give some space for approximation within 32-bit range without overflowing the UINT32_MAX boundary.

And the ultimate, most precise but computationally heavy solution is to use 64-bit rfrac and denom, calculated from frequencies expressed as double floating points, and multiplied with very very big ULL number. Also, uint64_t internals inside rational_best_approximation(). But this way is hardly possible for 8-bit AVR which will do the computations for ages in this case. On ARM Cortex this way works like a charm, providing exceptional frequency setting accuracy.

Memory leak

si5351_set_pll() does not free allocated buffer.
BTW, why malloc's are used? Create 30-byte buffer on the stack and avoid all problems.

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.

Use of floating point unnecessary

From pll_calc():

/* Factor calibration value into nominal crystal frequency */
/* Measured in parts-per-ten million */
ref_freq += (uint32_t)((double)(correction / 10000000.0) * (double)ref_freq)

Fixed-point is perhaps more precise, using a "long long" aka int64_t:

/* Factor calibration value into nominal crystal frequency */
/* Measured in parts-per-ten million */
ref_freq += (int32_t) ((((((int64_t)correction) << 31) /
    10000000LL) * ref_freq) >> 31);

Resulting linked binaries aren't that different in size (depending on optimization level in use).
Your mileage may vary.

Function pointer evaluated

Please look at line 138 at si5351.c:
if(pll_calc == 0)
Why does it evaluate function pointer here? The result will always be false.

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.