From d372df7ddb381571fd2964e32b486b6d1cd1ad03 Mon Sep 17 00:00:00 2001
From: Mathias <mk@blackbird.online>
Date: Sat, 1 Jul 2023 12:16:23 +0200
Subject: [PATCH] L4: Switch to MSI to prevent problems with PLL configuration,
 and enable power to AHB bus clock to allow RTC to run

---
 embassy-stm32/src/rcc/l4.rs     | 23 +++++++++++++++
 examples/stm32l4/src/bin/rtc.rs | 50 +++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)
 create mode 100644 examples/stm32l4/src/bin/rtc.rs

diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index f8c1a6e06..f7f3b9046 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -1,6 +1,7 @@
 use core::marker::PhantomData;
 
 use embassy_hal_common::into_ref;
+use stm32_metapac::rcc::regs::Cfgr;
 use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel};
 
 use crate::gpio::sealed::AFType;
@@ -439,6 +440,26 @@ impl<'d, T: McoInstance> Mco<'d, T> {
 }
 
 pub(crate) unsafe fn init(config: Config) {
+    // Switch to MSI to prevent problems with PLL configuration.
+    if !RCC.cr().read().msion() {
+        // Turn on MSI and configure it to 4MHz.
+        RCC.cr().modify(|w| {
+            w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0].
+            w.set_msirange(MSIRange::default().into());
+            w.set_msipllen(false);
+            w.set_msion(true)
+        });
+
+        // Wait until MSI is running
+        while !RCC.cr().read().msirdy() {}
+    }
+    if RCC.cfgr().read().sws() != Sw::MSI {
+        // Set MSI as a clock source, reset prescalers.
+        RCC.cfgr().write_value(Cfgr::default());
+        // Wait for clock switch status bits to change.
+        while RCC.cfgr().read().sws() != Sw::MSI {}
+    }
+
     match config.rtc_mux {
         RtcClockSource::LSE32 => {
             // 1. Unlock the backup domain
@@ -660,6 +681,8 @@ pub(crate) unsafe fn init(config: Config) {
         }
     };
 
+    RCC.apb1enr1().modify(|w| w.set_pwren(true));
+
     set_freqs(Clocks {
         sys: Hertz(sys_clk),
         ahb1: Hertz(ahb_freq),
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
new file mode 100644
index 000000000..0de708950
--- /dev/null
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -0,0 +1,50 @@
+#![no_std]
+#![no_main]
+#![feature(type_alias_impl_trait)]
+
+use chrono::{NaiveDate, NaiveDateTime};
+use defmt::*;
+use embassy_executor::Spawner;
+use embassy_stm32::rcc::{self, ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv};
+use embassy_stm32::rtc::{Rtc, RtcConfig};
+use embassy_stm32::time::Hertz;
+use embassy_stm32::Config;
+use embassy_time::{Duration, Timer};
+use {defmt_rtt as _, panic_probe as _};
+
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) {
+    let p = {
+        let mut config = Config::default();
+        config.rcc.mux = ClockSrc::PLL(
+            PLLSource::HSE(Hertz::mhz(8)),
+            PLLClkDiv::Div2,
+            PLLSrcDiv::Div1,
+            PLLMul::Mul20,
+            None,
+        );
+        config.rcc.rtc_mux = rcc::RtcClockSource::LSE32;
+        embassy_stm32::init(config)
+    };
+    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().clock_config(embassy_stm32::rtc::RtcClockSource::LSE),
+    );
+    info!("Got RTC! {:?}", now.timestamp());
+
+    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();
+    info!("Got RTC! {:?}", then.timestamp());
+
+}