diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-02-16 23:22:50 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-02-16 23:22:50 +0000 |
| commit | 897d42e01214396b448e5aae06a4186a4c282e7a (patch) | |
| tree | 0647c0548da5c09a51ac393bf5f37f11ba920ff7 | |
| parent | 0453f7ddb24b55bb080f24c22b6655f0014b21c2 (diff) | |
| parent | 610804f138708e616ed6a7d8324982b009a832d6 (diff) | |
Merge pull request #3880 from nikvoid/stm32-rtc-subsecond
STM32: RTC subsecond support
| -rw-r--r-- | embassy-stm32/src/rtc/datetime.rs | 21 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/mod.rs | 14 | ||||
| -rw-r--r-- | examples/stm32g0/src/bin/rtc.rs | 2 |
3 files changed, 33 insertions, 4 deletions
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 { | |||
| 22 | InvalidMinute, | 22 | InvalidMinute, |
| 23 | /// The [DateTime] contains an invalid second value. Must be between `0..=59`. | 23 | /// The [DateTime] contains an invalid second value. Must be between `0..=59`. |
| 24 | InvalidSecond, | 24 | InvalidSecond, |
| 25 | /// The [DateTime] contains an invalid microsecond value. Must be between `0..=999_999`. | ||
| 26 | InvalidMicrosecond, | ||
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | /// Structure containing date and time information | 29 | /// Structure containing date and time information |
| @@ -41,6 +43,8 @@ pub struct DateTime { | |||
| 41 | minute: u8, | 43 | minute: u8, |
| 42 | /// 0..59 | 44 | /// 0..59 |
| 43 | second: u8, | 45 | second: u8, |
| 46 | /// 0..999_999 | ||
| 47 | usecond: u32, | ||
| 44 | } | 48 | } |
| 45 | 49 | ||
| 46 | impl DateTime { | 50 | impl DateTime { |
| @@ -79,6 +83,11 @@ impl DateTime { | |||
| 79 | self.second | 83 | self.second |
| 80 | } | 84 | } |
| 81 | 85 | ||
| 86 | /// Get the microsecond (0..=999_999) | ||
| 87 | pub const fn microsecond(&self) -> u32 { | ||
| 88 | self.usecond | ||
| 89 | } | ||
| 90 | |||
| 82 | /// Create a new DateTime with the given information. | 91 | /// Create a new DateTime with the given information. |
| 83 | pub fn from( | 92 | pub fn from( |
| 84 | year: u16, | 93 | year: u16, |
| @@ -88,6 +97,7 @@ impl DateTime { | |||
| 88 | hour: u8, | 97 | hour: u8, |
| 89 | minute: u8, | 98 | minute: u8, |
| 90 | second: u8, | 99 | second: u8, |
| 100 | usecond: u32, | ||
| 91 | ) -> Result<Self, Error> { | 101 | ) -> Result<Self, Error> { |
| 92 | if year > 4095 { | 102 | if year > 4095 { |
| 93 | Err(Error::InvalidYear) | 103 | Err(Error::InvalidYear) |
| @@ -101,6 +111,8 @@ impl DateTime { | |||
| 101 | Err(Error::InvalidMinute) | 111 | Err(Error::InvalidMinute) |
| 102 | } else if second > 59 { | 112 | } else if second > 59 { |
| 103 | Err(Error::InvalidSecond) | 113 | Err(Error::InvalidSecond) |
| 114 | } else if usecond > 999_999 { | ||
| 115 | Err(Error::InvalidMicrosecond) | ||
| 104 | } else { | 116 | } else { |
| 105 | Ok(Self { | 117 | Ok(Self { |
| 106 | year, | 118 | year, |
| @@ -110,6 +122,7 @@ impl DateTime { | |||
| 110 | hour, | 122 | hour, |
| 111 | minute, | 123 | minute, |
| 112 | second, | 124 | second, |
| 125 | usecond, | ||
| 113 | }) | 126 | }) |
| 114 | } | 127 | } |
| 115 | } | 128 | } |
| @@ -126,6 +139,7 @@ impl From<chrono::NaiveDateTime> for DateTime { | |||
| 126 | hour: date_time.hour() as u8, | 139 | hour: date_time.hour() as u8, |
| 127 | minute: date_time.minute() as u8, | 140 | minute: date_time.minute() as u8, |
| 128 | second: date_time.second() as u8, | 141 | second: date_time.second() as u8, |
| 142 | usecond: date_time.and_utc().timestamp_subsec_micros(), | ||
| 129 | } | 143 | } |
| 130 | } | 144 | } |
| 131 | } | 145 | } |
| @@ -135,7 +149,12 @@ impl From<DateTime> for chrono::NaiveDateTime { | |||
| 135 | fn from(date_time: DateTime) -> Self { | 149 | fn from(date_time: DateTime) -> Self { |
| 136 | NaiveDate::from_ymd_opt(date_time.year as i32, date_time.month as u32, date_time.day as u32) | 150 | NaiveDate::from_ymd_opt(date_time.year as i32, date_time.month as u32, date_time.day as u32) |
| 137 | .unwrap() | 151 | .unwrap() |
| 138 | .and_hms_opt(date_time.hour as u32, date_time.minute as u32, date_time.second as u32) | 152 | .and_hms_micro_opt( |
| 153 | date_time.hour as u32, | ||
| 154 | date_time.minute as u32, | ||
| 155 | date_time.second as u32, | ||
| 156 | date_time.usecond, | ||
| 157 | ) | ||
| 139 | .unwrap() | 158 | .unwrap() |
| 140 | } | 159 | } |
| 141 | } | 160 | } |
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 { | |||
| 60 | /// | 60 | /// |
| 61 | /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. | 61 | /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. |
| 62 | pub fn now(&self) -> Result<DateTime, RtcError> { | 62 | pub fn now(&self) -> Result<DateTime, RtcError> { |
| 63 | self.read(|dr, tr, _| { | 63 | self.read(|dr, tr, _ss| { |
| 64 | let second = bcd2_to_byte((tr.st(), tr.su())); | 64 | let second = bcd2_to_byte((tr.st(), tr.su())); |
| 65 | let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); | 65 | let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); |
| 66 | let hour = bcd2_to_byte((tr.ht(), tr.hu())); | 66 | let hour = bcd2_to_byte((tr.ht(), tr.hu())); |
| @@ -70,7 +70,17 @@ impl RtcTimeProvider { | |||
| 70 | let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); | 70 | let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); |
| 71 | let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16; | 71 | let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16; |
| 72 | 72 | ||
| 73 | DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) | 73 | // Calculate second fraction and multiply to microseconds |
| 74 | // Formula from RM0410 | ||
| 75 | #[cfg(not(rtc_v2f2))] | ||
| 76 | let us = { | ||
| 77 | let prediv = RTC::regs().prer().read().prediv_s() as f32; | ||
| 78 | (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32 | ||
| 79 | }; | ||
| 80 | #[cfg(rtc_v2f2)] | ||
| 81 | let us = 0; | ||
| 82 | |||
| 83 | DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime) | ||
| 74 | }) | 84 | }) |
| 75 | } | 85 | } |
| 76 | 86 | ||
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) { | |||
| 15 | 15 | ||
| 16 | info!("Hello World!"); | 16 | info!("Hello World!"); |
| 17 | 17 | ||
| 18 | let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10); | 18 | let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10, 0); |
| 19 | 19 | ||
| 20 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 20 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 21 | 21 | ||
