Код:
void si5351_calc_info(uint32_t freq, struct si5351_pll_info* pi, struct si5351_msx_info* mi)
{
const uint32_t SI5351_PLL_VCO_MAX = si5351_xtal * 36;
const uint32_t SI5351_MULTISYNTH_MIN_FREQ = si5351_xtal / 25;
const uint32_t SI5351_MULTISYNTH_DIVBY4_FREQ = si5351_xtal * 6;
const uint32_t SI5351_PLL_C_MAX = 1048575;
const uint32_t SI5351_PLL_B_MAX = (SI5351_PLL_C_MAX-1);
uint32_t a, b, c;
uint64_t nom, den;
double divpll, divms, fpll, k;
uint8_t rdiv = SI5351_OUTPUT_CLK_DIV_1;
bool div4 = false;
if (freq >= ((si5351_xtal * 9) >> 1))
{
//Use output multisynth constant divider = 4,
//calculate PLL feedback multisynth to set desired frequency
if (freq >= SI5351_MULTISYNTH_DIVBY4_FREQ)
divms = 4.0;
else
divms = 6.0;
divpll = (freq / ((double)si5351_xtal)) * divms;
//Calculate a, b, c (pll feedback multisynth parameters)
a = (uint32_t)floor(divpll);
b = 0;
c = 1;
k = divpll - a;
nom = (uint64_t)(k * 0x6FFFFFFFFFFFFFFFull);
den = 0x6FFFFFFFFFFFFFFFull;
rational_best_approximation(nom, den, SI5351_PLL_B_MAX, SI5351_PLL_C_MAX, &b, &c);
fpll = si5351_xtal * ((double)a + (double)b / (double)c);
}
else
{
//Set PLL to maximum frequency, calculate output multisynth divider
//Handle frequencies below 1 MHz
if (freq < (SI5351_MULTISYNTH_MIN_FREQ / 64))
rdiv = SI5351_OUTPUT_CLK_DIV_128;
else if (freq < (SI5351_MULTISYNTH_MIN_FREQ / 32))
rdiv = SI5351_OUTPUT_CLK_DIV_64;
else if (freq < (SI5351_MULTISYNTH_MIN_FREQ / 16))
rdiv = SI5351_OUTPUT_CLK_DIV_32;
else if (freq < (SI5351_MULTISYNTH_MIN_FREQ / 8))
rdiv = SI5351_OUTPUT_CLK_DIV_16;
else if (freq < (SI5351_MULTISYNTH_MIN_FREQ / 4))
rdiv = SI5351_OUTPUT_CLK_DIV_8;
else if (freq < (SI5351_MULTISYNTH_MIN_FREQ / 2))
rdiv = SI5351_OUTPUT_CLK_DIV_4;
else if (freq < (SI5351_MULTISYNTH_MIN_FREQ))
rdiv = SI5351_OUTPUT_CLK_DIV_2;
divpll = ((double)SI5351_PLL_VCO_MAX) / ((double)si5351_xtal);
//Calculate a, b, c (pll feedback multisynth parameters)
a = (uint32_t)floor(divpll);
b = 0;
c = 1;
k = divpll - a;
nom = (uint64_t)(k * 0x6FFFFFFFFFFFFFFFull);
den = 0x6FFFFFFFFFFFFFFFull;
rational_best_approximation(nom, den, SI5351_PLL_B_MAX, SI5351_PLL_C_MAX, &b, &c);
fpll = si5351_xtal * ((double)a + (double)b / (double)c);
divms = fpll / (double)(freq * (1 << rdiv) * (div4 ? 4:1));
}
pi->a = a;
pi->b = b;
pi->c = c;
// Calculate a, b, c (output multisynth parameters) from divms calculated above
b = 0;
c = 1;
if (divms == 4.0)
{
a = 4; //MS divider is integer
}
else if (divms == 6.0)
{
a = 6; //MS divider is integer
}
else
{
//MS divider is fractional
a = (uint32_t)floor(divms);
k = divms - a;
nom = (uint64_t)(k * 0x6FFFFFFFFFFFFFFFull);
den = 0x6FFFFFFFFFFFFFFFull;
rational_best_approximation(nom, den, SI5351_PLL_B_MAX, SI5351_PLL_C_MAX, &b, &c);
}
mi->a = a;
mi->b = b;
mi->c = c;
mi->rdiv = rdiv;
mi->divby4 = div4;
}
//
// http://en.wikipedia.org/wiki/Continued_fraction
//
void rational_best_approximation(
uint64_t given_numerator, uint64_t given_denominator,
uint32_t max_numerator, uint32_t max_denominator,
uint32_t *best_numerator, uint32_t *best_denominator)
{
uint64_t n, d, n0, d0, n1, d1;
n = given_numerator;
d = given_denominator;
n0 = d1 = 0;
n1 = d0 = 1;
for (;;)
{
uint64_t t, a;
if ((n1 > max_numerator) || (d1 > max_denominator))
{
n1 = n0;
d1 = d0;
break;
}
if (d == 0)
break;
t = d;
a = n / d;
d = n % d;
n = t;
t = n0 + a * n1;
n0 = n1;
n1 = t;
t = d0 + a * d1;
d0 = d1;
d1 = t;
}
*best_numerator = (uint32_t)n1;
*best_denominator = (uint32_t)d1;
}