Merge pull request #2012 from mattico/h7-rtc
H7: support LSE, LSI, LSEBYP, and RTCCLKSEL
This commit is contained in:
commit
f30fc949ff
2
ci.sh
2
ci.sh
@ -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
|
||||||
|
@ -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]
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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| {
|
||||||
|
@ -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]
|
||||||
|
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());
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user