use crate::pac::{PWR, RCC, RTC};
use crate::rcc::Enable;
use crate::rcc::Rcc;
use crate::time::{Hertz, Hz};
use core::convert::Infallible;
use core::marker::PhantomData;
#[cfg(feature = "py32f030")]
const LSE_HERTZ: Hertz = Hz(32_768);
const LSI_HERTZ: Hertz = Hz(32_768);
pub struct RtcClkHseDiv128;
#[cfg(feature = "py32f030")]
pub struct RtcClkLse;
pub struct RtcClkLsi;
pub enum RestoredOrNewRtc<CS> {
Restored(Rtc<CS>),
New(Rtc<CS>),
}
pub struct Rtc<CS = RtcClkLsi> {
regs: RTC,
_clock_source: PhantomData<CS>,
}
#[cfg(feature = "py32f030")]
impl Rtc<RtcClkLse> {
pub fn new(regs: RTC, rcc: &mut Rcc, pwr: &mut PWR) -> Self {
let mut result = Rtc {
regs,
_clock_source: PhantomData,
};
Self::enable_apb_and_dbp(&mut rcc.regs, pwr);
rcc.regs.bdcr.modify(|_, w| {
w.lseon().set_bit();
w.rtcen().set_bit();
w.rtcsel().lse()
});
let prl = LSE_HERTZ.raw() - 1;
result.set_prescaler(prl);
result
}
pub fn restore_or_new(regs: RTC, rcc: &mut Rcc, pwr: &mut PWR) -> RestoredOrNewRtc<RtcClkLse> {
if Self::is_enabled(&rcc.regs) {
Self::enable_apb_and_dbp(&mut rcc.regs, pwr);
RestoredOrNewRtc::Restored(Rtc {
regs,
_clock_source: PhantomData,
})
} else {
RestoredOrNewRtc::New(Rtc::new(regs, rcc, pwr))
}
}
fn is_enabled(rcc: &RCC) -> bool {
let bdcr = rcc.bdcr.read();
bdcr.rtcen().is_enabled() && bdcr.rtcsel().is_lse()
}
pub fn select_frequency(&mut self, frequency: Hertz) {
assert!(frequency <= LSE_HERTZ / 2);
let prescaler = LSE_HERTZ.raw() / frequency.raw() - 1;
self.set_prescaler(prescaler);
}
}
impl Rtc<RtcClkLsi> {
pub fn new_lsi(regs: RTC, rcc: &mut Rcc, pwr: &mut PWR) -> Self {
let mut result = Rtc {
regs,
_clock_source: PhantomData,
};
Self::enable_apb_and_dbp(&mut rcc.regs, pwr);
Self::enable_lsi(&mut rcc.regs);
rcc.regs.bdcr.modify(|_, w| {
w.rtcen().set_bit();
w.rtcsel().lsi()
});
let prl = LSI_HERTZ.raw() - 1;
result.set_prescaler(prl);
result
}
pub fn restore_or_new_lsi(
regs: RTC,
rcc: &mut Rcc,
pwr: &mut PWR,
) -> RestoredOrNewRtc<RtcClkLsi> {
if Self::is_enabled(&rcc.regs) {
Self::enable_apb_and_dbp(&mut rcc.regs, pwr);
Self::enable_lsi(&mut rcc.regs);
RestoredOrNewRtc::Restored(Rtc {
regs,
_clock_source: PhantomData,
})
} else {
RestoredOrNewRtc::New(Rtc::new_lsi(regs, rcc, pwr))
}
}
fn is_enabled(rcc: &RCC) -> bool {
rcc.bdcr.read().rtcen().bit() && rcc.bdcr.read().rtcsel().is_lsi()
}
fn enable_lsi(rcc: &mut RCC) {
rcc.csr.modify(|_, w| {
w.lsion().set_bit()
});
}
pub fn select_frequency(&mut self, frequency: Hertz) {
assert!(frequency <= LSI_HERTZ / 2);
let prescaler = LSI_HERTZ.raw() / frequency.raw() - 1;
self.set_prescaler(prescaler);
}
}
impl Rtc<RtcClkHseDiv128> {
pub fn new_hse(regs: RTC, hse: Hertz, rcc: &mut Rcc, pwr: &mut PWR) -> Self {
let mut result = Rtc {
regs,
_clock_source: PhantomData,
};
Self::enable_apb_and_dbp(&mut rcc.regs, pwr);
if rcc.regs.cr.read().hserdy().bit_is_clear() {
panic!("HSE oscillator not ready");
}
rcc.regs.bdcr.modify(|_, w| {
w.rtcen().set_bit();
w.rtcsel().hse()
});
let prl = hse.raw() / 128 - 1;
result.set_prescaler(prl);
result
}
pub fn restore_or_new_hse(
regs: RTC,
rcc: &mut Rcc,
pwr: &mut PWR,
hse: Hertz,
) -> RestoredOrNewRtc<RtcClkHseDiv128> {
if Self::is_enabled(&rcc.regs) {
Self::enable_apb_and_dbp(&mut rcc.regs, pwr);
RestoredOrNewRtc::Restored(Rtc {
regs,
_clock_source: PhantomData,
})
} else {
RestoredOrNewRtc::New(Rtc::new_hse(regs, hse, rcc, pwr))
}
}
fn is_enabled(rcc: &RCC) -> bool {
let bdcr = rcc.bdcr.read();
bdcr.rtcen().is_enabled() && bdcr.rtcsel().is_hse()
}
pub fn select_frequency(&mut self, frequency: Hertz, hse: Hertz) {
assert!(frequency.raw() <= hse.raw() / 128 / 2);
let prescaler = hse.raw() / 128 / frequency.raw() - 1;
self.set_prescaler(prescaler);
}
}
impl<CS> Rtc<CS> {
fn enable_apb_and_dbp(rcc: &mut RCC, pwr: &mut PWR) {
PWR::enable(rcc);
RTC::enable(rcc);
pwr.cr1.modify(|_, w| w.dbp().bit(true));
cortex_m::asm::delay(100);
}
pub fn set_time(&mut self, counter_value: u32) {
self.perform_write(|s| {
s.regs
.cnth
.write(|w| unsafe { w.bits(counter_value >> 16) });
s.regs
.cntl
.write(|w| unsafe { w.bits(counter_value as u16 as u32) });
});
}
pub fn set_alarm(&mut self, counter_value: u32) {
let alarm_value = counter_value - 1;
self.perform_write(|s| {
s.regs
.alrh
.write(|w| w.alrh().bits((alarm_value >> 16) as u16));
s.regs.alrl.write(|w| w.alrl().bits(alarm_value as u16));
});
self.clear_alarm_flag();
}
pub fn listen_alarm(&mut self) {
self.perform_write(|s| {
s.regs.crh.modify(|_, w| w.alrie().set_bit());
})
}
pub fn unlisten_alarm(&mut self) {
self.perform_write(|s| {
s.regs.crh.modify(|_, w| w.alrie().clear_bit());
})
}
pub fn current_time(&self) -> u32 {
while !self.regs.crl.read().rsf().bit() {}
self.regs.cnth.read().bits() << 16 | self.regs.cntl.read().bits()
}
pub fn listen_seconds(&mut self) {
self.perform_write(|s| s.regs.crh.modify(|_, w| w.secie().set_bit()))
}
pub fn unlisten_seconds(&mut self) {
self.perform_write(|s| s.regs.crh.modify(|_, w| w.secie().clear_bit()))
}
pub fn clear_second_flag(&mut self) {
self.perform_write(|s| s.regs.crl.modify(|_, w| w.secf().clear_bit()))
}
pub fn clear_alarm_flag(&mut self) {
self.perform_write(|s| s.regs.crl.modify(|_, w| w.alrf().clear_bit()))
}
pub fn wait_alarm(&mut self) -> nb::Result<(), Infallible> {
if self.regs.crl.read().alrf().bit() {
self.regs.crl.modify(|_, w| w.alrf().clear_bit());
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn perform_write(&mut self, func: impl Fn(&mut Self)) {
while !self.regs.crl.read().rtoff().bit() {}
self.regs.crl.modify(|_, w| w.cnf().set_bit());
func(self);
self.regs.crl.modify(|_, w| w.cnf().clear_bit());
while !self.regs.crl.read().rtoff().bit() {}
}
fn set_prescaler(&mut self, prescaler: u32) {
assert!(prescaler < 1 << 20);
self.perform_write(|s| {
s.regs.prlh.write(|w| unsafe { w.bits(prescaler >> 16) });
s.regs
.prll
.write(|w| unsafe { w.bits(prescaler as u16 as u32) });
});
}
}