diff options
| author | Jakob <[email protected]> | 2025-11-15 13:36:23 +0100 |
|---|---|---|
| committer | Jakob <[email protected]> | 2025-11-15 13:36:23 +0100 |
| commit | 23d74db1d6113914f2c4b80f0992bfeed235a89d (patch) | |
| tree | c25a87219e3a1bd57327076955f44cd0be7e8ff4 | |
| parent | 435267941c5e585c0de714e3251f3d28426bcdca (diff) | |
Avoid generating update events when chaning timer period. Set frequency update methods to return applied ARR values which then can be used for calcualting new CCR values.
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/low_level.rs | 24 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 10 |
3 files changed, 20 insertions, 24 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 9a56a41fb..90ba196fc 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -160,15 +160,17 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 160 | 160 | ||
| 161 | /// Set PWM frequency. | 161 | /// Set PWM frequency. |
| 162 | /// | 162 | /// |
| 163 | /// Note: when you call this, the max duty value changes, so you will have to | 163 | /// Returns the applied ARR value which can be used to calculate CCR values. |
| 164 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | 164 | /// |
| 165 | pub fn set_frequency(&mut self, freq: Hertz) { | 165 | /// Note: that the frequency will not be applied in the timer until an update event |
| 166 | /// occurs. Reading the `max_duty` before the update event will return the old value | ||
| 167 | pub fn set_frequency(&mut self, freq: Hertz) -> u32 { | ||
| 166 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 168 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 167 | 2u8 | 169 | 2u8 |
| 168 | } else { | 170 | } else { |
| 169 | 1u8 | 171 | 1u8 |
| 170 | }; | 172 | }; |
| 171 | self.inner.set_frequency_internal(freq * multiplier, 16); | 173 | self.inner.set_frequency_internal(freq * multiplier, 16) |
| 172 | } | 174 | } |
| 173 | 175 | ||
| 174 | /// Get max duty value. | 176 | /// Get max duty value. |
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 0122fe4f7..f6af8be8c 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -293,19 +293,17 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 293 | /// the timer counter will wrap around at the same frequency as is being set. | 293 | /// the timer counter will wrap around at the same frequency as is being set. |
| 294 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved | 294 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved |
| 295 | /// because it needs to count up and down. | 295 | /// because it needs to count up and down. |
| 296 | pub fn set_frequency(&self, frequency: Hertz) { | 296 | pub fn set_frequency(&self, frequency: Hertz) -> u32 { |
| 297 | match T::BITS { | 297 | match T::BITS { |
| 298 | TimerBits::Bits16 => { | 298 | TimerBits::Bits16 => self.set_frequency_internal(frequency, 16), |
| 299 | self.set_frequency_internal(frequency, 16); | ||
| 300 | } | ||
| 301 | #[cfg(not(stm32l0))] | 299 | #[cfg(not(stm32l0))] |
| 302 | TimerBits::Bits32 => { | 300 | TimerBits::Bits32 => self.set_frequency_internal(frequency, 32), |
| 303 | self.set_frequency_internal(frequency, 32); | ||
| 304 | } | ||
| 305 | } | 301 | } |
| 306 | } | 302 | } |
| 307 | 303 | ||
| 308 | pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) { | 304 | /// Calculate ARR based on desired frequency |
| 305 | /// Returns actual value written to the register as u32 | ||
| 306 | pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) -> u32 { | ||
| 309 | let f = frequency.0; | 307 | let f = frequency.0; |
| 310 | assert!(f > 0); | 308 | assert!(f > 0); |
| 311 | let timer_f = T::frequency().0; | 309 | let timer_f = T::frequency().0; |
| @@ -322,10 +320,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 322 | let regs = self.regs_core(); | 320 | let regs = self.regs_core(); |
| 323 | regs.psc().write_value(psc); | 321 | regs.psc().write_value(psc); |
| 324 | regs.arr().write(|r| r.set_arr(arr)); | 322 | regs.arr().write(|r| r.set_arr(arr)); |
| 325 | 323 | arr as u32 | |
| 326 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | ||
| 327 | regs.egr().write(|r| r.set_ug(true)); | ||
| 328 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | ||
| 329 | } | 324 | } |
| 330 | #[cfg(not(stm32l0))] | 325 | #[cfg(not(stm32l0))] |
| 331 | TimerBits::Bits32 => { | 326 | TimerBits::Bits32 => { |
| @@ -335,10 +330,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 335 | let regs = self.regs_gp32_unchecked(); | 330 | let regs = self.regs_gp32_unchecked(); |
| 336 | regs.psc().write_value(psc); | 331 | regs.psc().write_value(psc); |
| 337 | regs.arr().write_value(arr); | 332 | regs.arr().write_value(arr); |
| 338 | 333 | arr | |
| 339 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | ||
| 340 | regs.egr().write(|r| r.set_ug(true)); | ||
| 341 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | ||
| 342 | } | 334 | } |
| 343 | } | 335 | } |
| 344 | } | 336 | } |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index c338b0fd4..01996c969 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -285,16 +285,18 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 285 | 285 | ||
| 286 | /// Set PWM frequency. | 286 | /// Set PWM frequency. |
| 287 | /// | 287 | /// |
| 288 | /// Note: when you call this, the max duty value changes, so you will have to | 288 | /// Returns the applied ARR value which can be used to calculate CCR values. |
| 289 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | 289 | /// |
| 290 | pub fn set_frequency(&mut self, freq: Hertz) { | 290 | /// Note: that the frequency will not be applied in the timer until an update event |
| 291 | /// occurs. Reading the `max_duty` before the update event will return the old value | ||
| 292 | pub fn set_frequency(&mut self, freq: Hertz) -> u32 { | ||
| 291 | // TODO: prevent ARR = u16::MAX? | 293 | // TODO: prevent ARR = u16::MAX? |
| 292 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 294 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 293 | 2u8 | 295 | 2u8 |
| 294 | } else { | 296 | } else { |
| 295 | 1u8 | 297 | 1u8 |
| 296 | }; | 298 | }; |
| 297 | self.inner.set_frequency_internal(freq * multiplier, 16); | 299 | self.inner.set_frequency_internal(freq * multiplier, 16) |
| 298 | } | 300 | } |
| 299 | 301 | ||
| 300 | /// Get max duty value. | 302 | /// Get max duty value. |
