use embedded_hal::timer::{Cancel, CountDown, Periodic};
use crate::clock_control::ClockControlConfig;
use crate::prelude::*;
use crate::target;
use crate::target::{TIMG0, TIMG1};
use core::marker::PhantomData;
pub mod watchdog;
#[derive(Debug)]
pub enum Error {
UnsupportedWatchdogConfig,
OutOfRange,
Disabled,
}
pub struct Timer<TIMG: TimerGroup, INST: TimerInst> {
clock_control_config: ClockControlConfig,
timg: *const target::timg::RegisterBlock,
_group: PhantomData<TIMG>,
_timer: PhantomData<INST>,
}
unsafe impl<TIMG: TimerGroup, INST: TimerInst> Send for Timer<TIMG, INST> {}
pub enum Event {
TimeOut,
TimeOutEdge,
}
#[doc(hidden)]
pub trait TimerGroup: core::ops::Deref {}
impl TimerGroup for target::TIMG0 {}
impl TimerGroup for target::TIMG1 {}
#[doc(hidden)]
pub trait TimerInst {}
pub trait TimerWithInterrupt: CountDown + Periodic + Cancel {
fn listen(&mut self, event: Event);
fn unlisten(&mut self, event: Event);
fn clear_interrupt(&mut self) -> &mut Self;
fn set_value<T: Into<TicksU64>>(&mut self, value: T) -> &mut Self;
fn get_value(&self) -> TicksU64;
fn get_value_in_ns(&self) -> NanoSecondsU64;
fn get_alarm(&self) -> TicksU64;
fn get_alarm_in_ns(&self) -> NanoSecondsU64;
fn set_alarm<T: Into<TicksU64>>(&mut self, value: T) -> &mut Self;
fn set_alarm_in_ns<T: Into<NanoSecondsU64>>(&mut self, value: T) -> &mut Self;
fn enable(&mut self, enable: bool) -> &mut Self;
fn is_enabled(&mut self) -> bool;
fn stop(&mut self);
fn increasing(&mut self, enable: bool) -> &mut Self;
fn is_increasing(&mut self) -> bool;
fn auto_reload(&mut self, enable: bool) -> &mut Self;
fn enable_alarm(&mut self, enable: bool) -> &mut Self;
fn alarm_active(&mut self) -> bool;
fn set_divider(&mut self, divider: u32) -> Result<&mut Self, Error>;
fn get_divider(&self) -> u32;
}
impl<TIMG: TimerGroup> Timer<TIMG, Timer0> {
pub fn new(
timg: TIMG,
clock_control_config: ClockControlConfig,
) -> (
Timer<TIMG, Timer0>,
Timer<TIMG, Timer1>,
Timer<TIMG, TimerLact>,
watchdog::Watchdog<TIMG>,
) {
let timer0 = Timer::<TIMG, Timer0> {
clock_control_config,
timg: &*timg as *const _ as *const target::timg::RegisterBlock,
_group: PhantomData {},
_timer: PhantomData {},
};
let timer1 = Timer::<TIMG, Timer1> {
clock_control_config,
timg: &*timg as *const _ as *const target::timg::RegisterBlock,
_group: PhantomData {},
_timer: PhantomData {},
};
let mut timerlact = Timer::<TIMG, TimerLact> {
clock_control_config,
timg: &*timg as *const _ as *const target::timg::RegisterBlock,
_group: PhantomData {},
_timer: PhantomData {},
};
timerlact.set_rtc_step(
clock_control_config.apb_frequency() / clock_control_config.rtc_frequency(),
);
(
timer0,
timer1,
timerlact,
watchdog::Watchdog::new(timg, clock_control_config),
)
}
}
impl<INST: TimerInst> Timer<TIMG0, INST> {
pub fn release(
_timer0: Timer<TIMG0, Timer0>,
_timer1: Timer<TIMG0, Timer1>,
_timer2: Timer<TIMG0, TimerLact>,
) -> TIMG0 {
unsafe { target::Peripherals::steal().TIMG0 }
}
}
impl<INST: TimerInst> Timer<TIMG1, INST> {
pub fn release(
_timer0: Timer<TIMG1, Timer0>,
_timer1: Timer<TIMG1, Timer1>,
_timer2: Timer<TIMG1, TimerLact>,
) -> TIMG1 {
unsafe { target::Peripherals::steal().TIMG1 }
}
}
static TIMER_MUTEX: CriticalSectionSpinLockMutex<()> = CriticalSectionSpinLockMutex::new(());
macro_rules! timer {
($TIMX:ident, $INT_ENA:ident, $CONFIG:ident, $HI:ident, $LO: ident,
$LOAD: ident, $LOAD_HI: ident, $LOAD_LO:ident, $UPDATE:ident, $ALARM_HI:ident,
$ALARM_LO:ident, $EN:ident, $INCREASE:ident, $AUTO_RELOAD:ident, $DIVIDER:ident,
$EDGE_INT_EN:ident, $LEVEL_INT_EN:ident, $ALARM_EN:ident,
$INT_RAW:ident, $INT_ST:ident, $INT_CLR:ident, $MIN_DIV:expr, $MAX_DIV:expr
) => {
#[doc(hidden)]
pub struct $TIMX {}
impl TimerInst for $TIMX {}
impl<TIMG: TimerGroup> TimerWithInterrupt for Timer<TIMG, $TIMX> {
fn listen(&mut self, event: Event) {
match event {
Event::TimeOut => self.enable_level_interrupt(true),
Event::TimeOutEdge => self.enable_edge_interrupt(true),
};
unsafe {
(&TIMER_MUTEX).lock(|_| {
(*(self.timg))
.int_ena_timers
.modify(|_, w| w.$INT_ENA().set_bit());
})
};
}
fn unlisten(&mut self, event: Event) {
match event {
Event::TimeOut => self.enable_level_interrupt(false),
Event::TimeOutEdge => self.enable_edge_interrupt(false),
};
}
fn clear_interrupt(&mut self) -> &mut Self {
self.enable_alarm(true);
unsafe {
(*(self.timg))
.int_clr_timers
.write(|w| w.$INT_CLR().set_bit())
}
self
}
fn set_value<T: Into<TicksU64>>(&mut self, value: T) -> &mut Self {
unsafe {
let timg = &*(self.timg);
let value: u64 = value.into().into();
timg.$LOAD_LO.write(|w| w.bits(value as u32));
timg.$LOAD_HI.write(|w| w.bits((value >> 32) as u32));
timg.$LOAD.write(|w| w.bits(1));
}
self
}
fn get_value(&self) -> TicksU64 {
unsafe {
let timg = &*(self.timg);
timg.$UPDATE.write(|w| w.bits(1));
TicksU64(
((timg.$HI.read().bits() as u64) << 32) | (timg.$LO.read().bits() as u64),
)
}
}
fn get_value_in_ns(&self) -> NanoSecondsU64 {
self.get_value() / (self.clock_control_config.apb_frequency() / self.get_divider())
}
fn get_alarm(&self) -> TicksU64 {
unsafe {
let timg = &*(self.timg);
TicksU64(
((timg.$ALARM_HI.read().bits() as u64) << 32)
| (timg.$ALARM_LO.read().bits() as u64),
)
}
}
fn get_alarm_in_ns(&self) -> NanoSecondsU64 {
self.get_alarm() / (self.clock_control_config.apb_frequency() / self.get_divider())
}
fn set_alarm<T: Into<TicksU64>>(&mut self, value: T) -> &mut Self {
unsafe {
let timg = &*(self.timg);
let value = value.into() / TicksU64(1);
timg.$ALARM_HI.write(|w| w.bits((value >> 32) as u32));
timg.$ALARM_LO.write(|w| w.bits(value as u32));
}
self
}
fn set_alarm_in_ns<T: Into<NanoSecondsU64>>(&mut self, value: T) -> &mut Self {
self.set_alarm(
self.clock_control_config.apb_frequency() / self.get_divider() * value.into(),
)
}
fn enable(&mut self, enable: bool) -> &mut Self {
unsafe { (*(self.timg)).$CONFIG.modify(|_, w| w.$EN().bit(enable)) }
self
}
fn is_enabled(&mut self) -> bool {
unsafe { (*(self.timg)).$CONFIG.read().$EN().bit_is_set() }
}
fn stop(&mut self) {
self.enable(false);
}
fn increasing(&mut self, enable: bool) -> &mut Self {
unsafe {
(*(self.timg))
.$CONFIG
.modify(|_, w| w.$INCREASE().bit(enable))
}
self
}
fn is_increasing(&mut self) -> bool {
unsafe { (*(self.timg)).$CONFIG.read().$INCREASE().bit_is_set() }
}
fn auto_reload(&mut self, enable: bool) -> &mut Self {
unsafe {
(*(self.timg))
.$CONFIG
.modify(|_, w| w.$AUTO_RELOAD().bit(enable))
}
self
}
fn enable_alarm(&mut self, enable: bool) -> &mut Self {
unsafe {
(*(self.timg))
.$CONFIG
.modify(|_, w| w.$ALARM_EN().bit(enable))
}
self
}
fn alarm_active(&mut self) -> bool {
unsafe { (*(self.timg)).$CONFIG.read().$ALARM_EN().bit_is_clear() }
}
fn set_divider(&mut self, divider: u32) -> Result<&mut Self, Error> {
if divider < $MIN_DIV || divider > $MAX_DIV {
return Err(Error::OutOfRange);
}
unsafe {
(*(self.timg)).$CONFIG.modify(|_, w| {
w.$DIVIDER()
.bits((if divider == 65536 { 0 } else { divider }) as u16)
})
};
Ok(self)
}
fn get_divider(&self) -> u32 {
let divider = unsafe { (*(self.timg)).$CONFIG.read().$DIVIDER().bits() };
if (divider == 0) {
65536
} else {
divider as u32
}
}
}
impl<TIMG: TimerGroup> Timer<TIMG, $TIMX> {
fn enable_edge_interrupt(&mut self, enable: bool) -> &mut Self {
unsafe {
(*(self.timg))
.$CONFIG
.modify(|_, w| w.$EDGE_INT_EN().bit(enable))
}
self
}
fn enable_level_interrupt(&mut self, enable: bool) -> &mut Self {
unsafe {
(*(self.timg))
.$CONFIG
.modify(|_, w| w.$LEVEL_INT_EN().bit(enable))
}
self
}
}
impl<TIMG: TimerGroup> Periodic for Timer<TIMG, $TIMX> {}
impl<TIMG: TimerGroup> CountDown for Timer<TIMG, $TIMX> {
type Time = NanoSecondsU64;
fn start<T: Into<Self::Time>>(&mut self, timeout: T) {
let alarm = self.clock_control_config.apb_frequency() / $MIN_DIV * timeout.into();
self.enable(false)
.set_divider($MIN_DIV)
.unwrap()
.auto_reload(true)
.set_value(0)
.set_alarm(alarm)
.enable_alarm(true)
.enable(true);
}
fn wait(&mut self) -> nb::Result<(), void::Void> {
if self.alarm_active() {
self.clear_interrupt();
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<TIMG: TimerGroup> Cancel for Timer<TIMG, $TIMX> {
type Error = Error;
fn cancel(&mut self) -> Result<(), Self::Error> {
if !self.is_enabled() {
return Err(Self::Error::Disabled);
}
self.stop();
Ok(())
}
}
};
}
impl<TIMG: TimerGroup> Timer<TIMG, TimerLact> {
fn set_rtc_step(&mut self, ticks: u32) -> &mut Self {
unsafe {
(*(self.timg))
.lactrtc
.modify(|_, w| w.lact_rtc_step_len().bits(ticks.into()));
};
self
}
}
timer!(
Timer0,
t0_int_ena,
t0config,
t0hi,
t0lo,
t0load,
t0loadhi,
t0loadlo,
t0update,
t0alarmhi,
t0alarmlo,
t0_en,
t0_increase,
t0_autoreload,
t0_divider,
t0_edge_int_en,
t0_level_int_en,
t0_alarm_en,
t0_int_raw,
t0_int_st,
t0_int_clr,
2,
65536
);
timer!(
Timer1,
t1_int_ena,
t1config,
t1hi,
t1lo,
t1load,
t1loadhi,
t1loadlo,
t1update,
t1alarmhi,
t1alarmlo,
t1_en,
t1_increase,
t1_autoreload,
t1_divider,
t1_edge_int_en,
t1_level_int_en,
t1_alarm_en,
t1_int_raw,
t1_int_st,
t1_int_clr,
2,
65536
);
timer!(
TimerLact,
lact_int_ena,
lactconfig,
lacthi,
lactlo,
lactload,
lactloadhi,
lactloadlo,
lactupdate,
lactalarmhi,
lactalarmlo,
lact_en,
lact_increase,
lact_autoreload,
lact_divider,
lact_edge_int_en,
lact_level_int_en,
lact_alarm_en,
lact_int_raw,
lact_int_st,
lact_int_clr,
3,
65535
);