diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 59904130..11820b7a 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -51,7 +51,7 @@ pub mod pwm; pub mod qspi; #[cfg(rng)] pub mod rng; -#[cfg(all(rtc, not(any(rtc_v1, rtc_v2f0, rtc_v2f7, rtc_v3, rtc_v3u5))))] +#[cfg(all(rtc, not(rtc_v1)))] pub mod rtc; #[cfg(sdmmc)] pub mod sdmmc; diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index 6274c1e0..0a590c1b 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -51,7 +51,7 @@ pub struct DateTime { impl From for DateTime { fn from(date_time: chrono::NaiveDateTime) -> Self { Self { - year: (date_time.year() - 1970) as u16, + year: date_time.year() as u16, month: date_time.month() as u8, day: date_time.day() as u8, day_of_week: date_time.weekday().into(), @@ -65,14 +65,10 @@ impl From for DateTime { #[cfg(feature = "chrono")] impl From for chrono::NaiveDateTime { fn from(date_time: DateTime) -> Self { - NaiveDate::from_ymd_opt( - (date_time.year + 1970) as i32, - date_time.month as u32, - date_time.day as u32, - ) - .unwrap() - .and_hms_opt(date_time.hour as u32, date_time.minute as u32, date_time.second as u32) - .unwrap() + NaiveDate::from_ymd_opt(date_time.year as i32, date_time.month as u32, date_time.day as u32) + .unwrap() + .and_hms_opt(date_time.hour as u32, date_time.minute as u32, date_time.second as u32) + .unwrap() } } @@ -159,6 +155,8 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) { let (yt, yu) = byte_to_bcd2(yr_offset); unsafe { + use crate::pac::rtc::vals::Ampm; + rtc.tr().write(|w| { w.set_ht(ht); w.set_hu(hu); @@ -166,7 +164,7 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) { w.set_mnu(mnu); w.set_st(st); w.set_su(su); - w.set_pm(stm32_metapac::rtc::vals::Ampm::AM); + w.set_pm(Ampm::AM); }); rtc.dr().write(|w| { diff --git a/embassy-stm32/src/rtc/datetime_chrono.rs b/embassy-stm32/src/rtc/datetime_chrono.rs deleted file mode 100644 index b46316cc..00000000 --- a/embassy-stm32/src/rtc/datetime_chrono.rs +++ /dev/null @@ -1,85 +0,0 @@ -use chrono::{Datelike, Timelike}; - -use super::byte_to_bcd2; -use crate::pac::rtc::Rtc; - -/// Alias for [`chrono::NaiveDateTime`] -pub type DateTime = chrono::NaiveDateTime; -/// Alias for [`chrono::Weekday`] -pub type DayOfWeek = chrono::Weekday; - -/// Errors regarding the [`DateTime`] and [`DateTimeFilter`] structs. -/// -/// [`DateTimeFilter`]: struct.DateTimeFilter.html -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Error { - /// The [DateTime] has an invalid year. The year must be between 0 and 4095. - InvalidYear, - /// The [DateTime] contains an invalid date. - InvalidDate, - /// The [DateTime] contains an invalid time. - InvalidTime, -} - -pub(super) fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 { - dotw.num_days_from_monday() as u8 -} - -pub(crate) fn validate_datetime(dt: &DateTime) -> Result<(), Error> { - if dt.year() < 0 || dt.year() > 4095 { - // rp2040 can't hold these years - Err(Error::InvalidYear) - } else { - // The rest of the chrono date is assumed to be valid - Ok(()) - } -} - -pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) { - let (ht, hu) = byte_to_bcd2(t.hour() as u8); - let (mnt, mnu) = byte_to_bcd2(t.minute() as u8); - let (st, su) = byte_to_bcd2(t.second() as u8); - - let (dt, du) = byte_to_bcd2(t.day() as u8); - let (mt, mu) = byte_to_bcd2(t.month() as u8); - let yr = t.year() as u16; - let yr_offset = (yr - 1970_u16) as u8; - let (yt, yu) = byte_to_bcd2(yr_offset); - - unsafe { - rtc.tr().write(|w| { - w.set_ht(ht); - w.set_hu(hu); - w.set_mnt(mnt); - w.set_mnu(mnu); - w.set_st(st); - w.set_su(su); - w.set_pm(stm32_metapac::rtc::vals::Ampm::AM); - }); - - rtc.dr().write(|w| { - w.set_dt(dt); - w.set_du(du); - w.set_mt(mt > 0); - w.set_mu(mu); - w.set_yt(yt); - w.set_yu(yu); - w.set_wdu(day_of_week_to_u8(t.weekday())); - }); - } -} - -pub(super) fn datetime( - year: u16, - month: u8, - day: u8, - _day_of_week: u8, - hour: u8, - minute: u8, - second: u8, -) -> Result { - let date = chrono::NaiveDate::from_ymd_opt(year.into(), month.try_into().unwrap(), day.into()) - .ok_or(Error::InvalidDate)?; - let time = chrono::NaiveTime::from_hms_opt(hour.into(), minute.into(), second.into()).ok_or(Error::InvalidTime)?; - Ok(DateTime::new(date, time)) -} diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 170783b2..962927fb 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,12 +10,12 @@ pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb ), - path = "v2/mod.rs" + path = "v2.rs" )] #[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")] -mod versions; +mod _version; +pub use _version::*; use embassy_hal_common::Peripheral; -pub use versions::*; /// Errors that can occur on methods on [RtcClock] #[derive(Clone, Debug, PartialEq, Eq)] @@ -113,7 +113,7 @@ impl Default for RtcCalibrationCyclePeriod { impl<'d, T: Instance> Rtc<'d, T> { pub fn new(_rtc: impl Peripheral

