Merge #1376
1376: rtc: cleanup and consolidate r=Dirbaio a=xoviat This removes an extra file that I left in, adds an example, and consolidates the files into one 'v2' file. Co-authored-by: xoviat <xoviat@users.noreply.github.com>
This commit is contained in:
commit
855c0d1423
20 changed files with 253 additions and 536 deletions
|
@ -51,7 +51,7 @@ pub mod pwm;
|
|||
pub mod qspi;
|
||||
#[cfg(rng)]
|
||||
pub mod rng;
|
||||
#[cfg(all(rtc, not(any(rtc_v1, rtc_v2f0, rtc_v2f7, rtc_v3, rtc_v3u5))))]
|
||||
#[cfg(all(rtc, not(rtc_v1)))]
|
||||
pub mod rtc;
|
||||
#[cfg(sdmmc)]
|
||||
pub mod sdmmc;
|
||||
|
|
|
@ -51,7 +51,7 @@ pub struct DateTime {
|
|||
impl From<chrono::NaiveDateTime> for DateTime {
|
||||
fn from(date_time: chrono::NaiveDateTime) -> Self {
|
||||
Self {
|
||||
year: (date_time.year() - 1970) as u16,
|
||||
year: date_time.year() as u16,
|
||||
month: date_time.month() as u8,
|
||||
day: date_time.day() as u8,
|
||||
day_of_week: date_time.weekday().into(),
|
||||
|
@ -65,14 +65,10 @@ impl From<chrono::NaiveDateTime> for DateTime {
|
|||
#[cfg(feature = "chrono")]
|
||||
impl From<DateTime> for chrono::NaiveDateTime {
|
||||
fn from(date_time: DateTime) -> Self {
|
||||
NaiveDate::from_ymd_opt(
|
||||
(date_time.year + 1970) as i32,
|
||||
date_time.month as u32,
|
||||
date_time.day as u32,
|
||||
)
|
||||
.unwrap()
|
||||
.and_hms_opt(date_time.hour as u32, date_time.minute as u32, date_time.second as u32)
|
||||
.unwrap()
|
||||
NaiveDate::from_ymd_opt(date_time.year as i32, date_time.month as u32, date_time.day as u32)
|
||||
.unwrap()
|
||||
.and_hms_opt(date_time.hour as u32, date_time.minute as u32, date_time.second as u32)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,6 +155,8 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) {
|
|||
let (yt, yu) = byte_to_bcd2(yr_offset);
|
||||
|
||||
unsafe {
|
||||
use crate::pac::rtc::vals::Ampm;
|
||||
|
||||
rtc.tr().write(|w| {
|
||||
w.set_ht(ht);
|
||||
w.set_hu(hu);
|
||||
|
@ -166,7 +164,7 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) {
|
|||
w.set_mnu(mnu);
|
||||
w.set_st(st);
|
||||
w.set_su(su);
|
||||
w.set_pm(stm32_metapac::rtc::vals::Ampm::AM);
|
||||
w.set_pm(Ampm::AM);
|
||||
});
|
||||
|
||||
rtc.dr().write(|w| {
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
use chrono::{Datelike, Timelike};
|
||||
|
||||
use super::byte_to_bcd2;
|
||||
use crate::pac::rtc::Rtc;
|
||||
|
||||
/// Alias for [`chrono::NaiveDateTime`]
|
||||
pub type DateTime = chrono::NaiveDateTime;
|
||||
/// Alias for [`chrono::Weekday`]
|
||||
pub type DayOfWeek = chrono::Weekday;
|
||||
|
||||
/// Errors regarding the [`DateTime`] and [`DateTimeFilter`] structs.
|
||||
///
|
||||
/// [`DateTimeFilter`]: struct.DateTimeFilter.html
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
/// The [DateTime] has an invalid year. The year must be between 0 and 4095.
|
||||
InvalidYear,
|
||||
/// The [DateTime] contains an invalid date.
|
||||
InvalidDate,
|
||||
/// The [DateTime] contains an invalid time.
|
||||
InvalidTime,
|
||||
}
|
||||
|
||||
pub(super) fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 {
|
||||
dotw.num_days_from_monday() as u8
|
||||
}
|
||||
|
||||
pub(crate) fn validate_datetime(dt: &DateTime) -> Result<(), Error> {
|
||||
if dt.year() < 0 || dt.year() > 4095 {
|
||||
// rp2040 can't hold these years
|
||||
Err(Error::InvalidYear)
|
||||
} else {
|
||||
// The rest of the chrono date is assumed to be valid
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) {
|
||||
let (ht, hu) = byte_to_bcd2(t.hour() as u8);
|
||||
let (mnt, mnu) = byte_to_bcd2(t.minute() as u8);
|
||||
let (st, su) = byte_to_bcd2(t.second() as u8);
|
||||
|
||||
let (dt, du) = byte_to_bcd2(t.day() as u8);
|
||||
let (mt, mu) = byte_to_bcd2(t.month() as u8);
|
||||
let yr = t.year() as u16;
|
||||
let yr_offset = (yr - 1970_u16) as u8;
|
||||
let (yt, yu) = byte_to_bcd2(yr_offset);
|
||||
|
||||
unsafe {
|
||||
rtc.tr().write(|w| {
|
||||
w.set_ht(ht);
|
||||
w.set_hu(hu);
|
||||
w.set_mnt(mnt);
|
||||
w.set_mnu(mnu);
|
||||
w.set_st(st);
|
||||
w.set_su(su);
|
||||
w.set_pm(stm32_metapac::rtc::vals::Ampm::AM);
|
||||
});
|
||||
|
||||
rtc.dr().write(|w| {
|
||||
w.set_dt(dt);
|
||||
w.set_du(du);
|
||||
w.set_mt(mt > 0);
|
||||
w.set_mu(mu);
|
||||
w.set_yt(yt);
|
||||
w.set_yu(yu);
|
||||
w.set_wdu(day_of_week_to_u8(t.weekday()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn datetime(
|
||||
year: u16,
|
||||
month: u8,
|
||||
day: u8,
|
||||
_day_of_week: u8,
|
||||
hour: u8,
|
||||
minute: u8,
|
||||
second: u8,
|
||||
) -> Result<DateTime, Error> {
|
||||
let date = chrono::NaiveDate::from_ymd_opt(year.into(), month.try_into().unwrap(), day.into())
|
||||
.ok_or(Error::InvalidDate)?;
|
||||
let time = chrono::NaiveTime::from_hms_opt(hour.into(), minute.into(), second.into()).ok_or(Error::InvalidTime)?;
|
||||
Ok(DateTime::new(date, time))
|
||||
}
|
|
@ -10,12 +10,12 @@ pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
|
|||
any(
|
||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
|
||||
),
|
||||
path = "v2/mod.rs"
|
||||
path = "v2.rs"
|
||||
)]
|
||||
#[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")]
|
||||
mod versions;
|
||||
mod _version;
|
||||
pub use _version::*;
|
||||
use embassy_hal_common::Peripheral;
|
||||
pub use versions::*;
|
||||
|
||||
/// Errors that can occur on methods on [RtcClock]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -113,7 +113,7 @@ impl Default for RtcCalibrationCyclePeriod {
|
|||
|
||||
impl<'d, T: Instance> Rtc<'d, T> {
|
||||
pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self {
|
||||
unsafe { enable_peripheral_clk() };
|
||||
unsafe { T::enable_peripheral_clk() };
|
||||
|
||||
let mut rtc_struct = Self {
|
||||
phantom: PhantomData,
|
||||
|
@ -179,14 +179,14 @@ impl<'d, T: Instance> Rtc<'d, T> {
|
|||
self.rtc_config
|
||||
}
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = BACKUP_REGISTER_COUNT;
|
||||
pub const BACKUP_REGISTER_COUNT: usize = T::BACKUP_REGISTER_COUNT;
|
||||
|
||||
/// Read content of the backup register.
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
pub fn read_backup_register(&self, register: usize) -> Option<u32> {
|
||||
read_backup_register(&T::regs(), register)
|
||||
T::read_backup_register(&T::regs(), register)
|
||||
}
|
||||
|
||||
/// Set content of the backup register.
|
||||
|
@ -194,7 +194,7 @@ impl<'d, T: Instance> Rtc<'d, T> {
|
|||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
pub fn write_backup_register(&self, register: usize, value: u32) {
|
||||
write_backup_register(&T::regs(), register, value)
|
||||
T::write_backup_register(&T::regs(), register, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,17 +219,31 @@ pub(crate) fn bcd2_to_byte(bcd: (u8, u8)) -> u8 {
|
|||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use crate::pac::rtc::Rtc;
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> crate::pac::rtc::Rtc;
|
||||
const BACKUP_REGISTER_COUNT: usize;
|
||||
|
||||
fn regs() -> Rtc {
|
||||
crate::pac::RTC
|
||||
}
|
||||
|
||||
unsafe fn enable_peripheral_clk() {}
|
||||
|
||||
/// Read content of the backup register.
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32>;
|
||||
|
||||
/// Set content of the backup register.
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
fn write_backup_register(rtc: &Rtc, register: usize, value: u32);
|
||||
|
||||
// fn apply_config(&mut self, rtc_config: RtcConfig);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance: sealed::Instance + 'static {}
|
||||
|
||||
impl sealed::Instance for crate::peripherals::RTC {
|
||||
fn regs() -> crate::pac::rtc::Rtc {
|
||||
crate::pac::RTC
|
||||
}
|
||||
}
|
||||
|
||||
impl Instance for crate::peripherals::RTC {}
|
||||
|
|
|
@ -1,29 +1,78 @@
|
|||
use stm32_metapac::rtc::vals::{Init, Osel, Pol};
|
||||
|
||||
use super::{Instance, RtcConfig};
|
||||
use super::{sealed, Instance, RtcConfig};
|
||||
use crate::pac::rtc::Rtc;
|
||||
|
||||
#[cfg_attr(rtc_v2f0, path = "v2f0.rs")]
|
||||
#[cfg_attr(rtc_v2f2, path = "v2f2.rs")]
|
||||
#[cfg_attr(rtc_v2f3, path = "v2f3.rs")]
|
||||
#[cfg_attr(rtc_v2f4, path = "v2f4.rs")]
|
||||
#[cfg_attr(rtc_v2f7, path = "v2f7.rs")]
|
||||
#[cfg_attr(rtc_v2h7, path = "v2h7.rs")]
|
||||
#[cfg_attr(rtc_v2l0, path = "v2l0.rs")]
|
||||
#[cfg_attr(rtc_v2l1, path = "v2l1.rs")]
|
||||
#[cfg_attr(rtc_v2l4, path = "v2l4.rs")]
|
||||
#[cfg_attr(rtc_v2wb, path = "v2wb.rs")]
|
||||
mod family;
|
||||
|
||||
pub use family::*;
|
||||
|
||||
impl<'d, T: Instance> super::Rtc<'d, T> {
|
||||
/// Applies the RTC config
|
||||
/// It this changes the RTC clock source the time will be reset
|
||||
pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
|
||||
// Unlock the backup domain
|
||||
unsafe {
|
||||
unlock_backup_domain(rtc_config.clock_config as u8);
|
||||
let clock_config = rtc_config.clock_config as u8;
|
||||
|
||||
#[cfg(not(rtc_v2wb))]
|
||||
use stm32_metapac::rcc::vals::Rtcsel;
|
||||
|
||||
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))]
|
||||
let cr = crate::pac::PWR.cr();
|
||||
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
|
||||
let cr = crate::pac::PWR.cr1();
|
||||
|
||||
// TODO: Missing from PAC for l0 and f0?
|
||||
#[cfg(not(any(rtc_v2f0, rtc_v2l0)))]
|
||||
{
|
||||
cr.modify(|w| w.set_dbp(true));
|
||||
while !cr.read().dbp() {}
|
||||
}
|
||||
|
||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
#[cfg(any(rtc_v2l0, rtc_v2l1))]
|
||||
let reg = crate::pac::RCC.csr().read();
|
||||
|
||||
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))]
|
||||
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||
|
||||
#[cfg(rtc_v2wb)]
|
||||
let rtcsel = reg.rtcsel();
|
||||
#[cfg(not(rtc_v2wb))]
|
||||
let rtcsel = reg.rtcsel().0;
|
||||
|
||||
if !reg.rtcen() || rtcsel != clock_config {
|
||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
|
||||
let cr = crate::pac::RCC.bdcr();
|
||||
#[cfg(any(rtc_v2l0, rtc_v2l1))]
|
||||
let cr = crate::pac::RCC.csr();
|
||||
|
||||
cr.modify(|w| {
|
||||
// Reset
|
||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
#[cfg(not(rtc_v2wb))]
|
||||
w.set_rtcsel(Rtcsel(clock_config));
|
||||
#[cfg(rtc_v2wb)]
|
||||
w.set_rtcsel(clock_config);
|
||||
w.set_rtcen(true);
|
||||
|
||||
// Restore bcdr
|
||||
#[cfg(any(rtc_v2l4, rtc_v2wb))]
|
||||
w.set_lscosel(reg.lscosel());
|
||||
#[cfg(any(rtc_v2l4, rtc_v2wb))]
|
||||
w.set_lscoen(reg.lscoen());
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
|
||||
#[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
|
||||
w.set_lsedrv(reg.lsedrv());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.write(true, |rtc| unsafe {
|
||||
|
@ -148,24 +197,33 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Read content of the backup register.
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
pub fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
|
||||
if register < BACKUP_REGISTER_COUNT {
|
||||
Some(unsafe { rtc.bkpr(register).read().bkp() })
|
||||
} else {
|
||||
None
|
||||
impl sealed::Instance for crate::peripherals::RTC {
|
||||
const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
unsafe fn enable_peripheral_clk() {
|
||||
#[cfg(any(rtc_v2l4, rtc_v2wb))]
|
||||
{
|
||||
// enable peripheral clock for communication
|
||||
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
|
||||
|
||||
// read to allow the pwr clock to enable
|
||||
crate::pac::PWR.cr1().read();
|
||||
}
|
||||
}
|
||||
|
||||
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
Some(unsafe { rtc.bkpr(register).read().bkp() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn write_backup_register(rtc: &Rtc, register: usize, value: u32) {
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set content of the backup register.
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
pub fn write_backup_register(rtc: &Rtc, register: usize, value: u32) {
|
||||
if register < BACKUP_REGISTER_COUNT {
|
||||
unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) }
|
||||
}
|
||||
}
|
||||
impl Instance for crate::peripherals::RTC {}
|
|
@ -1,41 +0,0 @@
|
|||
use stm32_metapac::rcc::vals::Rtcsel;
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr1().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
crate::pac::RCC.bdcr().modify(|w| {
|
||||
// Reset
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
w.set_rtcsel(Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
// Restore bcdr
|
||||
w.set_lscosel(reg.lscosel());
|
||||
w.set_lscoen(reg.lscoen());
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsedrv(reg.lsedrv());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// enable peripheral clock for communication
|
||||
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
|
||||
|
||||
// read to allow the pwr clock to enable
|
||||
crate::pac::PWR.cr1().read();
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
use stm32_metapac::rcc::vals::Rtcsel;
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
crate::pac::RCC.bdcr().modify(|w| {
|
||||
// Reset
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
w.set_rtcsel(Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// Nothing to do
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
use stm32_metapac::rcc::vals::Rtcsel;
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
crate::pac::RCC.bdcr().modify(|w| {
|
||||
// Reset
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
w.set_rtcsel(Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// Nothing to do
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
use stm32_metapac::rcc::vals::Rtcsel;
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr1().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
crate::pac::RCC.bdcr().modify(|w| {
|
||||
// Reset
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
w.set_rtcsel(Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// Nothing to do
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
use stm32_metapac::rcc::vals::Rtcsel;
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr1().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
crate::pac::RCC.bdcr().modify(|w| {
|
||||
// Reset
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
w.set_rtcsel(Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
// Restore bcdr
|
||||
w.set_lscosel(reg.lscosel());
|
||||
w.set_lscoen(reg.lscoen());
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsedrv(reg.lsedrv());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// enable peripheral clock for communication
|
||||
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
|
||||
|
||||
// read to allow the pwr clock to enable
|
||||
crate::pac::PWR.cr1().read();
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
use stm32_metapac::rcc::vals::Rtcsel;
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr1().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
crate::pac::RCC.bdcr().modify(|w| {
|
||||
// Reset
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
w.set_rtcsel(Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsedrv(reg.lsedrv());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// Nothing to do
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
// TODO: Missing from PAC?
|
||||
// crate::pac::PWR.cr().modify(|w| w.set_dbp(true));
|
||||
// while !crate::pac::PWR.cr().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.csr().read();
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.csr().modify(|w| {
|
||||
// Select RTC source
|
||||
w.set_rtcsel(crate::pac::rcc::vals::Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsedrv(reg.lsedrv());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// Nothing to do
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.csr().read();
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.csr().modify(|w| {
|
||||
// Select RTC source
|
||||
w.set_rtcsel(crate::pac::rcc::vals::Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// Nothing to do
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
use stm32_metapac::rcc::vals::Rtcsel;
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr1().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel().0 != clock_config {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
crate::pac::RCC.bdcr().modify(|w| {
|
||||
// Reset
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
w.set_rtcsel(Rtcsel(clock_config));
|
||||
w.set_rtcen(true);
|
||||
|
||||
// Restore bcdr
|
||||
w.set_lscosel(reg.lscosel());
|
||||
w.set_lscoen(reg.lscoen());
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsedrv(reg.lsedrv());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// enable peripheral clock for communication
|
||||
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
|
||||
|
||||
// read to allow the pwr clock to enable
|
||||
crate::pac::PWR.cr1().read();
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
pub const BACKUP_REGISTER_COUNT: usize = 20;
|
||||
|
||||
/// Unlock the backup domain
|
||||
pub(super) unsafe fn unlock_backup_domain(clock_config: u8) {
|
||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr1().read().dbp() {}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel() != clock_config {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
crate::pac::RCC.bdcr().modify(|w| {
|
||||
// Reset
|
||||
w.set_bdrst(false);
|
||||
|
||||
// Select RTC source
|
||||
w.set_rtcsel(clock_config);
|
||||
w.set_rtcen(true);
|
||||
|
||||
// Restore bcdr
|
||||
w.set_lscosel(reg.lscosel());
|
||||
w.set_lscoen(reg.lscoen());
|
||||
|
||||
w.set_lseon(reg.lseon());
|
||||
w.set_lsedrv(reg.lsedrv());
|
||||
w.set_lsebyp(reg.lsebyp());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_peripheral_clk() {
|
||||
// enable peripheral clock for communication
|
||||
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
|
||||
|
||||
// read to allow the pwr clock to enable
|
||||
crate::pac::PWR.cr1().read();
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType};
|
||||
|
||||
use super::{Instance, RtcCalibrationCyclePeriod, RtcConfig};
|
||||
use super::{sealed, Instance, RtcCalibrationCyclePeriod, RtcConfig};
|
||||
use crate::pac::rtc::Rtc;
|
||||
|
||||
impl<'d, T: Instance> super::Rtc<'d, T> {
|
||||
|
@ -9,43 +9,30 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||
pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
|
||||
// Unlock the backup domain
|
||||
unsafe {
|
||||
#[cfg(feature = "stm32g0c1ve")]
|
||||
#[cfg(any(rtc_v3u5, rcc_g0))]
|
||||
use crate::pac::rcc::vals::Rtcsel;
|
||||
#[cfg(not(any(rtc_v3u5, rcc_g0, rcc_g4, rcc_wl5, rcc_wle)))]
|
||||
use crate::pac::rtc::vals::Rtcsel;
|
||||
|
||||
#[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
|
||||
{
|
||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
||||
while !crate::pac::PWR.cr1().read().dbp() {}
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "stm32g0c1ve",
|
||||
feature = "stm32g491re",
|
||||
feature = "stm32u585zi",
|
||||
feature = "stm32g473cc"
|
||||
)))]
|
||||
#[cfg(any(rcc_wl5, rcc_wle))]
|
||||
{
|
||||
crate::pac::PWR
|
||||
.cr1()
|
||||
.modify(|w| w.set_dbp(stm32_metapac::pwr::vals::Dbp::ENABLED));
|
||||
while crate::pac::PWR.cr1().read().dbp() != stm32_metapac::pwr::vals::Dbp::DISABLED {}
|
||||
use crate::pac::pwr::vals::Dbp;
|
||||
|
||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
|
||||
while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {}
|
||||
}
|
||||
|
||||
let reg = crate::pac::RCC.bdcr().read();
|
||||
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||
|
||||
let config_rtcsel = rtc_config.clock_config as u8;
|
||||
#[cfg(not(any(
|
||||
feature = "stm32wl54jc-cm0p",
|
||||
feature = "stm32wle5ub",
|
||||
feature = "stm32g0c1ve",
|
||||
feature = "stm32wl55jc-cm4",
|
||||
feature = "stm32wl55uc-cm4",
|
||||
feature = "stm32g491re",
|
||||
feature = "stm32g473cc",
|
||||
feature = "stm32u585zi",
|
||||
feature = "stm32wle5jb"
|
||||
)))]
|
||||
let config_rtcsel = stm32_metapac::rtc::vals::Rtcsel(config_rtcsel);
|
||||
#[cfg(feature = "stm32g0c1ve")]
|
||||
let config_rtcsel = stm32_metapac::rcc::vals::Rtcsel(config_rtcsel);
|
||||
#[cfg(not(any(rcc_wl5, rcc_wle, rcc_g4)))]
|
||||
let config_rtcsel = Rtcsel(config_rtcsel);
|
||||
|
||||
if !reg.rtcen() || reg.rtcsel() != config_rtcsel {
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
@ -195,32 +182,24 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe fn enable_peripheral_clk() {
|
||||
// Nothing to do
|
||||
}
|
||||
impl sealed::Instance for crate::peripherals::RTC {
|
||||
const BACKUP_REGISTER_COUNT: usize = 32;
|
||||
|
||||
pub const BACKUP_REGISTER_COUNT: usize = 32;
|
||||
fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
//Some(rtc.bkpr()[register].read().bits())
|
||||
None // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Read content of the backup register.
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
pub fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
|
||||
if register < BACKUP_REGISTER_COUNT {
|
||||
//Some(rtc.bkpr()[register].read().bits())
|
||||
None // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
|
||||
} else {
|
||||
None
|
||||
fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) {
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
// RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
|
||||
//unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set content of the backup register.
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
pub fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) {
|
||||
if register < BACKUP_REGISTER_COUNT {
|
||||
// RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
|
||||
//unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) }
|
||||
}
|
||||
}
|
||||
impl Instance for crate::peripherals::RTC {}
|
||||
|
|
|
@ -26,6 +26,7 @@ nb = "1.0.0"
|
|||
embedded-storage = "0.3.0"
|
||||
micromath = "2.0.0"
|
||||
static_cell = "1.0"
|
||||
chrono = { version = "^0.4", default-features = false}
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
||||
|
|
30
examples/stm32f4/src/bin/rtc.rs
Normal file
30
examples/stm32f4/src/bin/rtc.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::rtc::{Rtc, RtcConfig};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
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());
|
||||
|
||||
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();
|
||||
}
|
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||
|
||||
[features]
|
||||
stm32f103c8 = ["embassy-stm32/stm32f103c8"] # Blue Pill
|
||||
stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc"] # Nucleo
|
||||
stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc", "chrono"] # Nucleo
|
||||
stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo
|
||||
stm32c031c6 = ["embassy-stm32/stm32c031c6"] # Nucleo
|
||||
stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo
|
||||
|
@ -16,6 +16,7 @@ stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
|
|||
stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
|
||||
|
||||
sdmmc = []
|
||||
chrono = ["embassy-stm32/chrono", "dep:chrono"]
|
||||
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||
|
@ -33,6 +34,8 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
|
|||
embedded-hal-async = { version = "=0.2.0-alpha.1" }
|
||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
|
||||
|
||||
chrono = { version = "^0.4", default-features = false, optional = true}
|
||||
|
||||
# BEGIN TESTS
|
||||
# Generated by gen_test.py. DO NOT EDIT.
|
||||
[[bin]]
|
||||
|
@ -40,6 +43,11 @@ name = "gpio"
|
|||
path = "src/bin/gpio.rs"
|
||||
required-features = []
|
||||
|
||||
[[bin]]
|
||||
name = "rtc"
|
||||
path = "src/bin/rtc.rs"
|
||||
required-features = [ "chrono",]
|
||||
|
||||
[[bin]]
|
||||
name = "sdmmc"
|
||||
path = "src/bin/sdmmc.rs"
|
||||
|
|
52
tests/stm32/src/bin/rtc.rs
Normal file
52
tests/stm32/src/bin/rtc.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
// required-features: chrono
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
mod example_common;
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
use defmt::assert;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::pac;
|
||||
use embassy_stm32::rtc::{Rtc, RtcConfig};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use example_common::*;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(config());
|
||||
info!("Hello World!");
|
||||
|
||||
let now = NaiveDate::from_ymd_opt(2020, 5, 15)
|
||||
.unwrap()
|
||||
.and_hms_opt(10, 30, 15)
|
||||
.unwrap();
|
||||
|
||||
info!("Starting LSI");
|
||||
|
||||
unsafe {
|
||||
pac::RCC.csr().modify(|w| w.set_lsion(true));
|
||||
while !pac::RCC.csr().read().lsirdy() {}
|
||||
}
|
||||
|
||||
info!("Started LSI");
|
||||
|
||||
let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
|
||||
|
||||
rtc.set_datetime(now.into()).expect("datetime not set");
|
||||
|
||||
info!("Waiting 5 seconds");
|
||||
Timer::after(Duration::from_millis(5000)).await;
|
||||
|
||||
let then: NaiveDateTime = rtc.now().unwrap().into();
|
||||
let seconds = (then - now).num_seconds();
|
||||
|
||||
defmt::info!("measured = {}", seconds);
|
||||
|
||||
assert!(seconds > 3 && seconds < 7);
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
Loading…
Reference in a new issue