Some notes on the Si5351a
Si5351 "XA" can be driven by a clock signal (25/27 MHz, 1Vpp) source: [2] p23, figure 14 Internet commenters report success driving it with a much wider frequency range as well as successfully exceeding the specified PLL range. Inputs from 3MHz to 146MHz and PLL frequencies from 168 to 1168MHz were tested. source: [1] intermediate PLL frequency: 600 to 900 MHz [3] p2 divider range 15 + 0/1048575 .. 90 "integer divide" FBA_INT flag is for _EVEN_ integers [3] p4 multisynth: valid dividiers are 4, 6, 8, 8 + 1/1048575 ... 2048 "integer divide" FBA_INT flag is for _EVEN_ integers [3] p6
[1]: http://www.simonsdialogs.com/2018/11/si5351a-any-frequency-cmos-clock-generator-and-vco-specifications-myths-and-truth/
[2]: https://www.silabs.com/documents/public/data-sheets/Si5351-B.pdf (rev 1.3)
[3]: https://www.silabs.com/documents/public/application-notes/AN619.pdf Manually Generating an Si5351 Register Map rev 0.8
Si5351 Frequency Planner in Python
The Si5351 and related clock generators are very flexible, but they are a bit cumbersome to "program".
The basic design of the Si5351 is that an incoming frequency is first multiplied to create a high internal frequency (nominally in the range from 600MHz to 900MHz), then divided to create an output frequency. The multipliers and dividers have restrictions on their ranges, there are just 2 PLLs but 3 output clocks, and certain types of configurations (e.g., "divisor is an integer multiple of 2") are said to give lower jitter outputs than others.
The datasheet advising users on how to create their own register values is very complicated and some of the parts resist comprehension even after multiple readings. Thie chip maker Silicon Labs provides a graphical closed source Windows program for generating register maps, though some internet commenters regard it as buggy.
This program represents my own effort to create a frequency planner. It neglects some datasheet rules, mostly related to output frequencies above 50MHz or so. It tries to
- Favor lower-jitter configurations where possible
- Favor making the first-listed frequency as accurate as possible
- Try each combination of ways to allocate output clocks to the PLLs
- Obey the datasheet restrictions as I've understood them
- Do all arithmetic as infinite precision arithmetic, not floating point
- Implement the divisor rules for extremely fast clocks
- Implement the divisor rules for higher numbered outputs on 20QFN packages
For exact input clocks such as 25MHz, it is surprisingly hard to find a "plausible" frequency that is inexact, and even harder to find a "plausible" frequency that is less exact than your reference clock. I didn't actually find a case where the error is not much smaller than the frequency stability of any reference I'd plausibly have access to.
(Of course, if you measure your reference clock as 25MHz + 13.37Hz and plug that in as the --input-freq then almost everything is related to that clock inexactly, so the fact that the clocks will still be really, really close to the requested value is very nice.)
It does not directly create a register map, but the values shown are easy enough to convert to the form used in the CircuitPython adafruit_si5151 library. Sadly, as CircuitPython does not support the fractions module, it's not currently feasible to run this code on a CircuitPython board directly controlling the si5351 chip.
Example:
Generate 315M/88 (NTSC colorburst), 4.43361875M (PAL colour carrier), 25.8048M (UART clock) all exactly from a 25MHz reference clock or crystal. However, the PAL colour carrier will have more jitter since it uses a fractional divisor:
$ ./party.py 315M/88 4.43361875M 25.8048M Input frequency: 25000000 (25000000.0) Frequency plan score: 10.38 PLL A: Frequency plan type: Fractional multiplier, double integer divisor (1) Multiplier = 126/5 (25.2) Intermediate frequency = 630000000 (630000000.0) Desired output frequency: 39375000/11 (3579545.4545454546) Divider = 176 (176.0) Exact r_divider = 0 (/ 1) PLL B: Frequency plan type: Fractional multiplier, fractional divisor (5) Multiplier = 12059443/500000 (24.118886) Intermediate frequency = 602972150 (602972150.0) Desired output frequency: 17734475/4 (4433618.75) Divider = 136 (136.0) Exact r_divider = 0 (/ 1) Desired output frequency: 25804800 (25804800.0) Divider = 12059443/516096 (23.366666279141864) Exact r_divider = 0 (/ 1)
Generate pi MHz from a 25MHz reference clock or crystal (error: 27.8 nano Hz)
$ ./party.py 3.1415926535898M Input frequency: 25000000 (25000000.0) Frequency plan score: 1.00 PLL A: Frequency plan type: Fractional multiplier, fractional divisor (5) Multiplier = 24 (24.0) Intermediate frequency = 600000000 (600000000.0) Desired output frequency: 15707963267949/5000000 (3141592.6535898) Divider = 40306053/211042 (190.98593171027568) Actual output frequency: 42208400000000/13435351 (3141592.653589772) Relative Error: -8.83757e-15 Absolute Error: 2.78e-08Hz r_divider = 0 (/ 1)
The source is available in a github gist:
Towards my GPS LED Light Clock
A few years ago, I made a CCFL light clock using an Arduino with a custom shield containing a transformer (to get a reliable 60Hz timebase) and a triac (for solid-state switching of the lamp). By having a simple 7-day alarm calendar (set at compile time), the clock seldom requires interaction except for the reading lamp function.
However, the design has two main problems:
All older entries
Website Copyright © 2004-2024 Jeff Epler