Merge pull request #2012 from mattico/h7-rtc

H7: support LSE, LSI, LSEBYP, and RTCCLKSEL
This commit is contained in:
Dario Nieuwenhuis 2023-10-06 21:27:04 +00:00 committed by GitHub
commit f30fc949ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 246 additions and 57 deletions

2
ci.sh
View File

@ -203,7 +203,7 @@ cargo batch \
rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_mac
rm out/tests/stm32wb55rg/wpan_ble rm out/tests/stm32wb55rg/wpan_ble
rm out/tests/stm32f207zg/eth
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
echo No teleprobe token found, skipping running HIL tests echo No teleprobe token found, skipping running HIL tests

View File

@ -59,7 +59,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
atomic-polyfill = "1.0.1" atomic-polyfill = "1.0.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-172c5ea18824d7cd38decb210e4af441fa3816cb" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f0f06b4c95bd9e185e4aa5f2e1d4b76ba84f1594" }
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-172c5ea18824d7cd38decb210e4af441fa3816cb", default-features = false, features = ["metadata"]} stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f0f06b4c95bd9e185e4aa5f2e1d4b76ba84f1594", default-features = false, features = ["metadata"]}
[features] [features]

View File

@ -564,7 +564,7 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
foreach_peripheral!( foreach_peripheral!(
(dac, $inst:ident) => { (dac, $inst:ident) => {
// H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
#[cfg(rcc_h7)] #[cfg(any(rcc_h7, rcc_h7rm0433))]
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz { fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 }) critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
@ -590,7 +590,7 @@ foreach_peripheral!(
} }
} }
#[cfg(rcc_h7)] #[cfg(any(rcc_h7, rcc_h7rm0433))]
impl crate::rcc::RccPeripheral for peripherals::$inst {} impl crate::rcc::RccPeripheral for peripherals::$inst {}
impl crate::dac::sealed::Instance for peripherals::$inst { impl crate::dac::sealed::Instance for peripherals::$inst {

View File

@ -1,26 +1,36 @@
#[allow(dead_code)]
#[derive(Clone, Copy)]
pub enum LseCfg {
Oscillator(LseDrive),
Bypass,
}
impl Default for LseCfg {
fn default() -> Self {
Self::Oscillator(Default::default())
}
}
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy)]
pub enum LseDrive { pub enum LseDrive {
#[cfg(any(rtc_v2f7, rtc_v2l4))]
Low = 0, Low = 0,
MediumLow = 0x01, MediumLow = 0x01,
#[default] #[default]
MediumHigh = 0x02, MediumHigh = 0x02,
#[cfg(any(rtc_v2f7, rtc_v2l4))]
High = 0x03, High = 0x03,
} }
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] // All families but these have the LSEDRV register
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
fn from(value: LseDrive) -> Self { fn from(value: LseDrive) -> Self {
use crate::pac::rcc::vals::Lsedrv; use crate::pac::rcc::vals::Lsedrv;
match value { match value {
#[cfg(any(rtc_v2f7, rtc_v2l4))]
LseDrive::Low => Lsedrv::LOW, LseDrive::Low => Lsedrv::LOW,
LseDrive::MediumLow => Lsedrv::MEDIUMLOW, LseDrive::MediumLow => Lsedrv::MEDIUMLOW,
LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH,
#[cfg(any(rtc_v2f7, rtc_v2l4))]
LseDrive::High => Lsedrv::HIGH, LseDrive::High => Lsedrv::HIGH,
} }
} }
@ -87,14 +97,19 @@ impl BackupDomain {
rtc_v3u5 rtc_v3u5
))] ))]
#[allow(dead_code, unused_variables)] #[allow(dead_code, unused_variables)]
pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseDrive>) { pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseCfg>) {
use atomic_polyfill::{compiler_fence, Ordering}; use atomic_polyfill::{compiler_fence, Ordering};
match clock_source { match clock_source {
RtcClockSource::LSI => assert!(lsi), RtcClockSource::LSI => assert!(lsi),
RtcClockSource::LSE => assert!(&lse.is_some()), RtcClockSource::LSE => assert!(lse.is_some()),
_ => {} _ => {}
}; };
let (lse_en, lse_byp, lse_drv) = match lse {
Some(LseCfg::Oscillator(lse_drv)) => (true, false, Some(lse_drv)),
Some(LseCfg::Bypass) => (true, true, None),
None => (false, false, None),
};
if lsi { if lsi {
#[cfg(rtc_v3u5)] #[cfg(rtc_v3u5)]
@ -131,10 +146,11 @@ impl BackupDomain {
{ {
ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK); ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK);
} }
ok &= reg.lseon() == lse.is_some(); ok &= reg.lseon() == lse_en;
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] ok &= reg.lsebyp() == lse_byp;
if let Some(lse_drive) = lse { #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
ok &= reg.lsedrv() == lse_drive.into(); if let Some(lse_drv) = lse_drv {
ok &= reg.lsedrv() == lse_drv.into();
} }
// if configuration is OK, we're done. // if configuration is OK, we're done.
@ -153,10 +169,13 @@ impl BackupDomain {
Self::modify(|w| w.set_bdrst(false)); Self::modify(|w| w.set_bdrst(false));
} }
if let Some(lse_drive) = lse { if lse_en {
Self::modify(|w| { Self::modify(|w| {
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
w.set_lsedrv(lse_drive.into()); if let Some(lse_drv) = lse_drv {
w.set_lsedrv(lse_drv.into());
}
w.set_lsebyp(lse_byp);
w.set_lseon(true); w.set_lseon(true);
}); });

View File

@ -540,7 +540,7 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pllsai: plls.pllsaiclk.map(Hertz), pllsai: plls.pllsaiclk.map(Hertz),
rtc: rtc, rtc,
rtc_hse: None, rtc_hse: None,
}); });
} }

