mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 16:23:10 +00:00
h7: implement RTC and LSE clock configuration
This commit is contained in:
parent
65ed19aae2
commit
f01609036f
@ -59,7 +59,7 @@ sdio-host = "0.5.0"
|
||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||
critical-section = "1.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"
|
||||
bxcan = "0.7.0"
|
||||
nb = "1.0.0"
|
||||
@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
||||
[build-dependencies]
|
||||
proc-macro2 = "1.0.36"
|
||||
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]
|
||||
|
@ -564,7 +564,7 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
||||
foreach_peripheral!(
|
||||
(dac, $inst:ident) => {
|
||||
// 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 {
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
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::dac::sealed::Instance for peripherals::$inst {
|
||||
|
@ -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)]
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub enum LseDrive {
|
||||
#[cfg(any(rtc_v2f7, rtc_v2l4))]
|
||||
Low = 0,
|
||||
MediumLow = 0x01,
|
||||
#[default]
|
||||
MediumHigh = 0x02,
|
||||
#[cfg(any(rtc_v2f7, rtc_v2l4))]
|
||||
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 {
|
||||
fn from(value: LseDrive) -> Self {
|
||||
use crate::pac::rcc::vals::Lsedrv;
|
||||
|
||||
match value {
|
||||
#[cfg(any(rtc_v2f7, rtc_v2l4))]
|
||||
LseDrive::Low => Lsedrv::LOW,
|
||||
LseDrive::MediumLow => Lsedrv::MEDIUMLOW,
|
||||
LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH,
|
||||
#[cfg(any(rtc_v2f7, rtc_v2l4))]
|
||||
LseDrive::High => Lsedrv::HIGH,
|
||||
}
|
||||
}
|
||||
@ -87,14 +97,19 @@ impl BackupDomain {
|
||||
rtc_v3u5
|
||||
))]
|
||||
#[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};
|
||||
|
||||
match clock_source {
|
||||
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 {
|
||||
#[cfg(rtc_v3u5)]
|
||||
@ -131,10 +146,11 @@ impl BackupDomain {
|
||||
{
|
||||
ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK);
|
||||
}
|
||||
ok &= reg.lseon() == lse.is_some();
|
||||
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
|
||||
if let Some(lse_drive) = lse {
|
||||
ok &= reg.lsedrv() == lse_drive.into();
|
||||
ok &= reg.lseon() == lse_en;
|
||||
ok &= reg.lsebyp() == lse_byp;
|
||||
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
|
||||
if let Some(lse_drv) = lse_drv {
|
||||
ok &= reg.lsedrv() == lse_drv.into();
|
||||
}
|
||||
|
||||
// if configuration is OK, we're done.
|
||||
@ -153,10 +169,13 @@ impl BackupDomain {
|
||||
Self::modify(|w| w.set_bdrst(false));
|
||||
}
|
||||
|
||||
if let Some(lse_drive) = lse {
|
||||
if lse_en {
|
||||
Self::modify(|w| {
|
||||
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
|
||||
w.set_lsedrv(lse_drive.into());
|
||||
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
|
||||
if let Some(lse_drv) = lse_drv {
|
||||
w.set_lsedrv(lse_drv.into());
|
||||
}
|
||||
w.set_lsebyp(lse_byp);
|
||||
w.set_lseon(true);
|
||||
});
|
||||
|
||||
|
@ -540,7 +540,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pllsai: plls.pllsaiclk.map(Hertz),
|
||||
|
||||
rtc: rtc,
|
||||
rtc,
|
||||
rtc_hse: None,
|
||||
});
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
|
||||
pub use crate::pac::rcc::vals::Ckpersel as PerClockSource;
|
||||
use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
|
||||
use crate::pac::{FLASH, PWR, RCC};
|
||||
#[cfg(stm32h7)]
|
||||
use crate::rcc::bd::{BackupDomain, LseCfg, RtcClockSource};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
@ -46,9 +48,9 @@ pub enum VoltageScale {
|
||||
pub enum HseMode {
|
||||
/// crystal/ceramic oscillator (HSEBYP=0)
|
||||
Oscillator,
|
||||
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
|
||||
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
|
||||
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))]
|
||||
BypassDigital,
|
||||
}
|
||||
@ -61,6 +63,15 @@ pub struct Hse {
|
||||
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)]
|
||||
pub enum Hsi {
|
||||
/// 64Mhz
|
||||
@ -157,6 +168,10 @@ impl From<TimerPrescaler> for Timpre {
|
||||
pub struct Config {
|
||||
pub hsi: Option<Hsi>,
|
||||
pub hse: Option<Hse>,
|
||||
#[cfg(stm32h7)]
|
||||
pub lse: Option<Lse>,
|
||||
#[cfg(stm32h7)]
|
||||
pub lsi: bool,
|
||||
pub csi: bool,
|
||||
pub hsi48: bool,
|
||||
pub sys: Sysclk,
|
||||
@ -181,6 +196,8 @@ pub struct Config {
|
||||
pub adc_clock_source: AdcClockSource,
|
||||
pub timer_prescaler: TimerPrescaler,
|
||||
pub voltage_scale: VoltageScale,
|
||||
#[cfg(stm32h7)]
|
||||
pub rtc_mux: Option<RtcClockSource>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@ -188,6 +205,10 @@ impl Default for Config {
|
||||
Self {
|
||||
hsi: Some(Hsi::Mhz64),
|
||||
hse: None,
|
||||
#[cfg(stm32h7)]
|
||||
lse: None,
|
||||
#[cfg(stm32h7)]
|
||||
lsi: false,
|
||||
csi: false,
|
||||
hsi48: false,
|
||||
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
|
||||
timer_prescaler: TimerPrescaler::DefaultX2,
|
||||
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);
|
||||
|
||||
#[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)]
|
||||
{
|
||||
RCC.d1cfgr().modify(|w| {
|
||||
@ -512,6 +548,17 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
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 {
|
||||
sys,
|
||||
ahb1: hclk,
|
||||
@ -525,7 +572,11 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
apb4,
|
||||
apb1_tim,
|
||||
apb2_tim,
|
||||
adc: adc,
|
||||
adc,
|
||||
#[cfg(stm32h7)]
|
||||
rtc: rtc_clk,
|
||||
#[cfg(stm32h7)]
|
||||
rtc_hse: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -420,7 +420,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
w.set_msirgsel(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
|
||||
w.set_msipllen(true);
|
||||
} else {
|
||||
|
@ -21,7 +21,7 @@ pub use mco::*;
|
||||
#[cfg_attr(rcc_c0, path = "c0.rs")]
|
||||
#[cfg_attr(rcc_g0, path = "g0.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_l1, path = "l1.rs")]
|
||||
#[cfg_attr(rcc_l4, path = "l4.rs")]
|
||||
@ -57,9 +57,9 @@ pub struct Clocks {
|
||||
pub apb2: Hertz,
|
||||
#[cfg(not(any(rcc_c0, rcc_g0)))]
|
||||
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,
|
||||
#[cfg(any(rcc_h7, rcc_h7ab))]
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab))]
|
||||
pub apb4: Hertz,
|
||||
#[cfg(any(rcc_wba))]
|
||||
pub apb7: Hertz,
|
||||
@ -67,16 +67,44 @@ pub struct Clocks {
|
||||
// AHB
|
||||
pub ahb1: Hertz,
|
||||
#[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_wba, rcc_wl5, rcc_wle
|
||||
rcc_l4,
|
||||
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,
|
||||
#[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
|
||||
))]
|
||||
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,
|
||||
|
||||
#[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))]
|
||||
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>,
|
||||
|
||||
#[cfg(any(rcc_f3, rcc_g4))]
|
||||
@ -97,11 +136,11 @@ pub struct Clocks {
|
||||
#[cfg(stm32f334)]
|
||||
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
|
||||
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
|
||||
pub rtc_hse: Option<Hertz>,
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
w.set_msirange(range.into());
|
||||
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
|
||||
w.set_msipllen(true);
|
||||
} else {
|
||||
|
@ -93,21 +93,50 @@ impl RtcTimeProvider {
|
||||
///
|
||||
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
|
||||
pub fn now(&self) -> Result<DateTime, RtcError> {
|
||||
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();
|
||||
// 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();
|
||||
|
||||
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;
|
||||
// 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()));
|
||||
|
||||
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 {
|
||||
#[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() };
|
||||
|
||||
// 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 {
|
||||
Some(hertz) => hertz,
|
||||
None => freqs.rtc_hse.unwrap(),
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
@ -157,6 +157,8 @@ impl super::Rtc {
|
||||
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| {
|
||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
# 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-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"] }
|
||||
@ -32,6 +32,7 @@ micromath = "2.0.0"
|
||||
stm32-fmc = "0.3.0"
|
||||
embedded-storage = "0.3.0"
|
||||
static_cell = { version = "1.1", features = ["nightly"]}
|
||||
chrono = { version = "^0.4", default-features = false }
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
|
39
examples/stm32h7/src/bin/rtc.rs
Normal file
39
examples/stm32h7/src/bin/rtc.rs
Normal 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());
|
||||
}
|
Loading…
Reference in New Issue
Block a user