aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob <[email protected]>2025-11-15 20:20:29 +0100
committerGitHub <[email protected]>2025-11-15 20:20:29 +0100
commit37ee00ec3e423d81c5a5dbeb3481c94c1311e079 (patch)
tree698d8848dc9141f37d750392412b04f8f0f565b8
parent4793f59cde20203b33dca7222d12cbd9f95d5e1c (diff)
parent933e27d99aaa4869aa601d6ac0f68b6e79788d3e (diff)
Merge branch 'main' into timer_update_management
-rw-r--r--embassy-stm32/CHANGELOG.md2
-rw-r--r--embassy-stm32/src/adc/g4.rs50
-rw-r--r--embassy-stm32/src/adc/mod.rs38
-rw-r--r--embassy-stm32/src/adc/v3.rs16
-rw-r--r--embassy-stm32/src/rtc/low_power.rs69
-rw-r--r--embassy-stm32/src/sai/mod.rs4
-rw-r--r--embassy-stm32/src/time_driver.rs33
-rw-r--r--examples/stm32h723/src/bin/spdifrx.rs2
8 files changed, 95 insertions, 119 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 71b8cdafa..ca8758a15 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
9 9
10- fix: Avoid generating timer update events when updating the frequency ([#4890](https://github.com/embassy-rs/embassy/pull/4890)) 10- fix: Avoid generating timer update events when updating the frequency ([#4890](https://github.com/embassy-rs/embassy/pull/4890))
11- chore: cleanup low-power add time
12- fix: Allow setting SAI peripheral `frame_length` to `256`
11- fix: flash erase on dual-bank STM32Gxxx 13- fix: flash erase on dual-bank STM32Gxxx
12- feat: Add support for STM32N657X0 14- feat: Add support for STM32N657X0
13- feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) 15- feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717))
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index bd8ccbf17..4957123a1 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,14 +1,12 @@
1#[cfg(stm32g4)] 1#[cfg(stm32g4)]
2use pac::adc::regs::Difsel as DifselReg; 2use pac::adc::regs::Difsel as DifselReg;
3#[allow(unused)] 3#[allow(unused)]
4#[cfg(stm32g4)]
5pub use pac::adc::vals::{Adcaldif, Adstp, Difsel, Dmacfg, Dmaen, Exten, Rovsm, Trovs};
6#[allow(unused)]
4#[cfg(stm32h7)] 7#[cfg(stm32h7)]
5use pac::adc::vals::{Adcaldif, Difsel, Exten}; 8use pac::adc::vals::{Adcaldif, Difsel, Exten};
6#[allow(unused)] 9pub use pac::adccommon::vals::{Dual, Presc};
7#[cfg(stm32g4)]
8pub use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs};
9pub use pac::adccommon::vals::Presc;
10pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
11pub use stm32_metapac::adccommon::vals::Dual;
12 10
13use super::{ 11use super::{
14 Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, 12 Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime,
@@ -176,6 +174,8 @@ impl<T: Instance> super::SealedAnyInstance for T {
176 } 174 }
177 175
178 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { 176 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
177 T::regs().cr().modify(|w| w.set_aden(false));
178
179 // Set sequence length 179 // Set sequence length
180 T::regs().sqr1().modify(|w| { 180 T::regs().sqr1().modify(|w| {
181 w.set_l(sequence.len() as u8 - 1); 181 w.set_l(sequence.len() as u8 - 1);
@@ -183,36 +183,34 @@ impl<T: Instance> super::SealedAnyInstance for T {
183 183
184 #[cfg(stm32g4)] 184 #[cfg(stm32g4)]
185 let mut difsel = DifselReg::default(); 185 let mut difsel = DifselReg::default();
186 let mut smpr = T::regs().smpr().read();
187 let mut smpr2 = T::regs().smpr2().read();
188 let mut sqr1 = T::regs().sqr1().read();
189 let mut sqr2 = T::regs().sqr2().read();
190 let mut sqr3 = T::regs().sqr3().read();
191 let mut sqr4 = T::regs().sqr4().read();
186 192
187 // Configure channels and ranks 193 // Configure channels and ranks
188 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { 194 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() {
189 let sample_time = sample_time.into(); 195 let sample_time = sample_time.into();
190 if ch <= 9 { 196 if ch <= 9 {
191 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); 197 smpr.set_smp(ch as _, sample_time);
192 } else { 198 } else {
193 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); 199 smpr2.set_smp((ch - 10) as _, sample_time);
194 } 200 }
195 201
196 match _i { 202 match _i {
197 0..=3 => { 203 0..=3 => {
198 T::regs().sqr1().modify(|w| { 204 sqr1.set_sq(_i, ch);
199 w.set_sq(_i, ch);
200 });
201 } 205 }
202 4..=8 => { 206 4..=8 => {
203 T::regs().sqr2().modify(|w| { 207 sqr2.set_sq(_i - 4, ch);
204 w.set_sq(_i - 4, ch);
205 });
206 } 208 }
207 9..=13 => { 209 9..=13 => {
208 T::regs().sqr3().modify(|w| { 210 sqr3.set_sq(_i - 9, ch);
209 w.set_sq(_i - 9, ch);
210 });
211 } 211 }
212 14..=15 => { 212 14..=15 => {
213 T::regs().sqr4().modify(|w| { 213 sqr4.set_sq(_i - 14, ch);
214 w.set_sq(_i - 14, ch);
215 });
216 } 214 }
217 _ => unreachable!(), 215 _ => unreachable!(),
218 } 216 }
@@ -232,12 +230,14 @@ impl<T: Instance> super::SealedAnyInstance for T {
232 } 230 }
233 } 231 }
234 232
233 T::regs().smpr().write_value(smpr);
234 T::regs().smpr2().write_value(smpr2);
235 T::regs().sqr1().write_value(sqr1);
236 T::regs().sqr2().write_value(sqr2);
237 T::regs().sqr3().write_value(sqr3);
238 T::regs().sqr4().write_value(sqr4);
235 #[cfg(stm32g4)] 239 #[cfg(stm32g4)]
236 { 240 T::regs().difsel().write_value(difsel);
237 T::regs().cr().modify(|w| w.set_aden(false));
238 T::regs().difsel().write_value(difsel);
239 T::enable();
240 }
241 } 241 }
242} 242}
243 243
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 13f8a1544..74648cc21 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -192,10 +192,16 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
192 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 192 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
193 channel.setup(); 193 channel.setup();
194 194
195 #[cfg(not(adc_v4))] 195 #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))]
196 T::enable(); 196 T::enable();
197 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); 197 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
198 198
199 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
200 //
201 // TODO: If hardware allows, enable after configure_sequence on all chips
202 #[cfg(any(adc_g4, adc_h5))]
203 T::enable();
204
199 T::convert() 205 T::convert()
200 } 206 }
201 207
@@ -229,10 +235,10 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
229 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use 235 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
230 /// `into_ring_buffered`, `into_ring_buffered_and_injected` 236 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
231 /// 237 ///
232 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use 238 /// Note: Depending on hardware limitations, this method may require channels to be passed
233 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). 239 /// in order or require the sequence to have the same sample time for all channnels, depending
234 /// 240 /// on the number and properties of the channels in the sequence. This method will panic if
235 /// In addtion, on STM320, this method will panic if the channels are not passed in order 241 /// the hardware cannot deliver the requested configuration.
236 pub async fn read( 242 pub async fn read(
237 &mut self, 243 &mut self,
238 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, 244 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
@@ -249,14 +255,20 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
249 "Asynchronous read sequence cannot be more than 16 in length" 255 "Asynchronous read sequence cannot be more than 16 in length"
250 ); 256 );
251 257
252 // Ensure no conversions are ongoing and ADC is enabled. 258 // Ensure no conversions are ongoing
253 T::stop(); 259 T::stop();
260 #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
254 T::enable(); 261 T::enable();
255 262
256 T::configure_sequence( 263 T::configure_sequence(
257 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), 264 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
258 ); 265 );
259 266
267 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
268 //
269 // TODO: If hardware allows, enable after configure_sequence on all chips
270 #[cfg(any(adc_g4, adc_h5))]
271 T::enable();
260 T::configure_dma(ConversionMode::Singular); 272 T::configure_dma(ConversionMode::Singular);
261 273
262 let request = rx_dma.request(); 274 let request = rx_dma.request();
@@ -294,6 +306,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
294 /// 306 ///
295 /// # Returns 307 /// # Returns
296 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling. 308 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
309 ///
310 /// Note: Depending on hardware limitations, this method may require channels to be passed
311 /// in order or require the sequence to have the same sample time for all channnels, depending
312 /// on the number and properties of the channels in the sequence. This method will panic if
313 /// the hardware cannot deliver the requested configuration.
297 pub fn into_ring_buffered<'a>( 314 pub fn into_ring_buffered<'a>(
298 self, 315 self,
299 dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>, 316 dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>,
@@ -307,15 +324,20 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
307 sequence.len() <= 16, 324 sequence.len() <= 16,
308 "Asynchronous read sequence cannot be more than 16 in length" 325 "Asynchronous read sequence cannot be more than 16 in length"
309 ); 326 );
310 // reset conversions and enable the adc 327 // Ensure no conversions are ongoing
311 T::stop(); 328 T::stop();
329 #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
312 T::enable(); 330 T::enable();
313 331
314 //adc side setup
315 T::configure_sequence( 332 T::configure_sequence(
316 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), 333 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
317 ); 334 );
318 335
336 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
337 //
338 // TODO: If hardware allows, enable after configure_sequence on all chips
339 #[cfg(any(adc_g4, adc_h5))]
340 T::enable();
319 T::configure_dma(ConversionMode::Repeated(mode)); 341 T::configure_dma(ConversionMode::Repeated(mode));
320 342
321 core::mem::forget(self); 343 core::mem::forget(self);
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 81eb1e3ee..b270588c4 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -260,6 +260,9 @@ impl<T: Instance> super::SealedAnyInstance for T {
260 } 260 }
261 261
262 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { 262 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
263 #[cfg(adc_h5)]
264 T::regs().cr().modify(|w| w.set_aden(false));
265
263 // Set sequence length 266 // Set sequence length
264 #[cfg(not(any(adc_g0, adc_u0)))] 267 #[cfg(not(any(adc_g0, adc_u0)))]
265 T::regs().sqr1().modify(|w| { 268 T::regs().sqr1().modify(|w| {
@@ -294,8 +297,11 @@ impl<T: Instance> super::SealedAnyInstance for T {
294 #[cfg(adc_u0)] 297 #[cfg(adc_u0)]
295 let mut channel_mask = 0; 298 let mut channel_mask = 0;
296 299
300 #[cfg(adc_h5)]
301 let mut difsel = 0u32;
302
297 // Configure channels and ranks 303 // Configure channels and ranks
298 for (_i, ((channel, _), sample_time)) in sequence.enumerate() { 304 for (_i, ((channel, _is_differential), sample_time)) in sequence.enumerate() {
299 // RM0492, RM0481, etc. 305 // RM0492, RM0481, etc.
300 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 306 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
301 #[cfg(any(adc_h5, adc_h7rs))] 307 #[cfg(any(adc_h5, adc_h7rs))]
@@ -357,12 +363,20 @@ impl<T: Instance> super::SealedAnyInstance for T {
357 _ => unreachable!(), 363 _ => unreachable!(),
358 } 364 }
359 365
366 #[cfg(adc_h5)]
367 {
368 difsel |= (_is_differential as u32) << channel;
369 }
370
360 #[cfg(adc_u0)] 371 #[cfg(adc_u0)]
361 { 372 {
362 channel_mask |= 1 << channel; 373 channel_mask |= 1 << channel;
363 } 374 }
364 } 375 }
365 376
377 #[cfg(adc_h5)]
378 T::regs().difsel().write(|w| w.set_difsel(difsel));
379
366 // On G0 and U0 enabled channels are sampled from 0 to last channel. 380 // On G0 and U0 enabled channels are sampled from 0 to last channel.
367 // It is possible to add up to 8 sequences if CHSELRMOD = 1. 381 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
368 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. 382 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index e5bf30927..f049d6b12 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -3,6 +3,7 @@ use embassy_time::{Duration, TICK_HZ};
3 3
4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; 4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte};
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::pac::rtc::vals::Wucksel;
6use crate::peripherals::RTC; 7use crate::peripherals::RTC;
7use crate::rtc::{RtcTimeProvider, SealedInstance}; 8use crate::rtc::{RtcTimeProvider, SealedInstance};
8 9
@@ -58,60 +59,16 @@ impl core::ops::Sub for RtcInstant {
58 } 59 }
59} 60}
60 61
61#[repr(u8)] 62fn wucksel_compute_min(val: u32) -> (Wucksel, u32) {
62#[derive(Clone, Copy, Debug)] 63 *[
63pub(crate) enum WakeupPrescaler { 64 (Wucksel::DIV2, 2),
64 Div2 = 2, 65 (Wucksel::DIV4, 4),
65 Div4 = 4, 66 (Wucksel::DIV8, 8),
66 Div8 = 8, 67 (Wucksel::DIV16, 16),
67 Div16 = 16, 68 ]
68} 69 .iter()
69 70 .find(|(_, psc)| *psc as u32 > val)
70#[cfg(any( 71 .unwrap_or(&(Wucksel::DIV16, 16))
71 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex
72))]
73impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
74 fn from(val: WakeupPrescaler) -> Self {
75 use crate::pac::rtc::vals::Wucksel;
76
77 match val {
78 WakeupPrescaler::Div2 => Wucksel::DIV2,
79 WakeupPrescaler::Div4 => Wucksel::DIV4,
80 WakeupPrescaler::Div8 => Wucksel::DIV8,
81 WakeupPrescaler::Div16 => Wucksel::DIV16,
82 }
83 }
84}
85
86#[cfg(any(
87 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex
88))]
89impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
90 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
91 use crate::pac::rtc::vals::Wucksel;
92
93 match val {
94 Wucksel::DIV2 => WakeupPrescaler::Div2,
95 Wucksel::DIV4 => WakeupPrescaler::Div4,
96 Wucksel::DIV8 => WakeupPrescaler::Div8,
97 Wucksel::DIV16 => WakeupPrescaler::Div16,
98 _ => unreachable!(),
99 }
100 }
101}
102
103impl WakeupPrescaler {
104 pub fn compute_min(val: u32) -> Self {
105 *[
106 WakeupPrescaler::Div2,
107 WakeupPrescaler::Div4,
108 WakeupPrescaler::Div8,
109 WakeupPrescaler::Div16,
110 ]
111 .iter()
112 .find(|psc| **psc as u32 > val)
113 .unwrap_or(&WakeupPrescaler::Div16)
114 }
115} 72}
116 73
117impl Rtc { 74impl Rtc {
@@ -138,7 +95,7 @@ impl Rtc {
138 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); 95 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
139 let rtc_hz = Self::frequency().0 as u64; 96 let rtc_hz = Self::frequency().0 as u64;
140 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; 97 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
141 let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); 98 let (wucksel, prescaler) = wucksel_compute_min((rtc_ticks / u16::MAX as u64) as u32);
142 99
143 // adjust the rtc ticks to the prescaler and subtract one rtc tick 100 // adjust the rtc ticks to the prescaler and subtract one rtc tick
144 let rtc_ticks = rtc_ticks / prescaler as u64; 101 let rtc_ticks = rtc_ticks / prescaler as u64;
@@ -159,7 +116,7 @@ impl Rtc {
159 while !regs.icsr().read().wutwf() {} 116 while !regs.icsr().read().wutwf() {}
160 } 117 }
161 118
162 regs.cr().modify(|w| w.set_wucksel(prescaler.into())); 119 regs.cr().modify(|w| w.set_wucksel(wucksel));
163 regs.wutr().write(|w| w.set_wut(rtc_ticks)); 120 regs.wutr().write(|w| w.set_wut(rtc_ticks));
164 regs.cr().modify(|w| w.set_wute(true)); 121 regs.cr().modify(|w| w.set_wute(true));
165 regs.cr().modify(|w| w.set_wutie(true)); 122 regs.cr().modify(|w| w.set_wutie(true));
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index 726d1729a..ce4bc43c3 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -391,7 +391,7 @@ pub struct Config {
391 pub frame_sync_polarity: FrameSyncPolarity, 391 pub frame_sync_polarity: FrameSyncPolarity,
392 pub frame_sync_active_level_length: word::U7, 392 pub frame_sync_active_level_length: word::U7,
393 pub frame_sync_definition: FrameSyncDefinition, 393 pub frame_sync_definition: FrameSyncDefinition,
394 pub frame_length: u8, 394 pub frame_length: u16,
395 pub clock_strobe: ClockStrobe, 395 pub clock_strobe: ClockStrobe,
396 pub output_drive: OutputDrive, 396 pub output_drive: OutputDrive,
397 pub master_clock_divider: Option<MasterClockDivider>, 397 pub master_clock_divider: Option<MasterClockDivider>,
@@ -696,7 +696,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
696 w.set_fspol(config.frame_sync_polarity.fspol()); 696 w.set_fspol(config.frame_sync_polarity.fspol());
697 w.set_fsdef(config.frame_sync_definition.fsdef()); 697 w.set_fsdef(config.frame_sync_definition.fsdef());
698 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); 698 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1);
699 w.set_frl(config.frame_length - 1); 699 w.set_frl((config.frame_length - 1).try_into().unwrap());
700 }); 700 });
701 701
702 ch.slotr().modify(|w| { 702 ch.slotr().modify(|w| {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 7db51d72e..bc34892ee 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -196,6 +196,11 @@ fn calc_now(period: u32, counter: u16) -> u64 {
196 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) 196 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
197} 197}
198 198
199#[cfg(feature = "low-power")]
200fn calc_period_counter(ticks: u64) -> (u32, u16) {
201 (2 * (ticks >> 16) as u32 + (ticks as u16 >= 0x8000) as u32, ticks as u16)
202}
203
199struct AlarmState { 204struct AlarmState {
200 timestamp: Cell<u64>, 205 timestamp: Cell<u64>,
201} 206}
@@ -358,34 +363,10 @@ impl RtcDriver {
358 #[cfg(feature = "low-power")] 363 #[cfg(feature = "low-power")]
359 /// Add the given offset to the current time 364 /// Add the given offset to the current time
360 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { 365 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
361 let offset = offset.as_ticks(); 366 let (period, counter) = calc_period_counter(self.now() + offset.as_ticks());
362 let cnt = regs_gp16().cnt().read().cnt() as u32;
363 let period = self.period.load(Ordering::SeqCst);
364
365 // Correct the race, if it exists
366 let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 {
367 period + 1
368 } else {
369 period
370 };
371
372 // Normalize to the full overflow
373 let period = (period / 2) * 2;
374
375 // Add the offset
376 let period = period + 2 * (offset / u16::MAX as u64) as u32;
377 let cnt = cnt + (offset % u16::MAX as u64) as u32;
378
379 let (cnt, period) = if cnt > u16::MAX as u32 {
380 (cnt - u16::MAX as u32, period + 2)
381 } else {
382 (cnt, period)
383 };
384
385 let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period };
386 367
387 self.period.store(period, Ordering::SeqCst); 368 self.period.store(period, Ordering::SeqCst);
388 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); 369 regs_gp16().cnt().write(|w| w.set_cnt(counter));
389 370
390 // Now, recompute alarm 371 // Now, recompute alarm
391 let alarm = self.alarm.borrow(cs); 372 let alarm = self.alarm.borrow(cs);
diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs
index cdbd69b89..5c29602c6 100644
--- a/examples/stm32h723/src/bin/spdifrx.rs
+++ b/examples/stm32h723/src/bin/spdifrx.rs
@@ -167,7 +167,7 @@ fn new_sai_transmitter<'d>(
167 sai_config.slot_count = hal::sai::word::U4(CHANNEL_COUNT as u8); 167 sai_config.slot_count = hal::sai::word::U4(CHANNEL_COUNT as u8);
168 sai_config.slot_enable = 0xFFFF; // All slots 168 sai_config.slot_enable = 0xFFFF; // All slots
169 sai_config.data_size = sai::DataSize::Data32; 169 sai_config.data_size = sai::DataSize::Data32;
170 sai_config.frame_length = (CHANNEL_COUNT * 32) as u8; 170 sai_config.frame_length = (CHANNEL_COUNT * 32) as u16;
171 sai_config.master_clock_divider = None; 171 sai_config.master_clock_divider = None;
172 172
173 let (sub_block_tx, _) = hal::sai::split_subblocks(sai); 173 let (sub_block_tx, _) = hal::sai::split_subblocks(sai);