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 /embassy-stm32/src/timer | |
| 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.
Diffstat (limited to 'embassy-stm32/src/timer')
| -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. |
