use crate::clocks::{Clocks, LfOscStarted};
use core::marker::PhantomData;
pub use rtic_monotonic::Monotonic;
#[cfg(any(feature = "9160", feature = "5340-app", feature = "5340-net"))]
use crate::pac::{rtc0_ns::RegisterBlock as RtcRegBlock, RTC0_NS as RTC0, RTC1_NS as RTC1};
#[cfg(not(any(feature = "9160", feature = "5340-app", feature = "5340-net")))]
use crate::pac::{rtc0::RegisterBlock as RtcRegBlock, RTC0, RTC1};
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
use crate::pac::RTC2;
#[cfg(any(feature = "9160", feature = "5340-app", feature = "5340-net"))]
use crate::pac::{
timer0_ns::RegisterBlock as TimerRegBlock, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1,
TIMER2_NS as TIMER2,
};
#[cfg(not(any(feature = "9160", feature = "5340-app", feature = "5340-net")))]
use crate::pac::{timer0::RegisterBlock as TimerRegBlock, TIMER0, TIMER1, TIMER2};
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
use crate::pac::{TIMER3, TIMER4};
mod sealed {
pub trait Instance {
type RegBlock;
fn reg<'a>() -> &'a Self::RegBlock;
}
pub trait RtcInstance: Instance<RegBlock = super::RtcRegBlock> {}
pub trait TimerInstance: Instance<RegBlock = super::TimerRegBlock> {
fn set_compare<const IDX: usize>(compare: u32);
fn clear_compare_flag<const IDX: usize>();
fn enable_compare<const IDX: usize>();
}
}
pub use sealed::{Instance, RtcInstance, TimerInstance};
#[derive(Debug)]
pub enum Error {
InvalidFrequency(u32),
TooLargePrescaler(u32),
}
pub struct MonotonicRtc<T: RtcInstance, const FREQ: u32> {
instance: PhantomData<T>,
overflow: u8,
}
impl<T, const FREQ: u32> MonotonicRtc<T, FREQ>
where
T: RtcInstance,
{
const MAX_PRESCALER: u32 = 4096;
pub fn new<H, L>(_: T, _: &Clocks<H, L, LfOscStarted>) -> Result<Self, Error> {
let presc = Self::prescaler()?;
unsafe { T::reg().prescaler.write(|w| w.bits(presc)) };
Ok(Self {
instance: PhantomData,
overflow: 0,
})
}
const fn prescaler() -> Result<u32, Error> {
let intermediate: u32 = 32_768 / FREQ;
let presc: u32 = (32_768 / FREQ) - 1;
if presc >= Self::MAX_PRESCALER {
return Err(Error::TooLargePrescaler(FREQ));
}
match 32_768 / intermediate == FREQ && presc < Self::MAX_PRESCALER {
true => Ok(presc),
_ => Err(Error::InvalidFrequency(FREQ)),
}
}
}
impl<T: RtcInstance, const FREQ: u32> Monotonic for MonotonicRtc<T, FREQ> {
type Instant = fugit::TimerInstantU32<FREQ>;
type Duration = fugit::TimerDurationU32<FREQ>;
const DISABLE_INTERRUPT_ON_EMPTY_QUEUE: bool = false;
fn now(&mut self) -> Self::Instant {
let rtcreg = T::reg();
let cnt = rtcreg.counter.read().bits();
let ovf = (if rtcreg.events_ovrflw.read().bits() == 1 {
self.overflow.wrapping_add(1)
} else {
self.overflow
}) as u32;
fugit::TimerInstantU32::<FREQ>::from_ticks((ovf << 24) | cnt)
}
fn set_compare(&mut self, instant: Self::Instant) {
let now = self.now();
const MIN_TICKS_FOR_COMPARE: u32 = 3;
let val = match instant.checked_duration_since(now) {
Some(x) if x.ticks() <= 0xffffff && x.ticks() > MIN_TICKS_FOR_COMPARE => {
instant.duration_since_epoch().ticks() & 0xffffff
}
Some(x) => {
(instant.duration_since_epoch().ticks() + (MIN_TICKS_FOR_COMPARE - x.ticks()))
& 0xffffff
}
_ => 0, } as u32;
unsafe { T::reg().cc[0].write(|w| w.bits(val)) };
}
fn clear_compare_flag(&mut self) {
unsafe {
T::reg().events_compare[0].write(|w| w.bits(0));
}
}
unsafe fn reset(&mut self) {
let rtc = T::reg();
rtc.intenset.write(|w| w.compare0().set().ovrflw().set());
rtc.evtenset.write(|w| w.compare0().set().ovrflw().set());
rtc.tasks_clear.write(|w| w.bits(1));
rtc.tasks_start.write(|w| w.bits(1));
}
fn zero() -> Self::Instant {
Self::Instant::from_ticks(0)
}
}
pub struct MonotonicTimer<T: TimerInstance, const FREQ: u32> {
instance: PhantomData<T>,
}
impl<T: TimerInstance, const FREQ: u32> MonotonicTimer<T, FREQ> {
pub fn internal_new<const PRESC: u8>() -> Self {
let reg = T::reg();
reg.prescaler
.write(|w| unsafe { w.prescaler().bits(PRESC) });
reg.bitmode.write(|w| w.bitmode()._32bit());
reg.mode.write(|w| w.mode().timer());
Self {
instance: PhantomData,
}
}
}
impl<T: TimerInstance, const FREQ: u32> Monotonic for MonotonicTimer<T, FREQ> {
type Instant = fugit::TimerInstantU32<FREQ>;
type Duration = fugit::TimerDurationU32<FREQ>;
fn now(&mut self) -> Self::Instant {
let reg: &TimerRegBlock = T::reg();
T::enable_compare::<1>();
let ticks = reg.cc[1].read().bits();
fugit::TimerInstantU32::<FREQ>::from_ticks(ticks.into())
}
fn set_compare(&mut self, instant: Self::Instant) {
T::set_compare::<2>(instant.duration_since_epoch().ticks())
}
fn clear_compare_flag(&mut self) {
T::clear_compare_flag::<2>();
}
fn zero() -> Self::Instant {
Self::Instant::from_ticks(0)
}
unsafe fn reset(&mut self) {
let reg = T::reg();
reg.intenset.write(|w| w.compare2().set());
reg.tasks_clear.write(|w| w.bits(1));
reg.tasks_start.write(|w| w.bits(1));
}
}
macro_rules! impl_instance {
(TimerRegBlock,$peripheral:ident) => {
impl TimerInstance for $peripheral {
fn set_compare<const IDX:usize>(compare:u32){
#[cfg(feature = "51")]
Self::reg().cc[IDX].write(|w| unsafe{w.bits(compare)});
#[cfg(not(feature = "51"))]
Self::reg().cc[IDX].write(|w| w.cc().variant(compare));
}
fn clear_compare_flag<const IDX:usize>(){
#[cfg(any(feature = "52832", feature = "51"))]
Self::reg().events_compare[2].write(|w| unsafe { w.bits(0) });
#[cfg(not(any(feature = "52832", feature = "51")))]
Self::reg().events_compare[2].write(|w| w.events_compare().clear_bit());
}
fn enable_compare<const IDX:usize>() {
#[cfg(any(feature = "52832", feature = "51"))]
Self::reg().tasks_capture[IDX].write(|w| unsafe { w.bits(1 << 31) });
#[cfg(not(any(feature = "52832", feature = "51")))]
Self::reg().tasks_capture[IDX].write(|w| w.tasks_capture().set_bit());
}
}
};
(RtcRegBlock,$peripheral:ident) => {
impl RtcInstance for $peripheral {}
};
(
$(
$reg:ident : {
$(
$(#[$feature_gate:meta])?
$peripheral:ident
)+
}
)+
) => {
$(
$(
$( #[$feature_gate] )?
impl Instance for $peripheral {
type RegBlock = $reg;
fn reg<'a>() -> &'a Self::RegBlock {
unsafe { & *Self::ptr().cast() }
}
}
impl_instance!($reg,$peripheral);
)+
)+
};
}
macro_rules! freq_gate {
(
$(
$freq:literal,$presc:literal
)+
) => (
$(
impl<T:TimerInstance> MonotonicTimer<T,$freq>
{
pub fn new(_: T) -> Self {
Self::internal_new::<$presc>()
}
}
)+
)
}
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
impl_instance! {
TimerRegBlock : {
TIMER0 TIMER1 TIMER2
TIMER3
TIMER4
}
RtcRegBlock : {
RTC0 RTC1
RTC2
}
}
#[cfg(not(any(feature = "52832", feature = "52833", feature = "52840")))]
impl_instance! {
TimerRegBlock : {
TIMER0 TIMER1 TIMER2
}
RtcRegBlock : {
RTC0 RTC1
}
}
freq_gate! {
16_000_000,0
8_000_000,1
4_000_000,2
2_000_000,3
1_000_000,4
500_000,5
250_000,6
125_000,7
62_500,8
}