use crate::hal::timer::{CountDown, Periodic};
use crate::pac::RTT;
use fugit::{ExtU32, TimerDurationU32 as TimerDuration};
use void::Void;
const SLCK_FREQ: u32 = 32_768;
pub struct RealTimeTimer<const PRESCALER: usize, const RTC1HZ: bool> {
rtt: RTT,
}
impl<const PRESCALER: usize, const RTC1HZ: bool> Periodic for RealTimeTimer<PRESCALER, RTC1HZ> {}
impl<const PRESCALER: usize, const RTC1HZ: bool> CountDown for RealTimeTimer<PRESCALER, RTC1HZ> {
type Time = TimerDuration<SLCK_FREQ>;
fn start<T>(&mut self, timeout: T)
where
T: Into<Self::Time>,
{
self.rtt.mr.modify(|_, w| w.rttdis().set_bit());
let rtt_mr = self.rtt.mr.read();
let almien = rtt_mr.almien().bit_is_set();
let rttincien = rtt_mr.rttincien().bit_is_set();
let timeout: TimerDuration<SLCK_FREQ> = timeout.into();
let period: Self::Time = if RTC1HZ {
assert_eq!(
PRESCALER,
(u16::MAX / 2) as usize,
"Prescaler must be set to 32768 for RTC1HZ"
);
1.secs()
} else {
let slck_duration: TimerDuration<SLCK_FREQ> = TimerDuration::from_ticks(1);
match PRESCALER {
0 => slck_duration * 2_u32.pow(16),
1 | 2 => {
panic!("Invalid prescaler");
}
_ => slck_duration * PRESCALER as u32,
}
};
let alarmv = timeout / period;
defmt::trace!(
"RTT: timeout:{:?} period:{:?} alarmv:{:?}",
timeout,
period,
alarmv
);
if almien {
self.disable_alarm_interrupt();
}
if rttincien {
self.disable_prescaler_interrupt();
}
self.rtt.ar.write(|w| unsafe { w.almv().bits(alarmv) });
if almien {
self.enable_alarm_interrupt();
}
if rttincien {
self.enable_prescaler_interrupt();
}
self.rtt.mr.modify(|_, w| w.rttdis().clear_bit());
self.rtt.mr.modify(|_, w| w.rttrst().set_bit());
}
fn wait(&mut self) -> nb::Result<(), Void> {
let rtt_sr = self.rtt.sr.read();
if rtt_sr.alms().bit_is_set() {
self.rtt.mr.modify(|_, w| w.rttrst().set_bit());
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<const PRESCALER: usize, const RTC1HZ: bool> RealTimeTimer<PRESCALER, RTC1HZ> {
pub fn new(rtt: RTT) -> Self {
crate::sealed::not_one_or_two::<PRESCALER>();
crate::sealed::smaller_than_or_eq::<PRESCALER, { u16::MAX as usize }>();
rtt.mr
.modify(|_, w| w.rttdis().set_bit().rttincien().clear_bit());
rtt.mr.modify(|_, w| unsafe {
w.rtpres()
.bits(PRESCALER as u16)
.rtc1hz()
.bit(RTC1HZ)
.rttrst()
.set_bit()
});
Self { rtt }
}
pub fn enable_alarm_interrupt(&mut self) {
self.rtt.mr.modify(|_, w| w.almien().set_bit());
}
pub fn enable_prescaler_interrupt(&mut self) {
self.rtt.mr.modify(|_, w| w.rttincien().set_bit());
}
pub fn disable_alarm_interrupt(&mut self) {
self.rtt.mr.modify(|_, w| w.almien().clear_bit());
}
pub fn disable_prescaler_interrupt(&mut self) {
self.rtt.mr.modify(|_, w| w.rttincien().clear_bit());
}
pub fn clear_interrupt_flags(&mut self) {
let _rtt_sr = self.rtt.sr.read();
self.rtt.mr.modify(|_, w| w.rttrst().set_bit());
}
}