View File

@ -9,6 +9,8 @@ pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
pub use crate::pac::rcc::vals::Ckpersel as PerClockSource; pub use crate::pac::rcc::vals::Ckpersel as PerClockSource;
use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
#[cfg(stm32h7)]
use crate::rcc::bd::{BackupDomain, LseCfg, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -46,9 +48,9 @@ pub enum VoltageScale {
pub enum HseMode { pub enum HseMode {
/// crystal/ceramic oscillator (HSEBYP=0) /// crystal/ceramic oscillator (HSEBYP=0)
Oscillator, Oscillator,
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
Bypass, Bypass,
/// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
#[cfg(any(rcc_h5, rcc_h50))] #[cfg(any(rcc_h5, rcc_h50))]
BypassDigital, BypassDigital,
} }
@ -61,6 +63,15 @@ pub struct Hse {
pub mode: HseMode, pub mode: HseMode,
} }
#[cfg(stm32h7)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Lse {
/// 32.768 kHz crystal/ceramic oscillator (LSEBYP=0)
Oscillator,
/// external clock input up to 1MHz (LSEBYP=1)
Bypass(Hertz),
}
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
pub enum Hsi { pub enum Hsi {
/// 64Mhz /// 64Mhz
@ -157,6 +168,10 @@ impl From<TimerPrescaler> for Timpre {
pub struct Config { pub struct Config {
pub hsi: Option<Hsi>, pub hsi: Option<Hsi>,
pub hse: Option<Hse>, pub hse: Option<Hse>,
#[cfg(stm32h7)]
pub lse: Option<Lse>,
#[cfg(stm32h7)]
pub lsi: bool,
pub csi: bool, pub csi: bool,
pub hsi48: bool, pub hsi48: bool,
pub sys: Sysclk, pub sys: Sysclk,
@ -181,6 +196,8 @@ pub struct Config {
pub adc_clock_source: AdcClockSource, pub adc_clock_source: AdcClockSource,
pub timer_prescaler: TimerPrescaler, pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale, pub voltage_scale: VoltageScale,
#[cfg(stm32h7)]
pub rtc_mux: Option<RtcClockSource>,
} }
impl Default for Config { impl Default for Config {
@ -188,6 +205,10 @@ impl Default for Config {
Self { Self {
hsi: Some(Hsi::Mhz64), hsi: Some(Hsi::Mhz64),
hse: None, hse: None,
#[cfg(stm32h7)]
lse: None,
#[cfg(stm32h7)]
lsi: false,
csi: false, csi: false,
hsi48: false, hsi48: false,
sys: Sysclk::HSI, sys: Sysclk::HSI,
@ -210,6 +231,8 @@ impl Default for Config {
adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5 adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5
timer_prescaler: TimerPrescaler::DefaultX2, timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale0, voltage_scale: VoltageScale::Scale0,
#[cfg(stm32h7)]
rtc_mux: None,
} }
} }
} }
@ -448,6 +471,19 @@ pub(crate) unsafe fn init(config: Config) {
flash_setup(hclk, config.voltage_scale); flash_setup(hclk, config.voltage_scale);
#[cfg(stm32h7)]
{
let lsecfg = config.lse.map(|lse| match lse {
Lse::Bypass(freq) => {
assert!(freq <= Hertz(1_000_000));
LseCfg::Bypass
}
Lse::Oscillator => LseCfg::Oscillator(Default::default()),
});
BackupDomain::configure_ls(config.rtc_mux.unwrap_or(RtcClockSource::NOCLOCK), config.lsi, lsecfg);
}
#[cfg(stm32h7)] #[cfg(stm32h7)]
{ {
RCC.d1cfgr().modify(|w| { RCC.d1cfgr().modify(|w| {
@ -512,6 +548,17 @@ pub(crate) unsafe fn init(config: Config) {
while !pac::SYSCFG.cccsr().read().ready() {} while !pac::SYSCFG.cccsr().read().ready() {}
} }
#[cfg(stm32h7)]
let rtc_clk = match config.rtc_mux {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(match config.lse {
Some(Lse::Oscillator) => Hertz(32768),
Some(Lse::Bypass(freq)) => freq,
None => panic!("LSE not configured"),
}),
_ => None,
};
set_freqs(Clocks { set_freqs(Clocks {
sys, sys,
ahb1: hclk, ahb1: hclk,
@ -525,7 +572,11 @@ pub(crate) unsafe fn init(config: Config) {
apb4, apb4,
apb1_tim, apb1_tim,
apb2_tim, apb2_tim,
adc: adc, adc,
#[cfg(stm32h7)]
rtc: rtc_clk,
#[cfg(stm32h7)]
rtc_hse: None,
}); });
} }

View File

@ -420,7 +420,7 @@ pub(crate) unsafe fn init(config: Config) {
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
if let RtcClockSource::LSE = config.rtc_mux { if config.rtc_mux == RtcClockSource::LSE {
// If LSE is enabled, enable calibration of MSI // If LSE is enabled, enable calibration of MSI
w.set_msipllen(true); w.set_msipllen(true);
} else { } else {

View File

@ -21,7 +21,7 @@ pub use mco::*;
#[cfg_attr(rcc_c0, path = "c0.rs")] #[cfg_attr(rcc_c0, path = "c0.rs")]
#[cfg_attr(rcc_g0, path = "g0.rs")] #[cfg_attr(rcc_g0, path = "g0.rs")]
#[cfg_attr(rcc_g4, path = "g4.rs")] #[cfg_attr(rcc_g4, path = "g4.rs")]
#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")] #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")]
#[cfg_attr(rcc_l0, path = "l0.rs")] #[cfg_attr(rcc_l0, path = "l0.rs")]
#[cfg_attr(rcc_l1, path = "l1.rs")] #[cfg_attr(rcc_l1, path = "l1.rs")]
#[cfg_attr(rcc_l4, path = "l4.rs")] #[cfg_attr(rcc_l4, path = "l4.rs")]
@ -57,9 +57,9 @@ pub struct Clocks {
pub apb2: Hertz, pub apb2: Hertz,
#[cfg(not(any(rcc_c0, rcc_g0)))] #[cfg(not(any(rcc_c0, rcc_g0)))]
pub apb2_tim: Hertz, pub apb2_tim: Hertz,
#[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))] #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))]
pub apb3: Hertz, pub apb3: Hertz,
#[cfg(any(rcc_h7, rcc_h7ab))] #[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab))]
pub apb4: Hertz, pub apb4: Hertz,
#[cfg(any(rcc_wba))] #[cfg(any(rcc_wba))]
pub apb7: Hertz, pub apb7: Hertz,
@ -67,16 +67,44 @@ pub struct Clocks {
// AHB // AHB
pub ahb1: Hertz, pub ahb1: Hertz,
#[cfg(any( #[cfg(any(
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, rcc_l4,
rcc_wba, rcc_wl5, rcc_wle rcc_l5,
rcc_f2,
rcc_f4,
rcc_f410,
rcc_f7,
rcc_h5,
rcc_h50,
rcc_h7,
rcc_h7rm0433,
rcc_h7ab,
rcc_g4,
rcc_u5,
rcc_wb,
rcc_wba,
rcc_wl5,
rcc_wle
))] ))]
pub ahb2: Hertz, pub ahb2: Hertz,
#[cfg(any( #[cfg(any(
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, rcc_l4,
rcc_l5,
rcc_f2,
rcc_f4,
rcc_f410,
rcc_f7,
rcc_h5,
rcc_h50,
rcc_h7,
rcc_h7rm0433,
rcc_h7ab,
rcc_u5,
rcc_wb,
rcc_wl5,
rcc_wle rcc_wle
))] ))]
pub ahb3: Hertz, pub ahb3: Hertz,
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))] #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))]
pub ahb4: Hertz, pub ahb4: Hertz,
#[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
@ -88,7 +116,18 @@ pub struct Clocks {
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pub pllsai: Option<Hertz>, pub pllsai: Option<Hertz>,
#[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))] #[cfg(any(
rcc_f1,
rcc_f100,
rcc_f1cl,
rcc_h5,
rcc_h50,
rcc_h7,
rcc_h7rm0433,
rcc_h7ab,
rcc_f3,
rcc_g4
))]
pub adc: Option<Hertz>, pub adc: Option<Hertz>,
#[cfg(any(rcc_f3, rcc_g4))] #[cfg(any(rcc_f3, rcc_g4))]
@ -97,11 +136,11 @@ pub struct Clocks {
#[cfg(stm32f334)] #[cfg(stm32f334)]
pub hrtim: Option<Hertz>, pub hrtim: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))] #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
/// Set only if the lsi or lse is configured, indicates stop is supported /// Set only if the lsi or lse is configured, indicates stop is supported
pub rtc: Option<Hertz>, pub rtc: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))] #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
/// Set if the hse is configured, indicates stop is not supported /// Set if the hse is configured, indicates stop is not supported
pub rtc_hse: Option<Hertz>, pub rtc_hse: Option<Hertz>,
} }

