diff options
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/bd.rs | 47 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f4.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h.rs | 57 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l4.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 59 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/wl.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/mod.rs | 65 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/v2.rs | 2 | ||||
| -rw-r--r-- | examples/stm32h7/Cargo.toml | 3 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/rtc.rs | 39 |
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" | |||
| 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 60 | critical-section = "1.1" | 60 | critical-section = "1.1" |
| 61 | atomic-polyfill = "1.0.1" | 61 | atomic-polyfill = "1.0.1" |
| 62 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-172c5ea18824d7cd38decb210e4af441fa3816cb" } | 62 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f0f06b4c95bd9e185e4aa5f2e1d4b76ba84f1594" } |
| 63 | vcell = "0.1.3" | 63 | vcell = "0.1.3" |
| 64 | bxcan = "0.7.0" | 64 | bxcan = "0.7.0" |
| 65 | nb = "1.0.0" | 65 | nb = "1.0.0" |
| @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 78 | [build-dependencies] | 78 | [build-dependencies] |
| 79 | proc-macro2 = "1.0.36" | 79 | proc-macro2 = "1.0.36" |
| 80 | quote = "1.0.15" | 80 | quote = "1.0.15" |
| 81 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-172c5ea18824d7cd38decb210e4af441fa3816cb", default-features = false, features = ["metadata"]} | 81 | stm32-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 {} | |||
| 564 | foreach_peripheral!( | 564 | foreach_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)] | ||
| 3 | pub enum LseCfg { | ||
| 4 | Oscillator(LseDrive), | ||
| 5 | Bypass, | ||
| 6 | } | ||
| 7 | |||
| 8 | impl 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)] |
| 3 | pub enum LseDrive { | 16 | pub 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)))] | ||
| 14 | impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { | 26 | impl 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; | |||
| 9 | pub use crate::pac::rcc::vals::Ckpersel as PerClockSource; | 9 | pub use crate::pac::rcc::vals::Ckpersel as PerClockSource; |
| 10 | use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; | 10 | use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; |
| 11 | use crate::pac::{FLASH, PWR, RCC}; | 11 | use crate::pac::{FLASH, PWR, RCC}; |
| 12 | #[cfg(stm32h7)] | ||
| 13 | use crate::rcc::bd::{BackupDomain, LseCfg, RtcClockSource}; | ||
| 12 | use crate::rcc::{set_freqs, Clocks}; | 14 | use crate::rcc::{set_freqs, Clocks}; |
| 13 | use crate::time::Hertz; | 15 | use crate::time::Hertz; |
| 14 | 16 | ||
| @@ -46,9 +48,9 @@ pub enum VoltageScale { | |||
| 46 | pub enum HseMode { | 48 | pub 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)] | ||
| 68 | pub 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)] |
| 65 | pub enum Hsi { | 76 | pub enum Hsi { |
| 66 | /// 64Mhz | 77 | /// 64Mhz |
| @@ -157,6 +168,10 @@ impl From<TimerPrescaler> for Timpre { | |||
| 157 | pub struct Config { | 168 | pub 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 | ||
| 186 | impl Default for Config { | 203 | impl 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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits", "chrono"] } |
| 10 | embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | 12 | embassy-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" | |||
| 32 | stm32-fmc = "0.3.0" | 32 | stm32-fmc = "0.3.0" |
| 33 | embedded-storage = "0.3.0" | 33 | embedded-storage = "0.3.0" |
| 34 | static_cell = { version = "1.1", features = ["nightly"]} | 34 | static_cell = { version = "1.1", features = ["nightly"]} |
| 35 | chrono = { 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 | |||
| 5 | use chrono::{NaiveDate, NaiveDateTime}; | ||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_stm32::rcc::Lse; | ||
| 9 | use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; | ||
| 10 | use embassy_stm32::Config; | ||
| 11 | use embassy_time::{Duration, Timer}; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async 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 | } | ||
