Move checks in new() so initialize() cannot fail.

This commit is contained in:
Nic0w 2021-04-29 21:06:11 +02:00
parent eb4ebc782a
commit 5620bdbd07

View file

@ -18,7 +18,12 @@ use nb::Error::WouldBlock;
pub trait State {} pub trait State {}
/// PLL is disabled. /// PLL is disabled.
pub struct Disabled; pub struct Disabled {
refdiv: u8,
fbdiv: u16,
post_div1: u8,
post_div2: u8,
}
/// PLL is configured, started and locking into its designated frequency. /// PLL is configured, started and locking into its designated frequency.
pub struct Locking { pub struct Locking {
@ -118,19 +123,11 @@ pub mod common_configs {
impl<D: PhaseLockedLoopDevice> PhaseLockedLoop<Disabled, D> { impl<D: PhaseLockedLoopDevice> PhaseLockedLoop<Disabled, D> {
/// Instantiates a new Phase-Locked-Loop device. /// Instantiates a new Phase-Locked-Loop device.
pub fn new(dev: D) -> PhaseLockedLoop<Disabled, D> { pub fn new<R: Rate>(
PhaseLockedLoop { dev: D,
state: Disabled,
device: dev,
}
}
/// Configures and starts the PLL : it switches to Locking state.
pub fn initialize<R: Rate>(
self,
xosc_frequency: Generic<u32>, xosc_frequency: Generic<u32>,
config: PLLConfig<R>, config: PLLConfig<R>,
) -> Result<PhaseLockedLoop<Locking, D>, Error> ) -> Result<PhaseLockedLoop<Disabled, D>, Error>
where where
R: Into<Hertz<u64>>, R: Into<Hertz<u64>>,
{ {
@ -155,10 +152,6 @@ impl<D: PhaseLockedLoopDevice> PhaseLockedLoop<Disabled, D> {
let ref_freq_range: Range<Hertz<u32>> = Hertz(5_000_000)..vco_freq.div(16); let ref_freq_range: Range<Hertz<u32>> = Hertz(5_000_000)..vco_freq.div(16);
// Turn off PLL in case it is already running
self.device.pwr.reset();
self.device.fbdiv_int.reset();
let ref_freq_hz = Hertz::<u32>::try_from(xosc_frequency) let ref_freq_hz = Hertz::<u32>::try_from(xosc_frequency)
.map_err(|_| Error::BadArgument)? .map_err(|_| Error::BadArgument)?
.checked_div(&(config.refdiv as u32)) .checked_div(&(config.refdiv as u32))
@ -168,11 +161,6 @@ impl<D: PhaseLockedLoopDevice> PhaseLockedLoop<Disabled, D> {
return Err(Error::RefFreqOutOfRange); return Err(Error::RefFreqOutOfRange);
} }
self.device.cs.write(|w| unsafe {
w.refdiv().bits(config.refdiv);
w
});
let fbdiv = vco_freq let fbdiv = vco_freq
.checked_div(ref_freq_hz.integer()) .checked_div(ref_freq_hz.integer())
.ok_or(Error::BadArgument)?; .ok_or(Error::BadArgument)?;
@ -185,8 +173,34 @@ impl<D: PhaseLockedLoopDevice> PhaseLockedLoop<Disabled, D> {
return Err(Error::FBDIVOutOfRange); return Err(Error::FBDIVOutOfRange);
} }
let refdiv = config.refdiv;
let post_div1 = config.post_div1;
let post_div2 = config.post_div2;
Ok(PhaseLockedLoop {
state: Disabled {
refdiv,
fbdiv,
post_div1,
post_div2,
},
device: dev,
})
}
/// Configures and starts the PLL : it switches to Locking state.
pub fn initialize(self) -> PhaseLockedLoop<Locking, D> {
// Turn off PLL in case it is already running
self.device.pwr.reset();
self.device.fbdiv_int.reset();
self.device.cs.write(|w| unsafe {
w.refdiv().bits(self.state.refdiv);
w
});
self.device.fbdiv_int.write(|w| unsafe { self.device.fbdiv_int.write(|w| unsafe {
w.fbdiv_int().bits(fbdiv); w.fbdiv_int().bits(self.state.fbdiv);
w w
}); });
@ -197,13 +211,13 @@ impl<D: PhaseLockedLoopDevice> PhaseLockedLoop<Disabled, D> {
w w
}); });
let post_div1 = config.post_div1; let post_div1 = self.state.post_div1;
let post_div2 = config.post_div2; let post_div2 = self.state.post_div2;
Ok(self.transition(Locking { self.transition(Locking {
post_div1, post_div1,
post_div2, post_div2,
})) })
} }
} }