View File

@ -261,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) {
w.set_msirange(range.into()); w.set_msirange(range.into());
w.set_msion(true); w.set_msion(true);
if let RtcClockSource::LSE = config.rtc_mux { if config.rtc_mux == RtcClockSource::LSE {
// If LSE is enabled, enable calibration of MSI // If LSE is enabled, enable calibration of MSI
w.set_msipllen(true); w.set_msipllen(true);
} else { } else {

View File

@ -93,21 +93,50 @@ impl RtcTimeProvider {
/// ///
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
pub fn now(&self) -> Result<DateTime, RtcError> { pub fn now(&self) -> Result<DateTime, RtcError> {
let r = RTC::regs(); // For RM0433 we use BYPSHAD=1 to work around errata ES0392 2.19.1
let tr = r.tr().read(); #[cfg(rcc_h7rm0433)]
let second = bcd2_to_byte((tr.st(), tr.su())); loop {
let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); let r = RTC::regs();
let hour = bcd2_to_byte((tr.ht(), tr.hu())); let ss = r.ssr().read().ss();
// Reading either RTC_SSR or RTC_TR locks the values in the higher-order let dr = r.dr().read();
// calendar shadow registers until RTC_DR is read. let tr = r.tr().read();
let dr = r.dr().read();
let weekday = dr.wdu(); // If an RTCCLK edge occurs during read we may see inconsistent values
let day = bcd2_to_byte((dr.dt(), dr.du())); // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9)
let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); let ss_after = r.ssr().read().ss();
let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; 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()));
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) 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 self::datetime::datetime(year, month, day, weekday, hour, minute, second)
.map_err(RtcError::InvalidDateTime);
}
}
#[cfg(not(rcc_h7rm0433))]
{
let r = RTC::regs();
let tr = r.tr().read();
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()));
let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
}
} }
} }
@ -175,18 +204,18 @@ impl Rtc {
} }
fn frequency() -> Hertz { fn frequency() -> Hertz {
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))] #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
let freqs = unsafe { crate::rcc::get_freqs() }; let freqs = unsafe { crate::rcc::get_freqs() };
// Load the clock frequency from the rcc mod, if supported // Load the clock frequency from the rcc mod, if supported
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))] #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
match freqs.rtc { match freqs.rtc {
Some(hertz) => hertz, Some(hertz) => hertz,
None => freqs.rtc_hse.unwrap(), None => freqs.rtc_hse.unwrap(),
} }
// Assume the default value, if not supported // Assume the default value, if not supported
#[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab)))]
Hertz(32_768) Hertz(32_768)
} }

