use crate::pac;
use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
use pac::Rtc;
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
use crate::pac::rtc::mode0::ctrl::Prescalerselect;
#[hal_cfg("rtc-d5x")]
use crate::pac::rtc::mode0::ctrla::Prescalerselect;
pub trait RtcInterrupt {
fn enable(rtc: &Rtc);
fn disable(rtc: &Rtc);
fn check_flag(rtc: &Rtc) -> bool;
fn clear_flag(rtc: &Rtc);
}
macro_rules! create_rtc_interrupt {
($mode:ident, $name:ident, $bit:ident) => {
#[doc = concat!("Type-level variant for the ", stringify!($name), " interrupt in ", stringify!($mode))]
pub enum $name {}
impl RtcInterrupt for $name {
#[inline]
fn enable(rtc: &Rtc) {
rtc.$mode().intenset().write(|w| w.$bit().set_bit());
}
#[inline]
fn disable(rtc: &Rtc) {
rtc.$mode().intenclr().write(|w| w.$bit().set_bit());
}
#[inline]
fn check_flag(rtc: &Rtc) -> bool {
rtc.$mode().intflag().read().$bit().bit_is_set()
}
#[inline]
fn clear_flag(rtc: &Rtc) {
rtc.$mode().intflag().write(|w| w.$bit().set_bit());
}
}
};
}
pub trait RtcMode {
type Count: Copy + PartialEq + Eq;
fn set_mode(rtc: &Rtc);
fn set_compare(rtc: &Rtc, number: usize, value: Self::Count);
#[cfg(feature = "rtic")]
fn get_compare(rtc: &Rtc, number: usize) -> Self::Count;
fn count(rtc: &Rtc) -> Self::Count;
fn set_count(rtc: &Rtc, count: Self::Count);
#[inline]
#[hal_macro_helper]
fn sync_busy(rtc: &Rtc) -> bool {
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
return rtc.mode0().status().read().syncbusy().bit_is_set();
#[hal_cfg("rtc-d5x")]
return rtc.mode0().syncbusy().read().bits() != 0;
}
#[inline]
#[hal_macro_helper]
fn reset(rtc: &Rtc) {
Self::sync(rtc);
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode0().ctrl().modify(|_, w| w.swrst().set_bit());
#[hal_cfg("rtc-d5x")]
rtc.mode0().ctrla().modify(|_, w| w.swrst().set_bit());
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
while rtc.mode0().ctrl().read().swrst().bit_is_set() {}
#[hal_cfg("rtc-d5x")]
while rtc.mode0().ctrla().read().swrst().bit_is_set() {}
}
#[inline]
#[hal_macro_helper]
fn set_prescaler(rtc: &Rtc, divider: Prescalerselect) {
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode0()
.ctrl()
.modify(|_, w| w.prescaler().variant(divider));
#[hal_cfg("rtc-d5x")]
rtc.mode0()
.ctrla()
.modify(|_, w| w.prescaler().variant(divider));
}
#[inline]
#[hal_macro_helper]
fn start_and_initialize(rtc: &Rtc) {
Self::enable(rtc);
#[hal_cfg("rtc-d5x")]
{
Self::sync(rtc);
rtc.mode0().ctrla().modify(|_, w| {
w.prescaler().div1();
w.countsync().set_bit();
w
});
Self::_wait_for_count_change(rtc);
}
}
#[inline]
fn enable_interrupt<I: RtcInterrupt>(rtc: &Rtc) {
I::enable(rtc);
}
#[inline]
fn disable_interrupt<I: RtcInterrupt>(rtc: &Rtc) {
I::disable(rtc);
}
#[inline]
fn check_interrupt_flag<I: RtcInterrupt>(rtc: &Rtc) -> bool {
I::check_flag(rtc)
}
#[inline]
fn clear_interrupt_flag<I: RtcInterrupt>(rtc: &Rtc) {
I::clear_flag(rtc);
}
#[inline]
fn sync(rtc: &Rtc) {
while Self::sync_busy(rtc) {}
}
#[inline]
#[hal_macro_helper]
fn disable(rtc: &Rtc) {
Self::sync(rtc);
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode0().ctrl().modify(|_, w| w.enable().clear_bit());
#[hal_cfg("rtc-d5x")]
rtc.mode0().ctrla().modify(|_, w| w.enable().clear_bit());
}
#[inline]
#[hal_macro_helper]
fn enable(rtc: &Rtc) {
Self::sync(rtc);
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode0().ctrl().modify(|_, w| w.enable().set_bit());
#[hal_cfg("rtc-d5x")]
rtc.mode0().ctrla().modify(|_, w| w.enable().set_bit());
}
#[inline]
fn _wait_for_count_change(rtc: &Rtc) -> Self::Count {
let mut last_count = Self::count(rtc);
loop {
let count = Self::count(rtc);
if count != last_count {
break count;
}
last_count = count;
}
}
}
pub mod mode0 {
use super::*;
create_rtc_interrupt!(mode0, Compare0, cmp0);
#[cfg(feature = "rtic")]
#[hal_cfg("rtc-d5x")]
create_rtc_interrupt!(mode0, Compare1, cmp1);
#[cfg(feature = "rtic")]
#[hal_cfg("rtc-d5x")]
create_rtc_interrupt!(mode0, Overflow, ovf);
pub struct RtcMode0;
impl RtcMode0 {
#[inline]
#[hal_macro_helper]
pub fn set_match_clear(rtc: &Rtc, enable: bool) {
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode0().ctrl().modify(|_, w| w.matchclr().bit(enable));
#[hal_cfg("rtc-d5x")]
rtc.mode0().ctrla().modify(|_, w| w.matchclr().bit(enable));
}
}
impl RtcMode for RtcMode0 {
type Count = u32;
#[inline]
#[hal_macro_helper]
fn set_mode(rtc: &Rtc) {
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode0().ctrl().modify(|_, w| w.mode().count32());
#[hal_cfg("rtc-d5x")]
rtc.mode0().ctrla().modify(|_, w| w.mode().count32());
}
#[inline]
fn set_compare(rtc: &Rtc, number: usize, value: Self::Count) {
Self::sync(rtc);
unsafe {
rtc.mode0().comp(number).write(|w| w.comp().bits(value));
}
}
#[inline]
#[cfg(feature = "rtic")]
fn get_compare(rtc: &Rtc, number: usize) -> Self::Count {
rtc.mode0().comp(number).read().bits()
}
#[inline]
#[hal_macro_helper]
fn count(rtc: &Rtc) -> Self::Count {
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
{
rtc.mode0().readreq().modify(|_, w| w.rreq().set_bit());
}
Self::sync(rtc);
rtc.mode0().count().read().bits()
}
#[inline]
fn set_count(rtc: &Rtc, count: Self::Count) {
Self::sync(rtc);
unsafe { rtc.mode0().count().write(|w| w.count().bits(count)) };
}
}
}
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
#[cfg(feature = "rtic")]
pub mod mode1 {
use super::*;
create_rtc_interrupt!(mode1, Compare0, cmp0);
#[cfg(feature = "rtic")]
create_rtc_interrupt!(mode1, Compare1, cmp1);
#[cfg(feature = "rtic")]
create_rtc_interrupt!(mode1, Overflow, ovf);
pub struct RtcMode1;
impl RtcMode for RtcMode1 {
type Count = u16;
#[inline]
#[hal_macro_helper]
fn set_mode(rtc: &Rtc) {
Self::sync(rtc);
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode0().ctrl().modify(|_, w| w.mode().count16());
#[hal_cfg("rtc-d5x")]
rtc.mode0().ctrla().modify(|_, w| w.mode().count16());
Self::sync(rtc);
unsafe { rtc.mode1().per().write(|w| w.bits(0xFFFF)) };
}
#[inline]
fn set_compare(rtc: &Rtc, number: usize, value: Self::Count) {
Self::sync(rtc);
unsafe { rtc.mode1().comp(number).write(|w| w.comp().bits(value)) };
}
#[inline]
#[cfg(feature = "rtic")]
fn get_compare(rtc: &Rtc, number: usize) -> Self::Count {
rtc.mode1().comp(number).read().bits()
}
#[inline]
#[hal_macro_helper]
fn count(rtc: &Rtc) -> Self::Count {
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
{
rtc.mode1().readreq().modify(|_, w| w.rreq().set_bit());
}
Self::sync(rtc);
rtc.mode1().count().read().bits()
}
#[inline]
fn set_count(rtc: &Rtc, count: Self::Count) {
Self::sync(rtc);
unsafe { rtc.mode1().count().write(|w| w.count().bits(count)) };
}
}
}
pub mod mode2 {
use super::*;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Datetime {
pub seconds: u8,
pub minutes: u8,
pub hours: u8,
pub day: u8,
pub month: u8,
pub year: u8,
}
macro_rules! from_reg_datetime {
($regr:ident) => {
impl From<pac::rtc::mode2::$regr::R> for Datetime {
fn from(clock: pac::rtc::mode2::$regr::R) -> Datetime {
Datetime {
seconds: clock.second().bits(),
minutes: clock.minute().bits(),
hours: clock.hour().bits(),
day: clock.day().bits(),
month: clock.month().bits(),
year: clock.year().bits(),
}
}
}
};
}
from_reg_datetime!(clock);
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
from_reg_datetime!(alarm);
#[hal_cfg("rtc-d5x")]
from_reg_datetime!(alarm0);
#[hal_cfg("rtc-d5x")]
from_reg_datetime!(alarm1);
macro_rules! write_datetime {
($regw:ident, $time:ident) => {
unsafe {
$regw
.second()
.bits($time.seconds)
.minute()
.bits($time.minutes)
.hour()
.bits($time.hours)
.day()
.bits($time.day)
.month()
.bits($time.month)
.year()
.bits($time.year)
}
};
}
pub struct RtcMode2;
impl RtcMode for RtcMode2 {
type Count = Datetime;
#[inline]
#[hal_macro_helper]
fn set_mode(rtc: &Rtc) {
Self::sync(rtc);
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode0().ctrl().modify(|_, w| w.mode().clock());
#[hal_cfg("rtc-d5x")]
rtc.mode0().ctrla().modify(|_, w| w.mode().clock());
}
#[inline]
#[hal_macro_helper]
fn set_compare(rtc: &Rtc, _number: usize, value: Self::Count) {
Self::sync(rtc);
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
rtc.mode2().alarm(0).write(|w| write_datetime!(w, value));
#[hal_cfg("rtc-d5x")]
if _number == 0 {
rtc.mode2().alarm0().write(|w| write_datetime!(w, value));
} else {
rtc.mode2().alarm1().write(|w| write_datetime!(w, value));
}
}
#[inline]
#[hal_macro_helper]
#[cfg(feature = "rtic")]
fn get_compare(rtc: &Rtc, _number: usize) -> Self::Count {
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
return rtc.mode2().alarm(0).read().into();
#[hal_cfg("rtc-d5x")]
if _number == 0 {
rtc.mode2().alarm0().read().into()
} else {
rtc.mode2().alarm1().read().into()
}
}
#[inline]
#[hal_macro_helper]
fn count(rtc: &Rtc) -> Self::Count {
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
{
rtc.mode2().readreq().modify(|_, w| w.rreq().set_bit());
}
Self::sync(rtc);
rtc.mode2().clock().read().into()
}
#[inline]
fn set_count(rtc: &Rtc, count: Self::Count) {
Self::sync(rtc);
rtc.mode2().clock().write(|w| write_datetime!(w, count));
}
}
}