diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index d5846f530..0d853fda2 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -61,7 +61,7 @@ pub struct Executor {
 impl Executor {
     /// Create a new Executor.
     pub fn take() -> &'static mut Self {
-        unsafe {
+        critical_section::with(|_| unsafe {
             assert!(EXECUTOR.is_none());
 
             EXECUTOR = Some(Self {
@@ -72,7 +72,7 @@ impl Executor {
             });
 
             EXECUTOR.as_mut().unwrap()
-        }
+        })
     }
 
     unsafe fn on_wakeup_irq(&mut self) {
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index d897843dc..f3428108c 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -18,9 +18,13 @@ pub struct RtcInstant {
 }
 
 impl RtcInstant {
-    #[allow(dead_code)]
-    pub(super) fn from(second: u8, subsecond: u16) -> Result<Self, super::RtcError> {
-        Ok(Self { second, subsecond })
+    #[cfg(not(rtc_v2f2))]
+    pub(super) const fn from(second: u8, subsecond: u16) -> Result<Self, Error> {
+        if second > 59 {
+            Err(Error::InvalidSecond)
+        } else {
+            Ok(Self { second, subsecond })
+        }
     }
 }
 
@@ -226,7 +230,7 @@ impl From<DayOfWeek> for chrono::Weekday {
     }
 }
 
-fn day_of_week_from_u8(v: u8) -> Result<DayOfWeek, Error> {
+pub(super) const fn day_of_week_from_u8(v: u8) -> Result<DayOfWeek, Error> {
     Ok(match v {
         1 => DayOfWeek::Monday,
         2 => DayOfWeek::Tuesday,
@@ -239,24 +243,6 @@ fn day_of_week_from_u8(v: u8) -> Result<DayOfWeek, Error> {
     })
 }
 
-pub(super) fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 {
+pub(super) const fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 {
     dotw as u8
 }
-
-pub(super) fn validate_datetime(dt: &DateTime) -> Result<(), Error> {
-    if dt.year > 4095 {
-        Err(Error::InvalidYear)
-    } else if dt.month < 1 || dt.month > 12 {
-        Err(Error::InvalidMonth)
-    } else if dt.day < 1 || dt.day > 31 {
-        Err(Error::InvalidDay)
-    } else if dt.hour > 23 {
-        Err(Error::InvalidHour)
-    } else if dt.minute > 59 {
-        Err(Error::InvalidMinute)
-    } else if dt.second > 59 {
-        Err(Error::InvalidSecond)
-    } else {
-        Ok(())
-    }
-}
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index c8990c30a..e527fdfee 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -9,8 +9,11 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
 #[cfg(feature = "low-power")]
 use embassy_sync::blocking_mutex::Mutex;
 
-pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError, RtcInstant};
-use crate::rtc::datetime::day_of_week_to_u8;
+use self::datetime::day_of_week_to_u8;
+#[cfg(not(rtc_v2f2))]
+use self::datetime::RtcInstant;
+pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
+use crate::pac::rtc::regs::{Dr, Tr};
 use crate::time::Hertz;
 
 /// refer to AN4759 to compare features of RTC2 and RTC3
@@ -31,11 +34,15 @@ use crate::peripherals::RTC;
 use crate::rtc::sealed::Instance;
 
 /// Errors that can occur on methods on [RtcClock]
+#[non_exhaustive]
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum RtcError {
     /// An invalid DateTime was given or stored on the hardware.
     InvalidDateTime(DateTimeError),
 
+    /// The current time could not be read
+    ReadFailure,
+
     /// The RTC clock is not running
     NotRunning,
 }
@@ -45,48 +52,25 @@ pub struct RtcTimeProvider {
 }
 
 impl RtcTimeProvider {
+    #[cfg(not(rtc_v2f2))]
+    pub(crate) fn instant(&self) -> Result<RtcInstant, RtcError> {
+        self.read(|_, tr, ss| {
+            let second = bcd2_to_byte((tr.st(), tr.su()));
+
+            RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
+        })
+    }
+
     /// Return the current datetime.
     ///
     /// # Errors
     ///
     /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
     pub fn now(&self) -> Result<DateTime, RtcError> {
-        // For RM0433 we use BYPSHAD=1 to work around errata ES0392 2.19.1
-        #[cfg(rcc_h7rm0433)]
-        loop {
-            let r = RTC::regs();
-            let ss = r.ssr().read().ss();
-            let dr = r.dr().read();
-            let tr = r.tr().read();
-
-            // If an RTCCLK edge occurs during read we may see inconsistent values
-            // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9)
-            let ss_after = r.ssr().read().ss();
-            if ss == ss_after {
-                let second = bcd2_to_byte((tr.st(), tr.su()));
-                let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
-                let hour = bcd2_to_byte((tr.ht(), tr.hu()));
-
-                let weekday = dr.wdu();
-                let day = bcd2_to_byte((dr.dt(), dr.du()));
-                let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
-                let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
-
-                return DateTime::from(year, month, day, weekday, hour, minute, second)
-                    .map_err(RtcError::InvalidDateTime);
-            }
-        }
-
-        #[cfg(not(rcc_h7rm0433))]
-        {
-            let r = RTC::regs();
-            let tr = r.tr().read();
+        self.read(|dr, tr, _| {
             let second = bcd2_to_byte((tr.st(), tr.su()));
             let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
             let hour = bcd2_to_byte((tr.ht(), tr.hu()));
-            // Reading either RTC_SSR or RTC_TR locks the values in the higher-order
-            // calendar shadow registers until RTC_DR is read.
-            let dr = r.dr().read();
 
             let weekday = dr.wdu();
             let day = bcd2_to_byte((dr.dt(), dr.du()));
@@ -94,7 +78,33 @@ impl RtcTimeProvider {
             let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
 
             DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
+        })
+    }
+
+    fn read<R>(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result<R, RtcError>) -> Result<R, RtcError> {
+        let r = RTC::regs();
+
+        #[cfg(not(rtc_v2f2))]
+        let read_ss = || r.ssr().read().ss();
+        #[cfg(rtc_v2f2)]
+        let read_ss = || 0;
+
+        let mut ss = read_ss();
+        for _ in 0..5 {
+            let tr = r.tr().read();
+            let dr = r.dr().read();
+            let ss_after = read_ss();
+
+            // If an RTCCLK edge occurs during read we may see inconsistent values
+            // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9)
+            if ss == ss_after {
+                return f(dr, tr, ss.try_into().unwrap());
+            } else {
+                ss = ss_after
+            }
         }
+
+        return Err(RtcError::ReadFailure);
     }
 }
 
@@ -145,6 +155,7 @@ impl Rtc {
         #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
         critical_section::with(|cs| {
             <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(cs);
+
             #[cfg(feature = "low-power")]
             unsafe {
                 crate::rcc::REFCOUNT_STOP2 -= 1
@@ -164,6 +175,14 @@ impl Rtc {
 
         this.configure(async_psc, sync_psc);
 
+        // Wait for the clock to update after initialization
+        #[cfg(not(rtc_v2f2))]
+        {
+            let now = this.instant().unwrap();
+
+            while this.instant().unwrap().subsecond == now.subsecond {}
+        }
+
         this
     }
 
@@ -183,7 +202,6 @@ impl Rtc {
     ///
     /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
     pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> {
-        self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
         self.write(true, |rtc| {
             let (ht, hu) = byte_to_bcd2(t.hour() as u8);
             let (mnt, mnu) = byte_to_bcd2(t.minute() as u8);
@@ -223,16 +241,8 @@ impl Rtc {
 
     #[cfg(not(rtc_v2f2))]
     /// Return the current instant.
-    pub fn instant(&self) -> Result<RtcInstant, RtcError> {
-        let r = RTC::regs();
-        let tr = r.tr().read();
-        let subsecond = r.ssr().read().ss();
-        let second = bcd2_to_byte((tr.st(), tr.su()));
-
-        // Unlock the registers
-        r.dr().read();
-
-        RtcInstant::from(second, subsecond.try_into().unwrap())
+    fn instant(&self) -> Result<RtcInstant, RtcError> {
+        self.time_provider().instant()
     }
 
     /// Return the current datetime.
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index b6ab9b209..006fd63f4 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -150,14 +150,14 @@ impl super::Rtc {
     pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
         self.write(true, |rtc| {
             rtc.cr().modify(|w| {
+                #[cfg(not(rtc_v2f2))]
+                w.set_bypshad(true);
                 #[cfg(rtc_v2f2)]
                 w.set_fmt(false);
                 #[cfg(not(rtc_v2f2))]
                 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
                 w.set_osel(Osel::DISABLED);
                 w.set_pol(Pol::HIGH);
-                #[cfg(rcc_h7rm0433)]
-                w.set_bypshad(true);
             });
 
             rtc.prer().modify(|w| {
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index a6b2655d8..7bf757e7d 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -11,6 +11,7 @@ impl super::Rtc {
     pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
         self.write(true, |rtc| {
             rtc.cr().modify(|w| {
+                w.set_bypshad(true);
                 w.set_fmt(Fmt::TWENTYFOURHOUR);
                 w.set_osel(Osel::DISABLED);
                 w.set_pol(Pol::HIGH);