use crate::{ constants::*, errors::*,register::*};
#[derive(Debug,Copy,Clone)]
pub struct Fpfd(pub u32);
impl Fpfd {
pub fn new(
ref_in_hz: u32,
rs: &RegisterSet,
) -> Result<Self,Error> {
(if !(REF_IN_FREQ_MIN .. REF_IN_FREQ_MAX+1).contains(&ref_in_hz) { Err(Error::InvalidReferenceFrequency) } else { Ok(())} )?;
let doubler : RefDoubler = rs.get();
let divider : Rdiv2 = rs.get();
let r : R = rs.get();
let fpfd = ref_in_hz * (1 + doubler as u32) / (r.0 as u32) / (1 + divider as u32);
if fpfd > PFD_FREQ_INTN_MAX {
Err(Error::InvalidReferenceFrequency)
} else {
Ok(Fpfd(fpfd))
}
}
}
#[derive(Debug,Copy,Clone)]
pub struct FracN(pub Fpfd);
impl FracN {
pub fn init(rs: RegisterSet) -> RegisterSet {
rs.set(FeedbackSelect::Fundamental) .set(Ldf::FracN)
.set(Ldp::Ldp10ns)
.set(AntiBacklashPulseWidth::AB6ns)
}
pub fn set_f_out(
self: &Self,
f_out_hz: u64,
rs: RegisterSet
) -> Result<RegisterSet, Error> {
(if !(OUT_FREQ_MIN .. OUT_FREQ_MAX+1).contains(&f_out_hz) { Err(Error::InvalidOutputFrequency) } else { Ok(())} ) ?;
let prescaler : Pr1Prescaler =
if f_out_hz > OUT_FREQ_P45_MAX {
Pr1Prescaler::Pr89
} else {
Pr1Prescaler::Pr45
};
let mut vcof = f_out_hz;
let mut rf_divider_select = 0;
while vcof < VCO_FREQ_MIN { vcof *= 2; rf_divider_select += 1; }
let rmod : Mod = rs.get();
let modulus = rmod.0 as u64;
let nscaled = (vcof * modulus) / self.0.0 as u64;
let int = nscaled / modulus;
let frac = nscaled % modulus;
Ok (
rs.set(Int(int as u16))
.set(Frac(frac as u16))
.set(RfDividerSelect(rf_divider_select))
.set(prescaler)
)
}
pub fn f_out_hz(ref_in_hz: u32, rs: &RegisterSet) -> Result<u64,Error> {
let int : Int = rs.get();
let int = int.0 as u64;
let frac : Frac = rs.get();
let frac = frac.0 as u64;
let modulus : Mod = rs.get();
let modulus = modulus.0 as u64;
let rfdiv : RfDividerSelect = rs.get();
let rfdiv : u64 = 1 << rfdiv.0;
let fpfd = Fpfd::new(ref_in_hz, rs)?;
let fpfd = fpfd.0 as u64;
Ok(
(int*fpfd + frac*fpfd/modulus) / rfdiv
)
}
}