#[cfg(any(feature = "rt"))]
#[cfg(any(feature = "stm32f302", feature = "stm32f303"))]
use crate::pac::{interrupt::RTC_WKUP, EXTI};
#[cfg(any(feature = "rt"))]
#[cfg(any(feature = "stm32f302", feature = "stm32f303"))]
use cortex_m::peripheral::NVIC;
use crate::pac::{PWR, RTC};
use crate::rcc::{APB1, BDCR};
use core::convert::TryInto;
use rtcc::{Datelike, Hours, NaiveDate, NaiveDateTime, NaiveTime, Rtcc, Timelike};
#[cfg(any(feature = "rt"))]
#[macro_export]
macro_rules! make_rtc_interrupt_handler {
($line:ident) => {
#[interrupt]
fn $line() {
free(|cs| {
unsafe { (*pac::EXTI::ptr()).pr1.modify(|_, w| w.pr20().bit(true)) };
unsafe { (*pac::RTC::ptr()).wpr.write(|w| w.bits(0xCA)) };
unsafe { (*pac::RTC::ptr()).wpr.write(|w| w.bits(0x53)) };
unsafe { (*pac::RTC::ptr()).cr.modify(|_, w| w.wute().clear_bit()) };
unsafe { (*pac::RTC::ptr()).isr.modify(|_, w| w.init().set_bit()) };
while unsafe { (*pac::RTC::ptr()).isr.read().initf().bit_is_clear() } {}
unsafe { (*pac::RTC::ptr()).isr.modify(|_, w| w.wutf().clear_bit()) };
unsafe { (*pac::RTC::ptr()).isr.modify(|_, w| w.init().clear_bit()) };
while !unsafe { (*pac::RTC::ptr()).isr.read().initf().bit_is_clear() } {}
unsafe { (*pac::RTC::ptr()).cr.modify(|_, w| w.wute().set_bit()) };
unsafe { (*pac::RTC::ptr()).wpr.write(|w| w.bits(0xFF)) };
});
}
};
}
#[derive(Debug)]
pub enum Error {
InvalidInputData,
}
pub const LSE_BITS: u8 = 0b01;
#[derive(Clone, Copy, Debug)]
pub enum WakeupDivision {
Sixteen,
Eight,
Four,
Two,
}
#[derive(Clone, Copy, Debug)]
pub enum ClockConfig {
One(WakeupDivision),
Two,
Three,
}
pub struct Rtc {
pub regs: RTC,
}
impl Rtc {
pub fn new(
regs: RTC,
prediv_s: u16,
prediv_a: u8,
bypass: bool,
apb1: &mut APB1,
bdcr: &mut BDCR,
pwr: &mut PWR,
) -> Self {
let mut result = Self { regs };
reset(bdcr);
unlock(apb1, pwr);
enable_lse(bdcr, bypass);
enable(bdcr);
result.set_24h_fmt();
result.regs.prer.modify(|_, w| {
w.prediv_s().bits(prediv_s);
w.prediv_a().bits(prediv_a)
});
result
}
pub fn set_24h_fmt(&mut self) {
self.regs.cr.modify(|_, w| w.fmt().set_bit());
}
pub fn set_12h_fmt(&mut self) {
self.regs.cr.modify(|_, w| w.fmt().clear_bit());
}
pub fn is_24h_fmt(&self) -> bool {
self.regs.cr.read().fmt().bit()
}
#[cfg(any(feature = "rt"))]
#[cfg(any(feature = "stm32f302", feature = "stm32f303"))]
pub fn set_auto_wakeup(&mut self, exti: &mut EXTI, clock_cfg: ClockConfig, sleep_time: u32) {
exti.imr1.modify(|_, w| w.mr20().unmasked());
exti.rtsr1.modify(|_, w| w.tr20().bit(true));
exti.ftsr1.modify(|_, w| w.tr20().bit(false));
unsafe { NVIC::unmask(RTC_WKUP) };
self.regs.wpr.write(|w| unsafe { w.bits(0xCA) });
self.regs.wpr.write(|w| unsafe { w.bits(0x53) });
self.regs.cr.modify(|_, w| w.wute().clear_bit());
while !self.regs.isr.read().wutwf().bit_is_set() {}
let lfe_freq = 32_768;
let sleep_for_cycles = lfe_freq * sleep_time / 1_000;
self.regs
.wutr
.modify(|_, w| w.wut().bits(sleep_for_cycles as u16));
let word = match clock_cfg {
ClockConfig::One(division) => match division {
WakeupDivision::Sixteen => 0b000,
WakeupDivision::Eight => 0b001,
WakeupDivision::Four => 0b010,
WakeupDivision::Two => 0b011,
},
ClockConfig::Two => 0b100,
ClockConfig::Three => 0b110,
};
self.regs
.cr
.modify(|_, w| unsafe { w.wucksel().bits(word) });
self.regs.cr.modify(|_, w| w.wute().set_bit());
self.regs.cr.modify(|_, w| w.wutie().set_bit());
self.regs.isr.modify(|_, w| w.wutf().clear_bit());
self.regs.wpr.write(|w| unsafe { w.bits(0xFF) });
}
#[cfg(any(feature = "rt"))]
#[cfg(any(feature = "stm32f302", feature = "stm32f303"))]
pub fn set_wakeup_interval(&mut self, sleep_time: u32) {
self.regs.wpr.write(|w| unsafe { w.bits(0xCA) });
self.regs.wpr.write(|w| unsafe { w.bits(0x53) });
self.regs.cr.modify(|_, w| w.wute().clear_bit());
while !self.regs.isr.read().wutwf().bit_is_set() {}
let lfe_freq = 32_768;
let sleep_for_cycles = lfe_freq * sleep_time / 1_000;
self.regs
.wutr
.modify(|_, w| w.wut().bits(sleep_for_cycles as u16));
self.regs.cr.modify(|_, w| w.wute().set_bit());
self.regs.wpr.write(|w| unsafe { w.bits(0xFF) });
}
#[cfg(any(feature = "rt"))]
pub fn clear_wakeup_flag(&mut self) {
self.modify(|regs| {
regs.cr.modify(|_, w| w.wute().clear_bit());
regs.isr.modify(|_, w| w.wutf().clear_bit());
regs.cr.modify(|_, w| w.wute().set_bit());
});
}
fn modify<F>(&mut self, mut closure: F)
where
F: FnMut(&mut RTC),
{
self.regs.wpr.write(|w| unsafe { w.bits(0xCA) });
self.regs.wpr.write(|w| unsafe { w.bits(0x53) });
let isr = self.regs.isr.read();
if isr.initf().bit_is_clear() {
self.regs.isr.modify(|_, w| w.init().set_bit());
while self.regs.isr.read().initf().bit_is_clear() {}
}
closure(&mut self.regs);
self.regs.isr.modify(|_, w| w.init().clear_bit());
while !self.regs.isr.read().initf().bit_is_clear() {}
self.regs.wpr.write(|w| unsafe { w.bits(0xFF) });
}
}
impl Rtcc for Rtc {
type Error = Error;
fn set_time(&mut self, time: &NaiveTime) -> Result<(), Self::Error> {
self.set_24h_fmt();
let (ht, hu) = bcd2_encode(time.hour())?;
let (mnt, mnu) = bcd2_encode(time.minute())?;
let (st, su) = bcd2_encode(time.second())?;
self.modify(|regs| {
regs.tr.write(|w| {
w.ht().bits(ht);
w.hu().bits(hu);
w.mnt().bits(mnt);
w.mnu().bits(mnu);
w.st().bits(st);
w.su().bits(su);
w.pm().clear_bit()
})
});
Ok(())
}
fn set_seconds(&mut self, seconds: u8) -> Result<(), Self::Error> {
if seconds > 59 {
return Err(Error::InvalidInputData);
}
let (st, su) = bcd2_encode(seconds as u32)?;
self.modify(|regs| regs.tr.modify(|_, w| w.st().bits(st).su().bits(su)));
Ok(())
}
fn set_minutes(&mut self, minutes: u8) -> Result<(), Self::Error> {
if minutes > 59 {
return Err(Error::InvalidInputData);
}
let (mnt, mnu) = bcd2_encode(minutes as u32)?;
self.modify(|regs| regs.tr.modify(|_, w| w.mnt().bits(mnt).mnu().bits(mnu)));
Ok(())
}
fn set_hours(&mut self, hours: Hours) -> Result<(), Self::Error> {
let (ht, hu) = hours_to_register(hours)?;
match hours {
Hours::H24(_h) => self.set_24h_fmt(),
Hours::AM(_h) | Hours::PM(_h) => self.set_12h_fmt(),
}
self.regs.tr.modify(|_, w| w.ht().bits(ht).hu().bits(hu));
Ok(())
}
fn set_weekday(&mut self, weekday: u8) -> Result<(), Self::Error> {
if (weekday < 1) || (weekday > 7) {
return Err(Error::InvalidInputData);
}
self.modify(|regs| regs.dr.modify(|_, w| unsafe { w.wdu().bits(weekday) }));
Ok(())
}
fn set_day(&mut self, day: u8) -> Result<(), Self::Error> {
if (day < 1) || (day > 31) {
return Err(Error::InvalidInputData);
}
let (dt, du) = bcd2_encode(day as u32)?;
self.modify(|regs| regs.dr.modify(|_, w| w.dt().bits(dt).du().bits(du)));
Ok(())
}
fn set_month(&mut self, month: u8) -> Result<(), Self::Error> {
if (month < 1) || (month > 12) {
return Err(Error::InvalidInputData);
}
let (mt, mu) = bcd2_encode(month as u32)?;
self.modify(|regs| regs.dr.modify(|_, w| w.mt().bit(mt > 0).mu().bits(mu)));
Ok(())
}
fn set_year(&mut self, year: u16) -> Result<(), Self::Error> {
if (year < 1970) || (year > 2038) {
return Err(Error::InvalidInputData);
}
let (yt, yu) = bcd2_encode(year as u32)?;
self.modify(|regs| regs.dr.modify(|_, w| w.yt().bits(yt).yu().bits(yu)));
Ok(())
}
fn set_date(&mut self, date: &NaiveDate) -> Result<(), Self::Error> {
if date.year() < 1970 {
return Err(Error::InvalidInputData);
}
let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
let (mt, mu) = bcd2_encode(date.month())?;
let (dt, du) = bcd2_encode(date.day())?;
self.modify(|regs| {
regs.dr.write(|w| {
w.dt().bits(dt);
w.du().bits(du);
w.mt().bit(mt > 0);
w.mu().bits(mu);
w.yt().bits(yt);
w.yu().bits(yu)
})
});
Ok(())
}
fn set_datetime(&mut self, date: &NaiveDateTime) -> Result<(), Self::Error> {
if date.year() < 1970 {
return Err(Error::InvalidInputData);
}
self.set_24h_fmt();
let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
let (mt, mu) = bcd2_encode(date.month())?;
let (dt, du) = bcd2_encode(date.day())?;
let (ht, hu) = bcd2_encode(date.hour())?;
let (mnt, mnu) = bcd2_encode(date.minute())?;
let (st, su) = bcd2_encode(date.second())?;
self.modify(|regs| {
regs.dr.write(|w| {
w.dt().bits(dt);
w.du().bits(du);
w.mt().bit(mt > 0);
w.mu().bits(mu);
w.yt().bits(yt);
w.yu().bits(yu)
})
});
self.modify(|regs| {
regs.tr.write(|w| {
w.ht().bits(ht);
w.hu().bits(hu);
w.mnt().bits(mnt);
w.mnu().bits(mnu);
w.st().bits(st);
w.su().bits(su);
w.pm().clear_bit()
})
});
Ok(())
}
fn get_seconds(&mut self) -> Result<u8, Self::Error> {
let tr = self.regs.tr.read();
let seconds = bcd2_decode(tr.st().bits(), tr.su().bits());
Ok(seconds as u8)
}
fn get_minutes(&mut self) -> Result<u8, Self::Error> {
let tr = self.regs.tr.read();
let minutes = bcd2_decode(tr.mnt().bits(), tr.mnu().bits());
Ok(minutes as u8)
}
fn get_hours(&mut self) -> Result<Hours, Self::Error> {
let tr = self.regs.tr.read();
let hours = bcd2_decode(tr.ht().bits(), tr.hu().bits());
if self.is_24h_fmt() {
return Ok(Hours::H24(hours as u8));
}
if !tr.pm().bit() {
return Ok(Hours::AM(hours as u8));
}
Ok(Hours::PM(hours as u8))
}
fn get_time(&mut self) -> Result<NaiveTime, Self::Error> {
self.set_24h_fmt();
let seconds = self.get_seconds().unwrap();
let minutes = self.get_minutes().unwrap();
let hours = hours_to_u8(self.get_hours()?)?;
Ok(NaiveTime::from_hms(
hours.into(),
minutes.into(),
seconds.into(),
))
}
fn get_weekday(&mut self) -> Result<u8, Self::Error> {
let dr = self.regs.dr.read();
let weekday = bcd2_decode(dr.wdu().bits(), 0x00);
Ok(weekday as u8)
}
fn get_day(&mut self) -> Result<u8, Self::Error> {
let dr = self.regs.dr.read();
let day = bcd2_decode(dr.dt().bits(), dr.du().bits());
Ok(day as u8)
}
fn get_month(&mut self) -> Result<u8, Self::Error> {
let dr = self.regs.dr.read();
let mt: u8 = if dr.mt().bit() { 1 } else { 0 };
let month = bcd2_decode(mt, dr.mu().bits());
Ok(month as u8)
}
fn get_year(&mut self) -> Result<u16, Self::Error> {
let dr = self.regs.dr.read();
let year = bcd2_decode(dr.yt().bits(), dr.yu().bits());
Ok(year as u16)
}
fn get_date(&mut self) -> Result<NaiveDate, Self::Error> {
let day = self.get_day().unwrap();
let month = self.get_month().unwrap();
let year = self.get_year().unwrap();
Ok(NaiveDate::from_ymd(year.into(), month.into(), day.into()))
}
fn get_datetime(&mut self) -> Result<NaiveDateTime, Self::Error> {
self.set_24h_fmt();
let day = self.get_day().unwrap();
let month = self.get_month().unwrap();
let year = self.get_year().unwrap();
let seconds = self.get_seconds().unwrap();
let minutes = self.get_minutes().unwrap();
let hours = hours_to_u8(self.get_hours()?)?;
Ok(
NaiveDate::from_ymd(year.into(), month.into(), day.into()).and_hms(
hours.into(),
minutes.into(),
seconds.into(),
),
)
}
}
fn bcd2_encode(word: u32) -> Result<(u8, u8), Error> {
let l = match (word / 10).try_into() {
Ok(v) => v,
Err(_) => {
return Err(Error::InvalidInputData);
}
};
let r = match (word % 10).try_into() {
Ok(v) => v,
Err(_) => {
return Err(Error::InvalidInputData);
}
};
Ok((l, r))
}
fn bcd2_decode(fst: u8, snd: u8) -> u32 {
(fst * 10 + snd).into()
}
fn hours_to_register(hours: Hours) -> Result<(u8, u8), Error> {
match hours {
Hours::H24(h) => Ok(bcd2_encode(h as u32))?,
Hours::AM(h) => Ok(bcd2_encode((h - 1) as u32))?,
Hours::PM(h) => Ok(bcd2_encode((h + 11) as u32))?,
}
}
fn hours_to_u8(hours: Hours) -> Result<u8, Error> {
if let Hours::H24(h) = hours {
Ok(h)
} else {
Err(Error::InvalidInputData)
}
}
fn enable_lse(bdcr: &mut BDCR, bypass: bool) {
bdcr.bdcr().modify(|_, w| w.lseon().set_bit());
bdcr.bdcr().modify(|_, w| w.lsebyp().bit(bypass));
while bdcr.bdcr().read().lserdy().bit_is_clear() {}
}
fn unlock(apb1: &mut APB1, pwr: &mut PWR) {
apb1.enr().modify(|_, w| {
w
.pwren()
.set_bit()
});
pwr.cr.modify(|_, w| {
w
.dbp()
.set_bit()
});
while pwr.cr.read().dbp().bit_is_clear() {}
}
pub fn enable(bdcr: &mut BDCR) {
bdcr.bdcr().modify(|_, w| w.rtcsel().lse());
bdcr.bdcr().modify(|_, w| w.rtcen().enabled());
}
pub fn disable(bdcr: &mut BDCR) {
bdcr.bdcr().modify(|_, w| w.rtcen().disabled());
}
fn reset(bdcr: &mut BDCR) {
bdcr.bdcr().modify(|_, w| w.bdrst().enabled());
bdcr.bdcr().modify(|_, w| w.bdrst().disabled());
}