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.
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 0 Output Divider
A+B/C
A = A1
B = 0
C = 1
You can set the even integer divide bit!
In this example, we'll make an output at Fout=7.1MHz using a Fxtal=27 MHz crystal.
- 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
- Next, we find y2 using
y2 = Fxtal/COMMON_SCALING_FACTOR
whereCOMMON_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:- 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
andFout=7,100,000
, so makeCOMMON_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
and27,000,000/COMMON_SCALING_FACTOR=270
. Theny2 = Fxtal/COMMON_SCALING_FACTOR=270
- 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.
- Fast way: make
- Now you can find
x2 = Fout*A1/(Fxtal/y2)=7.1e6*126/(27e6/270)=8946
- 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)
- You have to make sure that
y2<=1,048,757
If a Fout was chosen such thaty2>1,048,757
(that happens if you want a lot of precision in your output frequency), you can either:- just go and put a hard cap on
y2 = 1,048,757
and accept the tiny error (on the order of 3 Hz) - 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:
- just go and put a hard cap on
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)
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.