use crate::pac;
use crate::rcu::{IRC40K, Rcu};
use crate::time::Duration;
const RLD_MAX: u16 = 0xFFF;
const RLD_SPAN: u32 = RLD_MAX as u32 + 1;
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(missing_docs)]
pub enum FwdgtPsc {
Div4 = 0b000,
Div8 = 0b001,
Div16 = 0b010,
Div32 = 0b011,
Div64 = 0b100,
Div128 = 0b101,
Div256 = 0b110,
}
impl FwdgtPsc {
const ALL: [Self; 7] = [
Self::Div4,
Self::Div8,
Self::Div16,
Self::Div32,
Self::Div64,
Self::Div128,
Self::Div256,
];
const fn divider(self) -> u32 {
4 << (self as u8)
}
}
fn dividers(ticks: u32) -> (FwdgtPsc, u16) {
let ticks = ticks.max(1);
for psc in FwdgtPsc::ALL {
let div = psc.divider();
if ticks <= RLD_SPAN * div {
return (psc, (ticks / div).saturating_sub(1) as u16);
}
}
(FwdgtPsc::Div256, RLD_MAX)
}
fn timeout_to_ticks<const NOM: u64, const DENOM: u64>(
timeout: Duration<u32, NOM, DENOM>,
clock: u32,
) -> u32 {
let raw_time = u64::from(timeout.as_ticks());
let raw_freq = u64::from(clock);
(raw_time.saturating_mul(raw_freq).saturating_mul(NOM) / DENOM).min(u32::MAX.into()) as u32
}
pub struct Fwdgt {
fwdgt: pac::Fwdgt,
}
impl Fwdgt {
pub fn start(self, psc: FwdgtPsc, rld: u16) -> FwdgtRunning {
assert!(rld <= RLD_MAX, "FWDGT reload must fit in 12 bits");
self.fwdgt.ctl().write(|w| w.cmd().enable());
self.fwdgt.psc().write(|w| w.psc().bits(psc as u8));
self.fwdgt.rld().write(|w| w.rld().bits(rld));
while self.fwdgt.stat().read().pud().is_ongoing() {}
while self.fwdgt.stat().read().rud().is_ongoing() {}
self.fwdgt.ctl().write(|w| w.cmd().reset());
self.fwdgt.ctl().write(|w| w.cmd().start());
FwdgtRunning { fwdgt: self.fwdgt }
}
pub fn start_timeout<const NOM: u64, const DENOM: u64>(
self,
timeout: Duration<u32, NOM, DENOM>,
) -> FwdgtRunning {
let (psc, rld) = dividers(timeout_to_ticks(timeout, IRC40K));
self.start(psc, rld)
}
}
pub struct FwdgtRunning {
fwdgt: pac::Fwdgt,
}
impl FwdgtRunning {
pub fn feed(&mut self) {
self.fwdgt.ctl().write(|w| w.cmd().reset());
}
}
pub trait FwdgtExt {
fn constrain(self, rcu: &mut Rcu) -> Fwdgt;
}
impl FwdgtExt for pac::Fwdgt {
fn constrain(self, rcu: &mut Rcu) -> Fwdgt {
rcu.enable_irc40k();
Fwdgt { fwdgt: self }
}
}