diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index 526b0cfbd..8b420bb6e 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -22,6 +22,8 @@ pub enum Error { InvalidMinute, /// The [DateTime] contains an invalid second value. Must be between `0..=59`. InvalidSecond, + /// The [DateTime] contains an invalid microsecond value. Must be between `0..=999_999`. + InvalidMicrosecond, } /// Structure containing date and time information @@ -41,6 +43,8 @@ pub struct DateTime { minute: u8, /// 0..59 second: u8, + /// 0..999_999 + usecond: u32, } impl DateTime { @@ -79,6 +83,11 @@ impl DateTime { self.second } + /// Get the microsecond (0..=999_999) + pub const fn microsecond(&self) -> u32 { + self.usecond + } + /// Create a new DateTime with the given information. pub fn from( year: u16, @@ -88,6 +97,7 @@ impl DateTime { hour: u8, minute: u8, second: u8, + usecond: u32, ) -> Result { if year > 4095 { Err(Error::InvalidYear) @@ -101,6 +111,8 @@ impl DateTime { Err(Error::InvalidMinute) } else if second > 59 { Err(Error::InvalidSecond) + } else if usecond > 999_999 { + Err(Error::InvalidMicrosecond) } else { Ok(Self { year, @@ -110,6 +122,7 @@ impl DateTime { hour, minute, second, + usecond, }) } } @@ -126,6 +139,7 @@ impl From for DateTime { hour: date_time.hour() as u8, minute: date_time.minute() as u8, second: date_time.second() as u8, + usecond: date_time.and_utc().timestamp_subsec_micros(), } } } @@ -135,7 +149,12 @@ impl From for chrono::NaiveDateTime { fn from(date_time: DateTime) -> Self { 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) + .and_hms_micro_opt( + date_time.hour as u32, + date_time.minute as u32, + date_time.second as u32, + date_time.usecond, + ) .unwrap() } } diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 66646de4c..c2919e2bd 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -60,7 +60,7 @@ impl RtcTimeProvider { /// /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. pub fn now(&self) -> Result { - self.read(|dr, tr, _| { + self.read(|dr, tr, _ss| { 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())); @@ -70,7 +70,17 @@ impl RtcTimeProvider { let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16; - DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) + // Calculate second fraction and multiply to microseconds + // Formula from RM0410 + #[cfg(not(rtc_v2f2))] + let us = { + let prediv = RTC::regs().prer().read().prediv_s() as f32; + (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32 + }; + #[cfg(rtc_v2f2)] + let us = 0; + + DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime) }) } diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs index c02c1ecd7..50fb6398e 100644 --- a/examples/stm32g0/src/bin/rtc.rs +++ b/examples/stm32g0/src/bin/rtc.rs @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10); + let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10, 0); let mut rtc = Rtc::new(p.RTC, RtcConfig::default());