View File

@ -157,6 +157,8 @@ impl super::Rtc {
w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
w.set_osel(Osel::DISABLED); w.set_osel(Osel::DISABLED);
w.set_pol(Pol::HIGH); w.set_pol(Pol::HIGH);
#[cfg(rcc_h7rm0433)]
w.set_bypshad(true);
}); });
rtc.prer().modify(|w| { rtc.prer().modify(|w| {

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
# Change stm32h743bi to your chip name, if necessary. # Change stm32h743bi to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits", "chrono"] }
embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 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"
stm32-fmc = "0.3.0" stm32-fmc = "0.3.0"
embedded-storage = "0.3.0" embedded-storage = "0.3.0"
static_cell = { version = "1.1", features = ["nightly"]} static_cell = { version = "1.1", features = ["nightly"]}
chrono = { version = "^0.4", default-features = false }
# cargo build/run # cargo build/run
[profile.dev] [profile.dev]

View File

@ -0,0 +1,39 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use chrono::{NaiveDate, NaiveDateTime};
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::rcc::Lse;
use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig};
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.lse = Some(Lse::Oscillator);
config.rcc.rtc_mux = Some(RtcClockSource::LSE);
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());
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());
}

View File

@ -11,7 +11,7 @@ stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not
stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # Nucleo stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # Nucleo
stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma", "eth", "dac-adc-pin"] # Nucleo stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac-adc-pin"] # Nucleo
stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo
stm32h563zi = ["embassy-stm32/stm32h563zi", "eth"] # Nucleo stm32h563zi = ["embassy-stm32/stm32h563zi", "eth"] # Nucleo
stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board

