aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Ickstadt <[email protected]>2023-10-03 16:45:05 -0500
committerMatt Ickstadt <[email protected]>2023-10-06 13:28:30 -0500
commitf01609036ff757ef3f04e568c646a467289d5440 (patch)
tree1a1f974ba94cb5f9fe59de9c89b6f3682ed4766a
parent65ed19aae272d6d6320554446f9187ec2ef8bf39 (diff)
h7: implement RTC and LSE clock configuration
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/dac/mod.rs4
-rw-r--r--embassy-stm32/src/rcc/bd.rs47
-rw-r--r--embassy-stm32/src/rcc/f4.rs2
-rw-r--r--embassy-stm32/src/rcc/h.rs57
-rw-r--r--embassy-stm32/src/rcc/l4.rs2
-rw-r--r--embassy-stm32/src/rcc/mod.rs59
-rw-r--r--embassy-stm32/src/rcc/wl.rs2
-rw-r--r--embassy-stm32/src/rtc/mod.rs65
-rw-r--r--embassy-stm32/src/rtc/v2.rs2
-rw-r--r--examples/stm32h7/Cargo.toml3
-rw-r--r--examples/stm32h7/src/bin/rtc.rs39
12 files changed, 233 insertions, 53 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 1b688eca9..5258e4c7c 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -59,7 +59,7 @@ sdio-host = "0.5.0"
59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
60critical-section = "1.1" 60critical-section = "1.1"
61atomic-polyfill = "1.0.1" 61atomic-polyfill = "1.0.1"
62stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-172c5ea18824d7cd38decb210e4af441fa3816cb" } 62stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f0f06b4c95bd9e185e4aa5f2e1d4b76ba84f1594" }
63vcell = "0.1.3" 63vcell = "0.1.3"
64bxcan = "0.7.0" 64bxcan = "0.7.0"
65nb = "1.0.0" 65nb = "1.0.0"
@@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
78[build-dependencies] 78[build-dependencies]
79proc-macro2 = "1.0.36" 79proc-macro2 = "1.0.36"
80quote = "1.0.15" 80quote = "1.0.15"
81stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-172c5ea18824d7cd38decb210e4af441fa3816cb", default-features = false, features = ["metadata"]} 81stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f0f06b4c95bd9e185e4aa5f2e1d4b76ba84f1594", default-features = false, features = ["metadata"]}
82 82
83 83
84[features] 84[features]
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index a2040b857..976aa3eea 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -564,7 +564,7 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
564foreach_peripheral!( 564foreach_peripheral!(
565 (dac, $inst:ident) => { 565 (dac, $inst:ident) => {
566 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented 566 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
567 #[cfg(rcc_h7)] 567 #[cfg(any(rcc_h7, rcc_h7rm0433))]
568 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { 568 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
569 fn frequency() -> crate::time::Hertz { 569 fn frequency() -> crate::time::Hertz {
570 critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 }) 570 critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
@@ -590,7 +590,7 @@ foreach_peripheral!(
590 } 590 }
591 } 591 }
592 592
593 #[cfg(rcc_h7)] 593 #[cfg(any(rcc_h7, rcc_h7rm0433))]
594 impl crate::rcc::RccPeripheral for peripherals::$inst {} 594 impl crate::rcc::RccPeripheral for peripherals::$inst {}
595 595
596 impl crate::dac::sealed::Instance for peripherals::$inst { 596 impl crate::dac::sealed::Instance for peripherals::$inst {
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index cec2ea010..9c784c3a3 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -1,26 +1,36 @@
1#[allow(dead_code)] 1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum LseCfg {
4 Oscillator(LseDrive),
5 Bypass,
6}
7
8impl Default for LseCfg {
9 fn default() -> Self {
10 Self::Oscillator(Default::default())
11 }
12}
13
14#[allow(dead_code)]
2#[derive(Default, Clone, Copy)] 15#[derive(Default, Clone, Copy)]
3pub enum LseDrive { 16pub enum LseDrive {
4 #[cfg(any(rtc_v2f7, rtc_v2l4))]
5 Low = 0, 17 Low = 0,
6 MediumLow = 0x01, 18 MediumLow = 0x01,
7 #[default] 19 #[default]
8 MediumHigh = 0x02, 20 MediumHigh = 0x02,
9 #[cfg(any(rtc_v2f7, rtc_v2l4))]
10 High = 0x03, 21 High = 0x03,
11} 22}
12 23
13#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] 24// All families but these have the LSEDRV register
25#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
14impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { 26impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
15 fn from(value: LseDrive) -> Self { 27 fn from(value: LseDrive) -> Self {
16 use crate::pac::rcc::vals::Lsedrv; 28 use crate::pac::rcc::vals::Lsedrv;
17 29
18 match value { 30 match value {
19 #[cfg(any(rtc_v2f7, rtc_v2l4))]
20 LseDrive::Low => Lsedrv::LOW, 31 LseDrive::Low => Lsedrv::LOW,
21 LseDrive::MediumLow => Lsedrv::MEDIUMLOW, 32 LseDrive::MediumLow => Lsedrv::MEDIUMLOW,
22 LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, 33 LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH,
23 #[cfg(any(rtc_v2f7, rtc_v2l4))]
24 LseDrive::High => Lsedrv::HIGH, 34 LseDrive::High => Lsedrv::HIGH,
25 } 35 }
26 } 36 }
@@ -87,14 +97,19 @@ impl BackupDomain {
87 rtc_v3u5 97 rtc_v3u5
88 ))] 98 ))]
89 #[allow(dead_code, unused_variables)] 99 #[allow(dead_code, unused_variables)]
90 pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseDrive>) { 100 pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseCfg>) {
91 use atomic_polyfill::{compiler_fence, Ordering}; 101 use atomic_polyfill::{compiler_fence, Ordering};
92 102
93 match clock_source { 103 match clock_source {
94 RtcClockSource::LSI => assert!(lsi), 104 RtcClockSource::LSI => assert!(lsi),
95 RtcClockSource::LSE => assert!(&lse.is_some()), 105 RtcClockSource::LSE => assert!(lse.is_some()),
96 _ => {} 106 _ => {}
97 }; 107 };
108 let (lse_en, lse_byp, lse_drv) = match lse {
109 Some(LseCfg::Oscillator(lse_drv)) => (true, false, Some(lse_drv)),
110 Some(LseCfg::Bypass) => (true, true, None),
111 None => (false, false, None),
112 };
98 113
99 if lsi { 114 if lsi {
100 #[cfg(rtc_v3u5)] 115 #[cfg(rtc_v3u5)]
@@ -131,10 +146,11 @@ impl BackupDomain {
131 { 146 {
132 ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK); 147 ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK);
133 } 148 }
134 ok &= reg.lseon() == lse.is_some(); 149 ok &= reg.lseon() == lse_en;
135 #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] 150 ok &= reg.lsebyp() == lse_byp;
136 if let Some(lse_drive) = lse { 151 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
137 ok &= reg.lsedrv() == lse_drive.into(); 152 if let Some(lse_drv) = lse_drv {
153 ok &= reg.lsedrv() == lse_drv.into();
138 } 154 }
139 155
140 // if configuration is OK, we're done. 156 // if configuration is OK, we're done.
@@ -153,10 +169,13 @@ impl BackupDomain {
153 Self::modify(|w| w.set_bdrst(false)); 169 Self::modify(|w| w.set_bdrst(false));
154 } 170 }
155 171
156 if let Some(lse_drive) = lse { 172 if lse_en {
157 Self::modify(|w| { 173 Self::modify(|w| {
158 #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] 174 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
159 w.set_lsedrv(lse_drive.into()); 175 if let Some(lse_drv) = lse_drv {
176 w.set_lsedrv(lse_drv.into());
177 }
178 w.set_lsebyp(lse_byp);
160 w.set_lseon(true); 179 w.set_lseon(true);
161 }); 180 });
162 181
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index edc5ff52e..5ba958a02 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -540,7 +540,7 @@ pub(crate) unsafe fn init(config: Config) {
540 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] 540 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
541 pllsai: plls.pllsaiclk.map(Hertz), 541 pllsai: plls.pllsaiclk.map(Hertz),
542 542
543 rtc: rtc, 543 rtc,
544 rtc_hse: None, 544 rtc_hse: None,
545 }); 545 });
546} 546}
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 43e8db22e..5f9cc1c8b 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -9,6 +9,8 @@ pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
9pub use crate::pac::rcc::vals::Ckpersel as PerClockSource; 9pub use crate::pac::rcc::vals::Ckpersel as PerClockSource;
10use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; 10use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
11use crate::pac::{FLASH, PWR, RCC}; 11use crate::pac::{FLASH, PWR, RCC};
12#[cfg(stm32h7)]
13use crate::rcc::bd::{BackupDomain, LseCfg, RtcClockSource};
12use crate::rcc::{set_freqs, Clocks}; 14use crate::rcc::{set_freqs, Clocks};
13use crate::time::Hertz; 15use crate::time::Hertz;
14 16
@@ -46,9 +48,9 @@ pub enum VoltageScale {
46pub enum HseMode { 48pub enum HseMode {
47 /// crystal/ceramic oscillator (HSEBYP=0) 49 /// crystal/ceramic oscillator (HSEBYP=0)
48 Oscillator, 50 Oscillator,
49 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) 51 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
50 Bypass, 52 Bypass,
51 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) 53 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
52 #[cfg(any(rcc_h5, rcc_h50))] 54 #[cfg(any(rcc_h5, rcc_h50))]
53 BypassDigital, 55 BypassDigital,
54} 56}
@@ -61,6 +63,15 @@ pub struct Hse {
61 pub mode: HseMode, 63 pub mode: HseMode,
62} 64}
63 65
66#[cfg(stm32h7)]
67#[derive(Clone, Copy, Eq, PartialEq)]
68pub enum Lse {
69 /// 32.768 kHz crystal/ceramic oscillator (LSEBYP=0)
70 Oscillator,
71 /// external clock input up to 1MHz (LSEBYP=1)
72 Bypass(Hertz),
73}
74
64#[derive(Clone, Copy, Eq, PartialEq)] 75#[derive(Clone, Copy, Eq, PartialEq)]
65pub enum Hsi { 76pub enum Hsi {
66 /// 64Mhz 77 /// 64Mhz
@@ -157,6 +168,10 @@ impl From<TimerPrescaler> for Timpre {
157pub struct Config { 168pub struct Config {
158 pub hsi: Option<Hsi>, 169 pub hsi: Option<Hsi>,
159 pub hse: Option<Hse>, 170 pub hse: Option<Hse>,
171 #[cfg(stm32h7)]
172 pub lse: Option<Lse>,
173 #[cfg(stm32h7)]
174 pub lsi: bool,
160 pub csi: bool, 175 pub csi: bool,
161 pub hsi48: bool, 176 pub hsi48: bool,
162 pub sys: Sysclk, 177 pub sys: Sysclk,
@@ -181,6 +196,8 @@ pub struct Config {
181 pub adc_clock_source: AdcClockSource, 196 pub adc_clock_source: AdcClockSource,
182 pub timer_prescaler: TimerPrescaler, 197 pub timer_prescaler: TimerPrescaler,
183 pub voltage_scale: VoltageScale, 198 pub voltage_scale: VoltageScale,
199 #[cfg(stm32h7)]
200 pub rtc_mux: Option<RtcClockSource>,
184} 201}
185 202
186impl Default for Config { 203impl Default for Config {
@@ -188,6 +205,10 @@ impl Default for Config {
188 Self { 205 Self {
189 hsi: Some(Hsi::Mhz64), 206 hsi: Some(Hsi::Mhz64),
190 hse: None, 207 hse: None,
208 #[cfg(stm32h7)]
209 lse: None,
210 #[cfg(stm32h7)]
211 lsi: false,
191 csi: false, 212 csi: false,
192 hsi48: false, 213 hsi48: false,
193 sys: Sysclk::HSI, 214 sys: Sysclk::HSI,
@@ -210,6 +231,8 @@ impl Default for Config {
210 adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5 231 adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5
211 timer_prescaler: TimerPrescaler::DefaultX2, 232 timer_prescaler: TimerPrescaler::DefaultX2,
212 voltage_scale: VoltageScale::Scale0, 233 voltage_scale: VoltageScale::Scale0,
234 #[cfg(stm32h7)]
235 rtc_mux: None,
213 } 236 }
214 } 237 }
215} 238}
@@ -450,6 +473,19 @@ pub(crate) unsafe fn init(config: Config) {
450 473
451 #[cfg(stm32h7)] 474 #[cfg(stm32h7)]
452 { 475 {
476 let lsecfg = config.lse.map(|lse| match lse {
477 Lse::Bypass(freq) => {
478 assert!(freq <= Hertz(1_000_000));
479 LseCfg::Bypass
480 }
481 Lse::Oscillator => LseCfg::Oscillator(Default::default()),
482 });
483
484 BackupDomain::configure_ls(config.rtc_mux.unwrap_or(RtcClockSource::NOCLOCK), config.lsi, lsecfg);
485 }
486
487 #[cfg(stm32h7)]
488 {
453 RCC.d1cfgr().modify(|w| { 489 RCC.d1cfgr().modify(|w| {
454 w.set_d1cpre(config.d1c_pre); 490 w.set_d1cpre(config.d1c_pre);
455 w.set_d1ppre(config.apb3_pre); 491 w.set_d1ppre(config.apb3_pre);
@@ -512,6 +548,17 @@ pub(crate) unsafe fn init(config: Config) {
512 while !pac::SYSCFG.cccsr().read().ready() {} 548 while !pac::SYSCFG.cccsr().read().ready() {}
513 } 549 }
514 550
551 #[cfg(stm32h7)]
552 let rtc_clk = match config.rtc_mux {
553 Some(RtcClockSource::LSI) => Some(LSI_FREQ),
554 Some(RtcClockSource::LSE) => Some(match config.lse {
555 Some(Lse::Oscillator) => Hertz(32768),
556 Some(Lse::Bypass(freq)) => freq,
557 None => panic!("LSE not configured"),
558 }),
559 _ => None,
560 };
561
515 set_freqs(Clocks { 562 set_freqs(Clocks {
516 sys, 563 sys,
517 ahb1: hclk, 564 ahb1: hclk,
@@ -525,7 +572,11 @@ pub(crate) unsafe fn init(config: Config) {
525 apb4, 572 apb4,
526 apb1_tim, 573 apb1_tim,
527 apb2_tim, 574 apb2_tim,
528 adc: adc, 575 adc,
576 #[cfg(stm32h7)]
577 rtc: rtc_clk,
578 #[cfg(stm32h7)]
579 rtc_hse: None,
529 }); 580 });
530} 581}
531 582
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index 6f1f7458c..3a24eca82 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -420,7 +420,7 @@ pub(crate) unsafe fn init(config: Config) {
420 w.set_msirgsel(true); 420 w.set_msirgsel(true);
421 w.set_msion(true); 421 w.set_msion(true);
422 422
423 if let RtcClockSource::LSE = config.rtc_mux { 423 if config.rtc_mux == RtcClockSource::LSE {
424 // If LSE is enabled, enable calibration of MSI 424 // If LSE is enabled, enable calibration of MSI
425 w.set_msipllen(true); 425 w.set_msipllen(true);
426 } else { 426 } else {
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index ac9673833..bf497ca12 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -21,7 +21,7 @@ pub use mco::*;
21#[cfg_attr(rcc_c0, path = "c0.rs")] 21#[cfg_attr(rcc_c0, path = "c0.rs")]
22#[cfg_attr(rcc_g0, path = "g0.rs")] 22#[cfg_attr(rcc_g0, path = "g0.rs")]
23#[cfg_attr(rcc_g4, path = "g4.rs")] 23#[cfg_attr(rcc_g4, path = "g4.rs")]
24#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")] 24#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")]
25#[cfg_attr(rcc_l0, path = "l0.rs")] 25#[cfg_attr(rcc_l0, path = "l0.rs")]
26#[cfg_attr(rcc_l1, path = "l1.rs")] 26#[cfg_attr(rcc_l1, path = "l1.rs")]
27#[cfg_attr(rcc_l4, path = "l4.rs")] 27#[cfg_attr(rcc_l4, path = "l4.rs")]
@@ -57,9 +57,9 @@ pub struct Clocks {
57 pub apb2: Hertz, 57 pub apb2: Hertz,
58 #[cfg(not(any(rcc_c0, rcc_g0)))] 58 #[cfg(not(any(rcc_c0, rcc_g0)))]
59 pub apb2_tim: Hertz, 59 pub apb2_tim: Hertz,
60 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))] 60 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))]
61 pub apb3: Hertz, 61 pub apb3: Hertz,
62 #[cfg(any(rcc_h7, rcc_h7ab))] 62 #[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab))]
63 pub apb4: Hertz, 63 pub apb4: Hertz,
64 #[cfg(any(rcc_wba))] 64 #[cfg(any(rcc_wba))]
65 pub apb7: Hertz, 65 pub apb7: Hertz,
@@ -67,16 +67,44 @@ pub struct Clocks {
67 // AHB 67 // AHB
68 pub ahb1: Hertz, 68 pub ahb1: Hertz,
69 #[cfg(any( 69 #[cfg(any(
70 rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, 70 rcc_l4,
71 rcc_wba, rcc_wl5, rcc_wle 71 rcc_l5,
72 rcc_f2,
73 rcc_f4,
74 rcc_f410,
75 rcc_f7,
76 rcc_h5,
77 rcc_h50,
78 rcc_h7,
79 rcc_h7rm0433,
80 rcc_h7ab,
81 rcc_g4,
82 rcc_u5,
83 rcc_wb,
84 rcc_wba,
85 rcc_wl5,
86 rcc_wle
72 ))] 87 ))]
73 pub ahb2: Hertz, 88 pub ahb2: Hertz,
74 #[cfg(any( 89 #[cfg(any(
75 rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5, 90 rcc_l4,
91 rcc_l5,
92 rcc_f2,
93 rcc_f4,
94 rcc_f410,
95 rcc_f7,
96 rcc_h5,
97 rcc_h50,
98 rcc_h7,
99 rcc_h7rm0433,
100 rcc_h7ab,
101 rcc_u5,
102 rcc_wb,
103 rcc_wl5,
76 rcc_wle 104 rcc_wle
77 ))] 105 ))]
78 pub ahb3: Hertz, 106 pub ahb3: Hertz,
79 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))] 107 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))]
80 pub ahb4: Hertz, 108 pub ahb4: Hertz,
81 109
82 #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] 110 #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
@@ -88,7 +116,18 @@ pub struct Clocks {
88 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] 116 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
89 pub pllsai: Option<Hertz>, 117 pub pllsai: Option<Hertz>,
90 118
91 #[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))] 119 #[cfg(any(
120 rcc_f1,
121 rcc_f100,
122 rcc_f1cl,
123 rcc_h5,
124 rcc_h50,
125 rcc_h7,
126 rcc_h7rm0433,
127 rcc_h7ab,
128 rcc_f3,
129 rcc_g4
130 ))]
92 pub adc: Option<Hertz>, 131 pub adc: Option<Hertz>,
93 132
94 #[cfg(any(rcc_f3, rcc_g4))] 133 #[cfg(any(rcc_f3, rcc_g4))]
@@ -97,11 +136,11 @@ pub struct Clocks {
97 #[cfg(stm32f334)] 136 #[cfg(stm32f334)]
98 pub hrtim: Option<Hertz>, 137 pub hrtim: Option<Hertz>,
99 138
100 #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))] 139 #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
101 /// Set only if the lsi or lse is configured, indicates stop is supported 140 /// Set only if the lsi or lse is configured, indicates stop is supported
102 pub rtc: Option<Hertz>, 141 pub rtc: Option<Hertz>,
103 142
104 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 143 #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
105 /// Set if the hse is configured, indicates stop is not supported 144 /// Set if the hse is configured, indicates stop is not supported
106 pub rtc_hse: Option<Hertz>, 145 pub rtc_hse: Option<Hertz>,
107} 146}
diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs
index 6643d278a..937f55503 100644
--- a/embassy-stm32/src/rcc/wl.rs
+++ b/embassy-stm32/src/rcc/wl.rs
@@ -261,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) {
261 w.set_msirange(range.into()); 261 w.set_msirange(range.into());
262 w.set_msion(true); 262 w.set_msion(true);
263 263
264 if let RtcClockSource::LSE = config.rtc_mux { 264 if config.rtc_mux == RtcClockSource::LSE {
265 // If LSE is enabled, enable calibration of MSI 265 // If LSE is enabled, enable calibration of MSI
266 w.set_msipllen(true); 266 w.set_msipllen(true);
267 } else { 267 } else {
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 73b78f253..28dde2eb1 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -93,21 +93,50 @@ impl RtcTimeProvider {
93 /// 93 ///
94 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. 94 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
95 pub fn now(&self) -> Result<DateTime, RtcError> { 95 pub fn now(&self) -> Result<DateTime, RtcError> {
96 let r = RTC::regs(); 96 // For RM0433 we use BYPSHAD=1 to work around errata ES0392 2.19.1
97 let tr = r.tr().read(); 97 #[cfg(rcc_h7rm0433)]
98 let second = bcd2_to_byte((tr.st(), tr.su())); 98 loop {
99 let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); 99 let r = RTC::regs();
100 let hour = bcd2_to_byte((tr.ht(), tr.hu())); 100 let ss = r.ssr().read().ss();
101 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order 101 let dr = r.dr().read();
102 // calendar shadow registers until RTC_DR is read. 102 let tr = r.tr().read();
103 let dr = r.dr().read(); 103
104 104 // If an RTCCLK edge occurs during read we may see inconsistent values
105 let weekday = dr.wdu(); 105 // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9)
106 let day = bcd2_to_byte((dr.dt(), dr.du())); 106 let ss_after = r.ssr().read().ss();
107 let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); 107 if ss == ss_after {
108 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; 108 let second = bcd2_to_byte((tr.st(), tr.su()));
109 109 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
110 self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) 110 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
111
112 let weekday = dr.wdu();
113 let day = bcd2_to_byte((dr.dt(), dr.du()));
114 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
115 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
116
117 return self::datetime::datetime(year, month, day, weekday, hour, minute, second)
118 .map_err(RtcError::InvalidDateTime);
119 }
120 }
121
122 #[cfg(not(rcc_h7rm0433))]
123 {
124 let r = RTC::regs();
125 let tr = r.tr().read();
126 let second = bcd2_to_byte((tr.st(), tr.su()));
127 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
128 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
129 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order
130 // calendar shadow registers until RTC_DR is read.
131 let dr = r.dr().read();
132
133 let weekday = dr.wdu();
134 let day = bcd2_to_byte((dr.dt(), dr.du()));
135 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
136 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
137
138 self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
139 }
111 } 140 }
112} 141}
113 142
@@ -175,18 +204,18 @@ impl Rtc {
175 } 204 }
176 205
177 fn frequency() -> Hertz { 206 fn frequency() -> Hertz {
178 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 207 #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
179 let freqs = unsafe { crate::rcc::get_freqs() }; 208 let freqs = unsafe { crate::rcc::get_freqs() };
180 209
181 // Load the clock frequency from the rcc mod, if supported 210 // Load the clock frequency from the rcc mod, if supported
182 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 211 #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
183 match freqs.rtc { 212 match freqs.rtc {
184 Some(hertz) => hertz, 213 Some(hertz) => hertz,
185 None => freqs.rtc_hse.unwrap(), 214 None => freqs.rtc_hse.unwrap(),
186 } 215 }
187 216
188 // Assume the default value, if not supported 217 // Assume the default value, if not supported
189 #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] 218 #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab)))]
190 Hertz(32_768) 219 Hertz(32_768)
191 } 220 }
192 221
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 4974f6ee6..eeb23e1f1 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -157,6 +157,8 @@ impl super::Rtc {
157 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); 157 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
158 w.set_osel(Osel::DISABLED); 158 w.set_osel(Osel::DISABLED);
159 w.set_pol(Pol::HIGH); 159 w.set_pol(Pol::HIGH);
160 #[cfg(rcc_h7rm0433)]
161 w.set_bypshad(true);
160 }); 162 });
161 163
162 rtc.prer().modify(|w| { 164 rtc.prer().modify(|w| {
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 3a3927a9a..7bcdf2b3e 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits", "chrono"] }
10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
@@ -32,6 +32,7 @@ micromath = "2.0.0"
32stm32-fmc = "0.3.0" 32stm32-fmc = "0.3.0"
33embedded-storage = "0.3.0" 33embedded-storage = "0.3.0"
34static_cell = { version = "1.1", features = ["nightly"]} 34static_cell = { version = "1.1", features = ["nightly"]}
35chrono = { version = "^0.4", default-features = false }
35 36
36# cargo build/run 37# cargo build/run
37[profile.dev] 38[profile.dev]
diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs
new file mode 100644
index 000000000..eeb94073b
--- /dev/null
+++ b/examples/stm32h7/src/bin/rtc.rs
@@ -0,0 +1,39 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::rcc::Lse;
9use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig};
10use embassy_stm32::Config;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = {
17 let mut config = Config::default();
18 config.rcc.lse = Some(Lse::Oscillator);
19 config.rcc.rtc_mux = Some(RtcClockSource::LSE);
20 embassy_stm32::init(config)
21 };
22 info!("Hello World!");
23
24 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
25 .unwrap()
26 .and_hms_opt(10, 30, 15)
27 .unwrap();
28
29 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
30 info!("Got RTC! {:?}", now.timestamp());
31
32 rtc.set_datetime(now.into()).expect("datetime not set");
33
34 // In reality the delay would be much longer
35 Timer::after(Duration::from_millis(20000)).await;
36
37 let then: NaiveDateTime = rtc.now().unwrap().into();
38 info!("Got RTC! {:?}", then.timestamp());
39}