+ 'd, rtc_config: RtcConfig) -> Self { - unsafe { enable_peripheral_clk() }; + unsafe { T::enable_peripheral_clk() }; let mut rtc_struct = Self { phantom: PhantomData, @@ -179,14 +179,14 @@ impl<'d, T: Instance> Rtc<'d, T> { self.rtc_config } - pub const BACKUP_REGISTER_COUNT: usize = BACKUP_REGISTER_COUNT; + pub const BACKUP_REGISTER_COUNT: usize = T::BACKUP_REGISTER_COUNT; /// Read content of the backup register. /// /// The registers retain their values during wakes from standby mode or system resets. They also /// retain their value when Vdd is switched off as long as V_BAT is powered. pub fn read_backup_register(&self, register: usize) -> Option { - read_backup_register(&T::regs(), register) + T::read_backup_register(&T::regs(), register) } /// Set content of the backup register. @@ -194,7 +194,7 @@ impl<'d, T: Instance> Rtc<'d, T> { /// The registers retain their values during wakes from standby mode or system resets. They also /// retain their value when Vdd is switched off as long as V_BAT is powered. pub fn write_backup_register(&self, register: usize, value: u32) { - write_backup_register(&T::regs(), register, value) + T::write_backup_register(&T::regs(), register, value) } } @@ -219,17 +219,31 @@ pub(crate) fn bcd2_to_byte(bcd: (u8, u8)) -> u8 { } pub(crate) mod sealed { + use crate::pac::rtc::Rtc; + pub trait Instance { - fn regs() -> crate::pac::rtc::Rtc; + const BACKUP_REGISTER_COUNT: usize; + + fn regs() -> Rtc { + crate::pac::RTC + } + + unsafe fn enable_peripheral_clk() {} + + /// Read content of the backup register. + /// + /// The registers retain their values during wakes from standby mode or system resets. They also + /// retain their value when Vdd is switched off as long as V_BAT is powered. + fn read_backup_register(rtc: &Rtc, register: usize) -> Option; + + /// Set content of the backup register. + /// + /// The registers retain their values during wakes from standby mode or system resets. They also + /// retain their value when Vdd is switched off as long as V_BAT is powered. + fn write_backup_register(rtc: &Rtc, register: usize, value: u32); + + // fn apply_config(&mut self, rtc_config: RtcConfig); } } pub trait Instance: sealed::Instance + 'static {} - -impl sealed::Instance for crate::peripherals::RTC { - fn regs() -> crate::pac::rtc::Rtc { - crate::pac::RTC - } -} - -impl Instance for crate::peripherals::RTC {} diff --git a/embassy-stm32/src/rtc/v2/mod.rs b/embassy-stm32/src/rtc/v2.rs similarity index 61% rename from embassy-stm32/src/rtc/v2/mod.rs rename to embassy-stm32/src/rtc/v2.rs index 296adae8..adaafe67 100644 --- a/embassy-stm32/src/rtc/v2/mod.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,29 +1,78 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; -use super::{Instance, RtcConfig}; +use super::{sealed, Instance, RtcConfig}; use crate::pac::rtc::Rtc; -#[cfg_attr(rtc_v2f0, path = "v2f0.rs")] -#[cfg_attr(rtc_v2f2, path = "v2f2.rs")] -#[cfg_attr(rtc_v2f3, path = "v2f3.rs")] -#[cfg_attr(rtc_v2f4, path = "v2f4.rs")] -#[cfg_attr(rtc_v2f7, path = "v2f7.rs")] -#[cfg_attr(rtc_v2h7, path = "v2h7.rs")] -#[cfg_attr(rtc_v2l0, path = "v2l0.rs")] -#[cfg_attr(rtc_v2l1, path = "v2l1.rs")] -#[cfg_attr(rtc_v2l4, path = "v2l4.rs")] -#[cfg_attr(rtc_v2wb, path = "v2wb.rs")] -mod family; - -pub use family::*; - impl<'d, T: Instance> super::Rtc<'d, T> { /// Applies the RTC config /// It this changes the RTC clock source the time will be reset pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { // Unlock the backup domain unsafe { - unlock_backup_domain(rtc_config.clock_config as u8); + let clock_config = rtc_config.clock_config as u8; + + #[cfg(not(rtc_v2wb))] + use stm32_metapac::rcc::vals::Rtcsel; + + #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] + let cr = crate::pac::PWR.cr(); + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] + let cr = crate::pac::PWR.cr1(); + + // TODO: Missing from PAC for l0 and f0? + #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] + { + cr.modify(|w| w.set_dbp(true)); + while !cr.read().dbp() {} + } + + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let reg = crate::pac::RCC.bdcr().read(); + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let reg = crate::pac::RCC.csr().read(); + + #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] + assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + + #[cfg(rtc_v2wb)] + let rtcsel = reg.rtcsel(); + #[cfg(not(rtc_v2wb))] + let rtcsel = reg.rtcsel().0; + + if !reg.rtcen() || rtcsel != clock_config { + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); + + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let cr = crate::pac::RCC.bdcr(); + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let cr = crate::pac::RCC.csr(); + + cr.modify(|w| { + // Reset + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + w.set_bdrst(false); + + // Select RTC source + #[cfg(not(rtc_v2wb))] + w.set_rtcsel(Rtcsel(clock_config)); + #[cfg(rtc_v2wb)] + w.set_rtcsel(clock_config); + w.set_rtcen(true); + + // Restore bcdr + #[cfg(any(rtc_v2l4, rtc_v2wb))] + w.set_lscosel(reg.lscosel()); + #[cfg(any(rtc_v2l4, rtc_v2wb))] + w.set_lscoen(reg.lscoen()); + + w.set_lseon(reg.lseon()); + + #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] + w.set_lsedrv(reg.lsedrv()); + w.set_lsebyp(reg.lsebyp()); + }); + } } self.write(true, |rtc| unsafe { @@ -148,24 +197,33 @@ impl<'d, T: Instance> super::Rtc<'d, T> { } } -/// Read content of the backup register. -/// -/// The registers retain their values during wakes from standby mode or system resets. They also -/// retain their value when Vdd is switched off as long as V_BAT is powered. -pub fn read_backup_register(rtc: &Rtc, register: usize) -> Option { - if register < BACKUP_REGISTER_COUNT { - Some(unsafe { rtc.bkpr(register).read().bkp() }) - } else { - None +impl sealed::Instance for crate::peripherals::RTC { + const BACKUP_REGISTER_COUNT: usize = 20; + + unsafe fn enable_peripheral_clk() { + #[cfg(any(rtc_v2l4, rtc_v2wb))] + { + // enable peripheral clock for communication + crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); + + // read to allow the pwr clock to enable + crate::pac::PWR.cr1().read(); + } + } + + fn read_backup_register(rtc: &Rtc, register: usize) -> Option { + if register < Self::BACKUP_REGISTER_COUNT { + Some(unsafe { rtc.bkpr(register).read().bkp() }) + } else { + None + } + } + + fn write_backup_register(rtc: &Rtc, register: usize, value: u32) { + if register < Self::BACKUP_REGISTER_COUNT { + unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) } + } } } -/// Set content of the backup register. -/// -/// The registers retain their values during wakes from standby mode or system resets. They also -/// retain their value when Vdd is switched off as long as V_BAT is powered. -pub fn write_backup_register(rtc: &Rtc, register: usize, value: u32) { - if register < BACKUP_REGISTER_COUNT { - unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) } - } -} +impl Instance for crate::peripherals::RTC {} diff --git a/embassy-stm32/src/rtc/v2/v2f0.rs b/embassy-stm32/src/rtc/v2/v2f0.rs deleted file mode 100644 index d6871d91..00000000 --- a/embassy-stm32/src/rtc/v2/v2f0.rs +++ /dev/null @@ -1,41 +0,0 @@ -use stm32_metapac::rcc::vals::Rtcsel; - -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - - let reg = crate::pac::RCC.bdcr().read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - - crate::pac::RCC.bdcr().modify(|w| { - // Reset - w.set_bdrst(false); - - // Select RTC source - w.set_rtcsel(Rtcsel(clock_config)); - w.set_rtcen(true); - - // Restore bcdr - w.set_lscosel(reg.lscosel()); - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); -} diff --git a/embassy-stm32/src/rtc/v2/v2f2.rs b/embassy-stm32/src/rtc/v2/v2f2.rs deleted file mode 100644 index e041f3f4..00000000 --- a/embassy-stm32/src/rtc/v2/v2f2.rs +++ /dev/null @@ -1,31 +0,0 @@ -use stm32_metapac::rcc::vals::Rtcsel; - -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr().read().dbp() {} - - let reg = crate::pac::RCC.bdcr().read(); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - - crate::pac::RCC.bdcr().modify(|w| { - // Reset - w.set_bdrst(false); - - // Select RTC source - w.set_rtcsel(Rtcsel(clock_config)); - w.set_rtcen(true); - - w.set_lseon(reg.lseon()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // Nothing to do -} diff --git a/embassy-stm32/src/rtc/v2/v2f3.rs b/embassy-stm32/src/rtc/v2/v2f3.rs deleted file mode 100644 index e041f3f4..00000000 --- a/embassy-stm32/src/rtc/v2/v2f3.rs +++ /dev/null @@ -1,31 +0,0 @@ -use stm32_metapac::rcc::vals::Rtcsel; - -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr().read().dbp() {} - - let reg = crate::pac::RCC.bdcr().read(); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - - crate::pac::RCC.bdcr().modify(|w| { - // Reset - w.set_bdrst(false); - - // Select RTC source - w.set_rtcsel(Rtcsel(clock_config)); - w.set_rtcen(true); - - w.set_lseon(reg.lseon()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // Nothing to do -} diff --git a/embassy-stm32/src/rtc/v2/v2f4.rs b/embassy-stm32/src/rtc/v2/v2f4.rs deleted file mode 100644 index 4dd21cae..00000000 --- a/embassy-stm32/src/rtc/v2/v2f4.rs +++ /dev/null @@ -1,31 +0,0 @@ -use stm32_metapac::rcc::vals::Rtcsel; - -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - - let reg = crate::pac::RCC.bdcr().read(); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - - crate::pac::RCC.bdcr().modify(|w| { - // Reset - w.set_bdrst(false); - - // Select RTC source - w.set_rtcsel(Rtcsel(clock_config)); - w.set_rtcen(true); - - w.set_lseon(reg.lseon()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // Nothing to do -} diff --git a/embassy-stm32/src/rtc/v2/v2f7.rs b/embassy-stm32/src/rtc/v2/v2f7.rs deleted file mode 100644 index d6871d91..00000000 --- a/embassy-stm32/src/rtc/v2/v2f7.rs +++ /dev/null @@ -1,41 +0,0 @@ -use stm32_metapac::rcc::vals::Rtcsel; - -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - - let reg = crate::pac::RCC.bdcr().read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - - crate::pac::RCC.bdcr().modify(|w| { - // Reset - w.set_bdrst(false); - - // Select RTC source - w.set_rtcsel(Rtcsel(clock_config)); - w.set_rtcen(true); - - // Restore bcdr - w.set_lscosel(reg.lscosel()); - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); -} diff --git a/embassy-stm32/src/rtc/v2/v2h7.rs b/embassy-stm32/src/rtc/v2/v2h7.rs deleted file mode 100644 index f3b18068..00000000 --- a/embassy-stm32/src/rtc/v2/v2h7.rs +++ /dev/null @@ -1,33 +0,0 @@ -use stm32_metapac::rcc::vals::Rtcsel; - -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - - let reg = crate::pac::RCC.bdcr().read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - - crate::pac::RCC.bdcr().modify(|w| { - // Reset - w.set_bdrst(false); - - // Select RTC source - w.set_rtcsel(Rtcsel(clock_config)); - w.set_rtcen(true); - - w.set_lseon(reg.lseon()); - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // Nothing to do -} diff --git a/embassy-stm32/src/rtc/v2/v2l0.rs b/embassy-stm32/src/rtc/v2/v2l0.rs deleted file mode 100644 index dbd3b088..00000000 --- a/embassy-stm32/src/rtc/v2/v2l0.rs +++ /dev/null @@ -1,26 +0,0 @@ -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - // TODO: Missing from PAC? - // crate::pac::PWR.cr().modify(|w| w.set_dbp(true)); - // while !crate::pac::PWR.cr().read().dbp() {} - - let reg = crate::pac::RCC.csr().read(); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.csr().modify(|w| { - // Select RTC source - w.set_rtcsel(crate::pac::rcc::vals::Rtcsel(clock_config)); - w.set_rtcen(true); - - w.set_lseon(reg.lseon()); - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // Nothing to do -} diff --git a/embassy-stm32/src/rtc/v2/v2l1.rs b/embassy-stm32/src/rtc/v2/v2l1.rs deleted file mode 100644 index 1ac78b31..00000000 --- a/embassy-stm32/src/rtc/v2/v2l1.rs +++ /dev/null @@ -1,24 +0,0 @@ -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr().read().dbp() {} - - let reg = crate::pac::RCC.csr().read(); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.csr().modify(|w| { - // Select RTC source - w.set_rtcsel(crate::pac::rcc::vals::Rtcsel(clock_config)); - w.set_rtcen(true); - - w.set_lseon(reg.lseon()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // Nothing to do -} diff --git a/embassy-stm32/src/rtc/v2/v2l4.rs b/embassy-stm32/src/rtc/v2/v2l4.rs deleted file mode 100644 index d6871d91..00000000 --- a/embassy-stm32/src/rtc/v2/v2l4.rs +++ /dev/null @@ -1,41 +0,0 @@ -use stm32_metapac::rcc::vals::Rtcsel; - -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - - let reg = crate::pac::RCC.bdcr().read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() || reg.rtcsel().0 != clock_config { - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - - crate::pac::RCC.bdcr().modify(|w| { - // Reset - w.set_bdrst(false); - - // Select RTC source - w.set_rtcsel(Rtcsel(clock_config)); - w.set_rtcen(true); - - // Restore bcdr - w.set_lscosel(reg.lscosel()); - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); -} diff --git a/embassy-stm32/src/rtc/v2/v2wb.rs b/embassy-stm32/src/rtc/v2/v2wb.rs deleted file mode 100644 index 98761fa6..00000000 --- a/embassy-stm32/src/rtc/v2/v2wb.rs +++ /dev/null @@ -1,39 +0,0 @@ -pub const BACKUP_REGISTER_COUNT: usize = 20; - -/// Unlock the backup domain -pub(super) unsafe fn unlock_backup_domain(clock_config: u8) { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - - let reg = crate::pac::RCC.bdcr().read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() || reg.rtcsel() != clock_config { - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - - crate::pac::RCC.bdcr().modify(|w| { - // Reset - w.set_bdrst(false); - - // Select RTC source - w.set_rtcsel(clock_config); - w.set_rtcen(true); - - // Restore bcdr - w.set_lscosel(reg.lscosel()); - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } -} - -pub(crate) unsafe fn enable_peripheral_clk() { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); -} diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 6998c48c..19c52ee0 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,6 +1,6 @@ use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; -use super::{Instance, RtcCalibrationCyclePeriod, RtcConfig}; +use super::{sealed, Instance, RtcCalibrationCyclePeriod, RtcConfig}; use crate::pac::rtc::Rtc; impl<'d, T: Instance> super::Rtc<'d, T> { @@ -9,43 +9,30 @@ impl<'d, T: Instance> super::Rtc<'d, T> { pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { // Unlock the backup domain unsafe { - #[cfg(feature = "stm32g0c1ve")] + #[cfg(any(rtc_v3u5, rcc_g0))] + use crate::pac::rcc::vals::Rtcsel; + #[cfg(not(any(rtc_v3u5, rcc_g0, rcc_g4, rcc_wl5, rcc_wle)))] + use crate::pac::rtc::vals::Rtcsel; + + #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] { crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); while !crate::pac::PWR.cr1().read().dbp() {} } - - #[cfg(not(any( - feature = "stm32g0c1ve", - feature = "stm32g491re", - feature = "stm32u585zi", - feature = "stm32g473cc" - )))] + #[cfg(any(rcc_wl5, rcc_wle))] { - crate::pac::PWR - .cr1() - .modify(|w| w.set_dbp(stm32_metapac::pwr::vals::Dbp::ENABLED)); - while crate::pac::PWR.cr1().read().dbp() != stm32_metapac::pwr::vals::Dbp::DISABLED {} + use crate::pac::pwr::vals::Dbp; + + crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); + while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} } let reg = crate::pac::RCC.bdcr().read(); assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); let config_rtcsel = rtc_config.clock_config as u8; - #[cfg(not(any( - feature = "stm32wl54jc-cm0p", - feature = "stm32wle5ub", - feature = "stm32g0c1ve", - feature = "stm32wl55jc-cm4", - feature = "stm32wl55uc-cm4", - feature = "stm32g491re", - feature = "stm32g473cc", - feature = "stm32u585zi", - feature = "stm32wle5jb" - )))] - let config_rtcsel = stm32_metapac::rtc::vals::Rtcsel(config_rtcsel); - #[cfg(feature = "stm32g0c1ve")] - let config_rtcsel = stm32_metapac::rcc::vals::Rtcsel(config_rtcsel); + #[cfg(not(any(rcc_wl5, rcc_wle, rcc_g4)))] + let config_rtcsel = Rtcsel(config_rtcsel); if !reg.rtcen() || reg.rtcsel() != config_rtcsel { crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); @@ -195,32 +182,24 @@ impl<'d, T: Instance> super::Rtc<'d, T> { } } -pub(super) unsafe fn enable_peripheral_clk() { - // Nothing to do -} +impl sealed::Instance for crate::peripherals::RTC { + const BACKUP_REGISTER_COUNT: usize = 32; -pub const BACKUP_REGISTER_COUNT: usize = 32; + fn read_backup_register(_rtc: &Rtc, register: usize) -> Option { + if register < Self::BACKUP_REGISTER_COUNT { + //Some(rtc.bkpr()[register].read().bits()) + None // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC + } else { + None + } + } -/// Read content of the backup register. -/// -/// The registers retain their values during wakes from standby mode or system resets. They also -/// retain their value when Vdd is switched off as long as V_BAT is powered. -pub fn read_backup_register(_rtc: &Rtc, register: usize) -> Option { - if register < BACKUP_REGISTER_COUNT { - //Some(rtc.bkpr()[register].read().bits()) - None // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC - } else { - None + fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) { + if register < Self::BACKUP_REGISTER_COUNT { + // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC + //unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) } + } } } -/// Set content of the backup register. -/// -/// The registers retain their values during wakes from standby mode or system resets. They also -/// retain their value when Vdd is switched off as long as V_BAT is powered. -pub fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) { - if register < BACKUP_REGISTER_COUNT { - // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC - //unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) } - } -} +impl Instance for crate::peripherals::RTC {} diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 511a1fa8..f5f8b632 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -26,6 +26,7 @@ nb = "1.0.0" embedded-storage = "0.3.0" micromath = "2.0.0" static_cell = "1.0" +chrono = { version = "^0.4", default-features = false} [profile.release] debug = 2 diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs new file mode 100644 index 00000000..0eca5820 --- /dev/null +++ b/examples/stm32f4/src/bin/rtc.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use chrono::{NaiveDate, NaiveDateTime}; +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let now = NaiveDate::from_ymd_opt(2020, 5, 15) + .unwrap() + .and_hms_opt(10, 30, 15) + .unwrap(); + + let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + + rtc.set_datetime(now.into()).expect("datetime not set"); + + // In reality the delay would be much longer + Timer::after(Duration::from_millis(20000)).await; + + let _then: NaiveDateTime = rtc.now().unwrap().into(); +} diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 84261f8e..d10d01e2 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [features] stm32f103c8 = ["embassy-stm32/stm32f103c8"] # Blue Pill -stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc"] # Nucleo +stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc", "chrono"] # Nucleo stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo stm32c031c6 = ["embassy-stm32/stm32c031c6"] # Nucleo stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo @@ -16,6 +16,7 @@ stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board sdmmc = [] +chrono = ["embassy-stm32/chrono", "dep:chrono"] [dependencies] embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } @@ -33,6 +34,8 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } embedded-hal-async = { version = "=0.2.0-alpha.1" } panic-probe = { version = "0.3.0", features = ["print-defmt"] } +chrono = { version = "^0.4", default-features = false, optional = true} + # BEGIN TESTS # Generated by gen_test.py. DO NOT EDIT. [[bin]] @@ -40,6 +43,11 @@ name = "gpio" path = "src/bin/gpio.rs" required-features = [] +[[bin]] +name = "rtc" +path = "src/bin/rtc.rs" +required-features = [ "chrono",] + [[bin]] name = "sdmmc" path = "src/bin/sdmmc.rs" diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs new file mode 100644 index 00000000..ccf2ca60 --- /dev/null +++ b/tests/stm32/src/bin/rtc.rs @@ -0,0 +1,52 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +// required-features: chrono + +#[path = "../example_common.rs"] +mod example_common; +use chrono::{NaiveDate, NaiveDateTime}; +use defmt::assert; +use embassy_executor::Spawner; +use embassy_stm32::pac; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_time::{Duration, Timer}; +use example_common::*; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(config()); + info!("Hello World!"); + + let now = NaiveDate::from_ymd_opt(2020, 5, 15) + .unwrap() + .and_hms_opt(10, 30, 15) + .unwrap(); + + info!("Starting LSI"); + + unsafe { + pac::RCC.csr().modify(|w| w.set_lsion(true)); + while !pac::RCC.csr().read().lsirdy() {} + } + + info!("Started LSI"); + + let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + + rtc.set_datetime(now.into()).expect("datetime not set"); + + info!("Waiting 5 seconds"); + Timer::after(Duration::from_millis(5000)).await; + + let then: NaiveDateTime = rtc.now().unwrap().into(); + let seconds = (then - now).num_seconds(); + + defmt::info!("measured = {}", seconds); + + assert!(seconds > 3 && seconds < 7); + + info!("Test OK"); + cortex_m::asm::bkpt(); +}