View File

@ -12,15 +12,24 @@ use defmt::assert;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::RtcClockSource; use embassy_stm32::rcc::RtcClockSource;
use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig};
use embassy_stm32::time::Hertz;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = config(); let mut config = config();
config.rcc.lse = Some(Hertz(32_768)); #[cfg(feature = "stm32h755zi")]
config.rcc.rtc = Some(RtcClockSource::LSE); {
use embassy_stm32::rcc::Lse;
config.rcc.lse = Some(Lse::Oscillator);
config.rcc.rtc_mux = Some(RtcClockSource::LSE);
}
#[cfg(not(feature = "stm32h755zi"))]
{
use embassy_stm32::time::Hertz;
config.rcc.lse = Some(Hertz(32_768));
config.rcc.rtc = Some(RtcClockSource::LSE);
}
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");
@ -40,7 +49,7 @@ async fn main(_spawner: Spawner) {
let then: NaiveDateTime = rtc.now().unwrap().into(); let then: NaiveDateTime = rtc.now().unwrap().into();
let seconds = (then - now).num_seconds(); let seconds = (then - now).num_seconds();
defmt::info!("measured = {}", seconds); info!("measured = {}", seconds);
assert!(seconds > 3 && seconds < 7); assert!(seconds > 3 && seconds < 7);