#![macro_use]
use core::marker::PhantomData;
use embassy_hal_internal::interrupt::InterruptExt;
use embassy_hal_internal::{Peri, PeripheralType};
use crate::interrupt::typelevel::Interrupt as _;
use crate::{interrupt, pac};
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PrescalerOutOfRangeError(u32);
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CompareOutOfRangeError(u32);
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Interrupt {
Tick,
Overflow,
Compare0,
Compare1,
Compare2,
Compare3,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CompareChannel {
_0,
_1,
_2,
_3,
}
pub(crate) trait SealedInstance {
fn regs() -> pac::rtc::Rtc;
}
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
type Interrupt: crate::interrupt::typelevel::Interrupt;
unsafe fn steal() -> Peri<'static, Self>;
}
macro_rules! impl_rtc {
($type:ident, $pac_type:ident, $irq:ident) => {
impl crate::rtc::SealedInstance for peripherals::$type {
#[inline]
fn regs() -> pac::rtc::Rtc {
unsafe { pac::rtc::Rtc::from_ptr(pac::$pac_type.as_ptr()) }
}
}
impl crate::rtc::Instance for peripherals::$type {
type Interrupt = crate::interrupt::typelevel::$irq;
unsafe fn steal() -> embassy_hal_internal::Peri<'static, Self> {
unsafe { peripherals::$type::steal() }
}
}
};
}
pub struct Rtc<'d> {
r: pac::rtc::Rtc,
irq: interrupt::Interrupt,
_phantom: PhantomData<&'d ()>,
}
impl<'d> Rtc<'d> {
pub fn new<T: Instance>(_rtc: Peri<'d, T>, prescaler: u32) -> Result<Self, PrescalerOutOfRangeError> {
if prescaler >= (1 << 12) {
return Err(PrescalerOutOfRangeError(prescaler));
}
T::regs().prescaler().write(|w| w.set_prescaler(prescaler as u16));
Ok(Self {
r: T::regs(),
irq: T::Interrupt::IRQ,
_phantom: PhantomData,
})
}
pub fn new_for_freq<T: Instance>(rtc: Peri<'d, T>, freq_hz: u32) -> Result<Self, PrescalerOutOfRangeError> {
let prescaler = (32_768 / freq_hz).saturating_sub(1);
Self::new(rtc, prescaler)
}
pub unsafe fn steal<T: Instance>() -> Self {
Self {
r: T::regs(),
irq: T::Interrupt::IRQ,
_phantom: PhantomData,
}
}
#[cfg(feature = "unstable-pac")]
#[inline]
pub fn regs(&mut self) -> pac::rtc::Rtc {
self.r
}
#[inline]
pub fn enable(&mut self) {
self.r.tasks_start().write_value(1);
}
#[inline]
pub fn disable(&mut self) {
self.r.tasks_stop().write_value(1);
}
pub fn enable_interrupt(&mut self, int: Interrupt, enable_in_nvic: bool) {
let regs = self.r;
match int {
Interrupt::Tick => regs.intenset().write(|w| w.set_tick(true)),
Interrupt::Overflow => regs.intenset().write(|w| w.set_ovrflw(true)),
Interrupt::Compare0 => regs.intenset().write(|w| w.set_compare(0, true)),
Interrupt::Compare1 => regs.intenset().write(|w| w.set_compare(1, true)),
Interrupt::Compare2 => regs.intenset().write(|w| w.set_compare(2, true)),
Interrupt::Compare3 => regs.intenset().write(|w| w.set_compare(3, true)),
}
if enable_in_nvic {
unsafe { self.irq.enable() };
}
}
pub fn disable_interrupt(&mut self, int: Interrupt, disable_in_nvic: bool) {
let regs = self.r;
match int {
Interrupt::Tick => regs.intenclr().write(|w| w.set_tick(true)),
Interrupt::Overflow => regs.intenclr().write(|w| w.set_ovrflw(true)),
Interrupt::Compare0 => regs.intenclr().write(|w| w.set_compare(0, true)),
Interrupt::Compare1 => regs.intenclr().write(|w| w.set_compare(1, true)),
Interrupt::Compare2 => regs.intenclr().write(|w| w.set_compare(2, true)),
Interrupt::Compare3 => regs.intenclr().write(|w| w.set_compare(3, true)),
}
if disable_in_nvic {
self.irq.disable();
}
}
pub fn enable_event(&mut self, evt: Interrupt) {
let regs = self.r;
match evt {
Interrupt::Tick => regs.evtenset().write(|w| w.set_tick(true)),
Interrupt::Overflow => regs.evtenset().write(|w| w.set_ovrflw(true)),
Interrupt::Compare0 => regs.evtenset().write(|w| w.set_compare(0, true)),
Interrupt::Compare1 => regs.evtenset().write(|w| w.set_compare(1, true)),
Interrupt::Compare2 => regs.evtenset().write(|w| w.set_compare(2, true)),
Interrupt::Compare3 => regs.evtenset().write(|w| w.set_compare(3, true)),
}
}
pub fn disable_event(&mut self, evt: Interrupt) {
let regs = self.r;
match evt {
Interrupt::Tick => regs.evtenclr().write(|w| w.set_tick(true)),
Interrupt::Overflow => regs.evtenclr().write(|w| w.set_ovrflw(true)),
Interrupt::Compare0 => regs.evtenclr().write(|w| w.set_compare(0, true)),
Interrupt::Compare1 => regs.evtenclr().write(|w| w.set_compare(1, true)),
Interrupt::Compare2 => regs.evtenclr().write(|w| w.set_compare(2, true)),
Interrupt::Compare3 => regs.evtenclr().write(|w| w.set_compare(3, true)),
}
}
pub fn reset_event(&mut self, evt: Interrupt) {
let regs = self.r;
match evt {
Interrupt::Tick => regs.events_tick().write_value(0),
Interrupt::Overflow => regs.events_ovrflw().write_value(0),
Interrupt::Compare0 => regs.events_compare(0).write_value(0),
Interrupt::Compare1 => regs.events_compare(1).write_value(0),
Interrupt::Compare2 => regs.events_compare(2).write_value(0),
Interrupt::Compare3 => regs.events_compare(3).write_value(0),
}
}
pub fn is_event_triggered(&self, evt: Interrupt) -> bool {
let regs = self.r;
let val = match evt {
Interrupt::Tick => regs.events_tick().read(),
Interrupt::Overflow => regs.events_ovrflw().read(),
Interrupt::Compare0 => regs.events_compare(0).read(),
Interrupt::Compare1 => regs.events_compare(1).read(),
Interrupt::Compare2 => regs.events_compare(2).read(),
Interrupt::Compare3 => regs.events_compare(3).read(),
};
val == 1
}
pub fn set_compare(&mut self, reg: CompareChannel, val: u32) -> Result<(), CompareOutOfRangeError> {
if val >= (1 << 24) {
return Err(CompareOutOfRangeError(val));
}
let reg = match reg {
CompareChannel::_0 => 0,
CompareChannel::_1 => 1,
CompareChannel::_2 => 2,
CompareChannel::_3 => 3,
};
self.r.cc(reg).write(|w| w.set_compare(val));
Ok(())
}
#[inline]
pub fn clear(&self) {
self.r.tasks_clear().write_value(1);
}
#[inline]
pub fn read(&self) -> u32 {
self.r.counter().read().counter()
}
}