Fixed PLL calculations

This commit is contained in:
Sebastian 2023-08-29 23:38:58 +02:00
parent d19c799151
commit 558bc0d496
1 changed files with 28 additions and 14 deletions

View File

@ -100,14 +100,9 @@ where
}
pub fn set_pll_freq(&mut self, i2c: &mut I2C, pll: PLL, freq: u32) {
let fdiv = freq / self.freq_xtal;
let rm = freq % self.freq_xtal;
// Divider is a + (b/c)
let gcd = num::integer::gcd(rm, self.freq_xtal);
let c = if gcd < 0x0FFFFF { gcd } else { 0x0FFFFF };
let a = fdiv;
let b = ((rm as u64) * (c as u64) / (self.freq_xtal as u64)) as u32;
let (a, b, c) = as_fraction(freq, self.freq_xtal);
let params = PllParams {
p1: 128 * a + (128 * b / c) - 512,
@ -143,14 +138,9 @@ where
pub fn set_ms_freq(&mut self, i2c: &mut I2C, synth: Multisynth, freq: u32) {
let pll = self.ms_srcs[synth as usize];
let fdiv = self.pll_freqs[pll as usize] / freq;
let rm = self.pll_freqs[pll as usize] % freq;
let pll_freq = self.pll_freqs[pll as usize];
let gcd = num::integer::gcd(rm, freq);
let c: u32 = if gcd < 0x0FFFFF { gcd } else { 0x0FFFFF };
let a: u32 = fdiv;
let b: u32 = ((rm as u64) * (c as u64) / (freq as u64)) as u32;
let (a, b, c) = as_fraction(pll_freq, freq);
let params = PllParams {
p1: 128 * a + (128 * b / c) - 512,
@ -207,3 +197,27 @@ where
self.write_params(i2c, synth.base_address(), params);
}
}
// Turns a fraction x/y into a + b/c with minimal c.
// If c is larger than 0x0FFFFF, c will be limited to that value and
// a best effort approximation for b will be computed
fn as_fraction(x: u32, y: u32) -> (u32, u32, u32) {
let gcd = num::integer::gcd(x, y);
let num = x / gcd;
let denom = y / gcd;
let a = num / denom;
if denom < 0x0FFFFF {
let rm = num % denom;
let c = denom;
let b = rm;
(a, b, c)
} else {
let rm = x % y;
let c = 0x0FFFFF;
let b = ((rm as u64) * (c as u64) / (y as u64)) as u32;
(a, b, c)
}
}