mirror of
https://github.com/ttrftech/NanoVNA.git
synced 2025-12-06 03:31:59 +01:00
feat: improve frequency accuracy
This commit is contained in:
parent
75ea464c91
commit
6a88f8ed8f
124
si5351.c
124
si5351.c
|
|
@ -222,55 +222,66 @@ si5351_setupMultisynth(uint8_t output,
|
||||||
si5351_write(clkctrl[output], dat);
|
si5351_write(clkctrl[output], dat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t
|
|
||||||
gcd(uint32_t x, uint32_t y)
|
|
||||||
{
|
|
||||||
uint32_t z;
|
|
||||||
while (y != 0) {
|
|
||||||
z = x % y;
|
|
||||||
x = y;
|
|
||||||
y = z;
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define XTALFREQ 26000000L
|
#define XTALFREQ 26000000L
|
||||||
#define PLL_N 32
|
#define PLL_N 32
|
||||||
#define PLLFREQ (XTALFREQ * PLL_N)
|
#define PLLFREQ (XTALFREQ * PLL_N)
|
||||||
|
|
||||||
void
|
void
|
||||||
si5351_set_frequency_fixedpll(int channel, int pll, int pllfreq, int freq,
|
si5351_set_frequency_fixedpll(int channel, int pll, int pllfreq, int freq,
|
||||||
uint32_t rdiv, uint8_t drive_strength)
|
int rdiv, uint8_t drive_strength, int mul)
|
||||||
{
|
{
|
||||||
int32_t div = pllfreq / freq; // range: 8 ~ 1800
|
int denom = freq;
|
||||||
int32_t num = pllfreq - freq * div;
|
int div = (pllfreq * mul) / denom; // range: 8 ~ 1800
|
||||||
int32_t denom = freq;
|
int num = (pllfreq * mul) - denom * div;
|
||||||
//int32_t k = freq / (1<<20) + 1;
|
|
||||||
int32_t k = gcd(num, denom);
|
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
|
||||||
num /= k;
|
int max_denominator = (1 << 20) - 1;
|
||||||
denom /= k;
|
if (denom > max_denominator) {
|
||||||
while (denom >= (1<<20)) {
|
int p0 = 0, q0 = 1, p1 = 1, q1 = 0;
|
||||||
num >>= 1;
|
while (denom != 0) {
|
||||||
denom >>= 1;
|
int a = num / denom;
|
||||||
|
int q2 = q0 + a*q1;
|
||||||
|
if (q2 > max_denominator)
|
||||||
|
break;
|
||||||
|
int p2 = p0 + a*p1;
|
||||||
|
p0 = p1; q0 = q1; p1 = p2; q1 = q2;
|
||||||
|
int new_denom = num - a * denom;
|
||||||
|
num = denom; denom = new_denom;
|
||||||
|
}
|
||||||
|
num = p1;
|
||||||
|
denom = q1;
|
||||||
}
|
}
|
||||||
|
|
||||||
si5351_setupMultisynth(channel, pll, div, num, denom, rdiv, drive_strength);
|
si5351_setupMultisynth(channel, pll, div, num, denom, rdiv, drive_strength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
si5351_set_frequency_fixeddiv(int channel, int pll, int freq, int div,
|
si5351_set_frequency_fixeddiv(int channel, int pll, int freq, int div,
|
||||||
uint8_t drive_strength)
|
uint8_t drive_strength, int mul)
|
||||||
{
|
{
|
||||||
int32_t pllfreq = freq * div;
|
int denom = XTALFREQ * mul;
|
||||||
int32_t multi = pllfreq / XTALFREQ;
|
int64_t pllfreq = (int64_t)freq * div;
|
||||||
int32_t num = pllfreq - multi * XTALFREQ;
|
int multi = pllfreq / denom;
|
||||||
int32_t denom = XTALFREQ;
|
int num = pllfreq - denom * multi;
|
||||||
int32_t k = gcd(num, denom);
|
|
||||||
num /= k;
|
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
|
||||||
denom /= k;
|
int max_denominator = (1 << 20) - 1;
|
||||||
while (denom >= (1<<20)) {
|
if (denom > max_denominator) {
|
||||||
num >>= 1;
|
int p0 = 0, q0 = 1, p1 = 1, q1 = 0;
|
||||||
denom >>= 1;
|
while (denom != 0) {
|
||||||
|
int a = num / denom;
|
||||||
|
int q2 = q0 + a*q1;
|
||||||
|
if (q2 > max_denominator)
|
||||||
|
break;
|
||||||
|
int p2 = p0 + a*p1;
|
||||||
|
p0 = p1; q0 = q1; p1 = p2; q1 = q2;
|
||||||
|
int new_denom = num - a * denom;
|
||||||
|
num = denom; denom = new_denom;
|
||||||
|
}
|
||||||
|
num = p1;
|
||||||
|
denom = q1;
|
||||||
}
|
}
|
||||||
|
|
||||||
si5351_setupPLL(pll, multi, num, denom);
|
si5351_setupPLL(pll, multi, num, denom);
|
||||||
si5351_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength);
|
si5351_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength);
|
||||||
}
|
}
|
||||||
|
|
@ -285,11 +296,11 @@ si5351_set_frequency(int channel, int freq, uint8_t drive_strength)
|
||||||
{
|
{
|
||||||
if (freq <= 100000000) {
|
if (freq <= 100000000) {
|
||||||
si5351_setupPLL(SI5351_PLL_B, 32, 0, 1);
|
si5351_setupPLL(SI5351_PLL_B, 32, 0, 1);
|
||||||
si5351_set_frequency_fixedpll(channel, SI5351_PLL_B, PLLFREQ, freq, SI5351_R_DIV_1, drive_strength);
|
si5351_set_frequency_fixedpll(channel, SI5351_PLL_B, PLLFREQ, freq, SI5351_R_DIV_1, drive_strength, 1);
|
||||||
} else if (freq < 150000000) {
|
} else if (freq < 150000000) {
|
||||||
si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 6, drive_strength);
|
si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 6, drive_strength, 1);
|
||||||
} else {
|
} else {
|
||||||
si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 4, drive_strength);
|
si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 4, drive_strength, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,17 +324,18 @@ si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_streng
|
||||||
int band;
|
int band;
|
||||||
int delay = DELAY_NORMAL;
|
int delay = DELAY_NORMAL;
|
||||||
uint32_t ofreq = freq + offset;
|
uint32_t ofreq = freq + offset;
|
||||||
|
int mul = 1, omul = 1;
|
||||||
uint32_t rdiv = SI5351_R_DIV_1;
|
uint32_t rdiv = SI5351_R_DIV_1;
|
||||||
if (freq >= config.harmonic_freq_threshold * 3) {
|
if (freq >= config.harmonic_freq_threshold * 3) {
|
||||||
freq /= 5;
|
mul = 5;
|
||||||
ofreq /= 7;
|
omul = 7;
|
||||||
} else if (freq >= config.harmonic_freq_threshold) {
|
} else if (freq >= config.harmonic_freq_threshold) {
|
||||||
freq /= 3;
|
mul = 3;
|
||||||
ofreq /= 5;
|
omul = 5;
|
||||||
}
|
}
|
||||||
if (freq <= 100000000) {
|
if ((freq / mul) < 100000000) {
|
||||||
band = 0;
|
band = 0;
|
||||||
} else if (freq < 150000000) {
|
} else if ((freq / mul) < 150000000) {
|
||||||
band = 1;
|
band = 1;
|
||||||
} else {
|
} else {
|
||||||
band = 2;
|
band = 2;
|
||||||
|
|
@ -357,34 +369,34 @@ si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_streng
|
||||||
}
|
}
|
||||||
|
|
||||||
si5351_set_frequency_fixedpll(0, SI5351_PLL_A, PLLFREQ, ofreq,
|
si5351_set_frequency_fixedpll(0, SI5351_PLL_A, PLLFREQ, ofreq,
|
||||||
rdiv, drive_strength);
|
rdiv, drive_strength, omul);
|
||||||
si5351_set_frequency_fixedpll(1, SI5351_PLL_A, PLLFREQ, freq,
|
si5351_set_frequency_fixedpll(1, SI5351_PLL_A, PLLFREQ, freq,
|
||||||
rdiv, drive_strength);
|
rdiv, drive_strength, mul);
|
||||||
//if (current_band != 0)
|
//if (current_band != 0)
|
||||||
si5351_set_frequency_fixedpll(2, SI5351_PLL_A, PLLFREQ, CLK2_FREQUENCY,
|
si5351_set_frequency_fixedpll(2, SI5351_PLL_A, PLLFREQ, CLK2_FREQUENCY,
|
||||||
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
|
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
// Set PLL twice on changing from band 2
|
// Set PLL twice on changing from band 2
|
||||||
if (current_band == 2) {
|
if (current_band == 2) {
|
||||||
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength);
|
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul);
|
||||||
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength);
|
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul);
|
||||||
}
|
}
|
||||||
|
|
||||||
// div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1
|
// div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1
|
||||||
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength);
|
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul);
|
||||||
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength);
|
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul);
|
||||||
si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq * 6, CLK2_FREQUENCY,
|
si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq / mul * 6, CLK2_FREQUENCY,
|
||||||
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
|
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
// div by 4 mode. both PLL A and B are dedicated for CLK0, CLK1
|
// div by 4 mode. both PLL A and B are dedicated for CLK0, CLK1
|
||||||
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 4, drive_strength);
|
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 4, drive_strength, omul);
|
||||||
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 4, drive_strength);
|
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 4, drive_strength, mul);
|
||||||
si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq * 4, CLK2_FREQUENCY,
|
si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq / mul * 4, CLK2_FREQUENCY,
|
||||||
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
|
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue