use crate::hal::timer::{CountDown, Periodic};
use crate::pac::RTT;
use embedded_time::duration::*;
use embedded_time::rate::*;
use void::Void;
pub struct RealTimeTimer {
rtt: RTT,
rtc1hz: bool, }
impl Periodic for RealTimeTimer {}
impl CountDown for RealTimeTimer {
type Time = Microseconds;
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 prescaler = self.rtt.mr.read().rtpres().bits();
let period: Microseconds = if self.rtc1hz {
1_u32.Hz().to_duration().unwrap()
} else {
let slck_duration: Microseconds = 32_768_u32.Hz().to_duration().unwrap();
match prescaler {
0 => slck_duration * 2_u32.pow(16),
1 | 2 => 1_u32.Hz().to_duration().unwrap(), _ => slck_duration * prescaler.into(),
}
};
let timeout: u32 = *timeout.into().integer();
let period: u32 = *period.integer();
let alarmv = timeout / period;
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 RealTimeTimer {
pub fn new(rtt: RTT, prescaler: u16, rtc1hz: bool) -> Self {
rtt.mr
.modify(|_, w| w.rttdis().set_bit().rttincien().clear_bit());
rtt.mr.modify(|_, w| unsafe {
w.rtpres()
.bits(prescaler)
.rtc1hz()
.bit(rtc1hz)
.rttrst()
.set_bit()
});
Self { rtt, rtc1hz }
}
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());
}
}