diff options
| author | Jakob <[email protected]> | 2025-11-15 20:20:29 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-15 20:20:29 +0100 |
| commit | 37ee00ec3e423d81c5a5dbeb3481c94c1311e079 (patch) | |
| tree | 698d8848dc9141f37d750392412b04f8f0f565b8 | |
| parent | 4793f59cde20203b33dca7222d12cbd9f95d5e1c (diff) | |
| parent | 933e27d99aaa4869aa601d6ac0f68b6e79788d3e (diff) | |
Merge branch 'main' into timer_update_management
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/g4.rs | 50 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 38 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 16 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/low_power.rs | 69 | ||||
| -rw-r--r-- | embassy-stm32/src/sai/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 33 | ||||
| -rw-r--r-- | examples/stm32h723/src/bin/spdifrx.rs | 2 |
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)] |
| 2 | use pac::adc::regs::Difsel as DifselReg; | 2 | use pac::adc::regs::Difsel as DifselReg; |
| 3 | #[allow(unused)] | 3 | #[allow(unused)] |
| 4 | #[cfg(stm32g4)] | ||
| 5 | pub use pac::adc::vals::{Adcaldif, Adstp, Difsel, Dmacfg, Dmaen, Exten, Rovsm, Trovs}; | ||
| 6 | #[allow(unused)] | ||
| 4 | #[cfg(stm32h7)] | 7 | #[cfg(stm32h7)] |
| 5 | use pac::adc::vals::{Adcaldif, Difsel, Exten}; | 8 | use pac::adc::vals::{Adcaldif, Difsel, Exten}; |
| 6 | #[allow(unused)] | 9 | pub use pac::adccommon::vals::{Dual, Presc}; |
| 7 | #[cfg(stm32g4)] | ||
| 8 | pub use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; | ||
| 9 | pub use pac::adccommon::vals::Presc; | ||
| 10 | pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; | ||
| 11 | pub use stm32_metapac::adccommon::vals::Dual; | ||
| 12 | 10 | ||
| 13 | use super::{ | 11 | use 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 | ||
| 4 | use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; | 4 | use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; |
| 5 | use crate::interrupt::typelevel::Interrupt; | 5 | use crate::interrupt::typelevel::Interrupt; |
| 6 | use crate::pac::rtc::vals::Wucksel; | ||
| 6 | use crate::peripherals::RTC; | 7 | use crate::peripherals::RTC; |
| 7 | use crate::rtc::{RtcTimeProvider, SealedInstance}; | 8 | use 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)] | 62 | fn wucksel_compute_min(val: u32) -> (Wucksel, u32) { |
| 62 | #[derive(Clone, Copy, Debug)] | 63 | *[ |
| 63 | pub(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 | ))] | ||
| 73 | impl 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 | ))] | ||
| 89 | impl 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 | |||
| 103 | impl 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 | ||
| 117 | impl Rtc { | 74 | impl 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")] | ||
| 200 | fn calc_period_counter(ticks: u64) -> (u32, u16) { | ||
| 201 | (2 * (ticks >> 16) as u32 + (ticks as u16 >= 0x8000) as u32, ticks as u16) | ||
| 202 | } | ||
| 203 | |||
| 199 | struct AlarmState { | 204 | struct 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); |
