urukul: failsave for PLL timeout

This commit is contained in:
occheung 2020-12-18 17:43:59 +08:00
parent adc5807ff1
commit f1069d951d
2 changed files with 67 additions and 3 deletions

View File

@ -253,7 +253,12 @@ where
} }
// Finally, try enabling PLL // Finally, try enabling PLL
else { else {
self.enable_pll(f_sys_clk) self.enable_pll(f_sys_clk)?;
if self.f_sys_clk == self.get_sys_clk_frequency()? {
Ok(())
} else {
Err(Error::WaitRetry)
}
} }
} }
@ -844,6 +849,32 @@ where
pub fn get_f_sys_clk(&mut self) -> f64 { pub fn get_f_sys_clk(&mut self) -> f64 {
self.f_sys_clk self.f_sys_clk
} }
// Acquire real f_sys_clk
pub fn get_sys_clk_frequency(&mut self) -> Result<f64, Error<E>> {
// Calculate the new system clock frequency, examine the clock tree
let mut configuration_queries = [
// Acquire PLL status
(DDSCFRMask::PLL_ENABLE, 0),
// Acquire N-divider, to adjust VCO if necessary
(DDSCFRMask::N, 0),
// Acquire REF_CLK divider bypass
(DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0)
];
self.get_configurations(&mut configuration_queries)?;
if configuration_queries[0].1 == 1 {
// Recalculate sys_clk
let divider :f64 = configuration_queries[1].1.into();
Ok(self.f_ref_clk * divider)
}
else if configuration_queries[2].1 == 0 {
Ok(self.f_ref_clk / 2.0)
}
else {
Ok(self.f_ref_clk)
}
}
} }
// Strong check for bytes passed to a register // Strong check for bytes passed to a register

View File

@ -30,6 +30,16 @@ pub enum Error<E> {
MqttCommandError, MqttCommandError,
VectorOutOfSpace, VectorOutOfSpace,
StringOutOfSpace, StringOutOfSpace,
WaitRetry, // Prompt driver to just wait and retry
}
impl<E> Error<E> {
pub fn is_wait_retry(&self) -> bool {
match self {
Error::WaitRetry => true,
_ => false,
}
}
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -330,16 +340,39 @@ where
} }
pub fn set_channel_sys_clk(&mut self, channel: u8, f_sys_clk: f64) -> Result<(), Error<E>> { pub fn set_channel_sys_clk(&mut self, channel: u8, f_sys_clk: f64) -> Result<(), Error<E>> {
self.dds[usize::from(channel)].set_sys_clk_frequency(f_sys_clk).map(|_| ()) loop {
if let Err(e) = self.dds[usize::from(channel)].set_sys_clk_frequency(f_sys_clk).map(|_| ()) {
if e.is_wait_retry() {
cortex_m::asm::delay(400_000);
} else {
return Err(e);
}
} else {
break;
}
}
Ok(())
} }
pub fn get_channel_sys_clk(&mut self, channel: u8) -> Result<f64, Error<E>> { pub fn get_channel_sys_clk(&mut self, channel: u8) -> Result<f64, Error<E>> {
Ok(self.dds[usize::from(channel)].get_f_sys_clk()) Ok(self.dds[usize::from(channel)].get_f_sys_clk())
} }
pub fn get_channel_calculated_sys_clk(&mut self, channel: u8) -> Result<f64, Error<E>> {
self.dds[usize::from(channel)].get_sys_clk_frequency()
}
pub fn borrow_dds(&mut self, channel: u8) -> &mut DDS<SPI> {
&mut self.dds[usize::from(channel)]
}
pub fn borrow_config_register(&mut self) -> &mut ConfigRegister<SPI> {
&mut self.config_register
}
// Multi-dds channel functions // Multi-dds channel functions
// Do not allow reading of DDS registers // Do not allow reading of DDS registers
// Make sure only 1 SPI transaction is compelted per function call // Make sure only 1 SPI transaction is completed per function call
// Setup NU_MASK in configuration register // Setup NU_MASK in configuration register
// This selects the DDS channels that will be covered by multi_channel DDS (spi3) // This selects the DDS channels that will be covered by multi_channel DDS (spi3)