diff options
| author | xoviat <[email protected]> | 2025-11-15 21:14:36 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-15 21:14:36 +0000 |
| commit | 7a7527ac69bac0725f6586fa7bdd9e8556f7d105 (patch) | |
| tree | d33fd73f705bf65173bcd643a5f2253445b18bf8 | |
| parent | 11d753c8715b03ea4fbcad939a0537c54b45704f (diff) | |
| parent | 98052fbbeae66e4666d1fa4581550403aa40f295 (diff) | |
Merge pull request #4894 from xoviat/time
Avoid generating update events when changing timer period, #2.
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/input_capture.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/low_level.rs | 19 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/pwm_input.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 10 |
6 files changed, 27 insertions, 15 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index da0d14e4f..df832d15f 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | ## Unreleased - ReleaseDate | 8 | ## Unreleased - ReleaseDate |
| 9 | 9 | ||
| 10 | - feat: Add waveform methods to ComplementaryPwm | 10 | - feat: Add waveform methods to ComplementaryPwm |
| 11 | - 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 | - chore: cleanup low-power add time |
| 12 | - fix: Allow setting SAI peripheral `frame_length` to `256` | 13 | - fix: Allow setting SAI peripheral `frame_length` to `256` |
| 13 | - fix: flash erase on dual-bank STM32Gxxx | 14 | - fix: flash erase on dual-bank STM32Gxxx |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 76cbbe91d..6d4c70dff 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -77,8 +77,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 77 | 77 | ||
| 78 | this.inner.set_counting_mode(counting_mode); | 78 | this.inner.set_counting_mode(counting_mode); |
| 79 | this.set_frequency(freq); | 79 | this.set_frequency(freq); |
| 80 | this.inner.start(); | ||
| 81 | |||
| 82 | this.inner.enable_outputs(); | 80 | this.inner.enable_outputs(); |
| 83 | 81 | ||
| 84 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 82 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| @@ -89,6 +87,10 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 89 | }); | 87 | }); |
| 90 | this.inner.set_autoreload_preload(true); | 88 | this.inner.set_autoreload_preload(true); |
| 91 | 89 | ||
| 90 | // Generate update event so pre-load registers are written to the shadow registers | ||
| 91 | this.inner.generate_update_event(); | ||
| 92 | this.inner.start(); | ||
| 93 | |||
| 92 | this | 94 | this |
| 93 | } | 95 | } |
| 94 | 96 | ||
| @@ -160,8 +162,8 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 160 | 162 | ||
| 161 | /// Set PWM frequency. | 163 | /// Set PWM frequency. |
| 162 | /// | 164 | /// |
| 163 | /// Note: when you call this, the max duty value changes, so you will have to | 165 | /// Note: that the frequency will not be applied in the timer until an update event |
| 164 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | 166 | /// occurs. |
| 165 | pub fn set_frequency(&mut self, freq: Hertz) { | 167 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 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 |
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index 2a4ec2db0..9cf0f8c34 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs | |||
| @@ -60,6 +60,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { | |||
| 60 | this.inner.set_counting_mode(counting_mode); | 60 | this.inner.set_counting_mode(counting_mode); |
| 61 | this.inner.set_tick_freq(freq); | 61 | this.inner.set_tick_freq(freq); |
| 62 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details | 62 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details |
| 63 | this.inner.generate_update_event(); | ||
| 63 | this.inner.start(); | 64 | this.inner.start(); |
| 64 | 65 | ||
| 65 | // enable NVIC interrupt | 66 | // enable NVIC interrupt |
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index c574277e7..f0105ece8 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -272,6 +272,17 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 272 | self.regs_core().cr1().modify(|r| r.set_cen(true)); | 272 | self.regs_core().cr1().modify(|r| r.set_cen(true)); |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | /// Generate timer update event from software. | ||
| 276 | /// | ||
| 277 | /// Set URS to avoid generating interrupt or DMA request. This update event is only | ||
| 278 | /// used to load value from pre-load registers. If called when the timer is running, | ||
| 279 | /// it may disrupt the output waveform. | ||
| 280 | pub fn generate_update_event(&self) { | ||
| 281 | self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | ||
| 282 | self.regs_core().egr().write(|r| r.set_ug(true)); | ||
| 283 | self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | ||
| 284 | } | ||
| 285 | |||
| 275 | /// Stop the timer. | 286 | /// Stop the timer. |
| 276 | pub fn stop(&self) { | 287 | pub fn stop(&self) { |
| 277 | self.regs_core().cr1().modify(|r| r.set_cen(false)); | 288 | self.regs_core().cr1().modify(|r| r.set_cen(false)); |
| @@ -322,10 +333,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 322 | let regs = self.regs_core(); | 333 | let regs = self.regs_core(); |
| 323 | regs.psc().write_value(psc); | 334 | regs.psc().write_value(psc); |
| 324 | regs.arr().write(|r| r.set_arr(arr)); | 335 | regs.arr().write(|r| r.set_arr(arr)); |
| 325 | |||
| 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 | } | 336 | } |
| 330 | #[cfg(not(stm32l0))] | 337 | #[cfg(not(stm32l0))] |
| 331 | TimerBits::Bits32 => { | 338 | TimerBits::Bits32 => { |
| @@ -335,10 +342,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 335 | let regs = self.regs_gp32_unchecked(); | 342 | let regs = self.regs_gp32_unchecked(); |
| 336 | regs.psc().write_value(psc); | 343 | regs.psc().write_value(psc); |
| 337 | regs.arr().write_value(arr); | 344 | regs.arr().write_value(arr); |
| 338 | |||
| 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 | } | 345 | } |
| 343 | } | 346 | } |
| 344 | } | 347 | } |
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs index da8a79b09..057ab011a 100644 --- a/embassy-stm32/src/timer/pwm_input.rs +++ b/embassy-stm32/src/timer/pwm_input.rs | |||
| @@ -47,6 +47,7 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { | |||
| 47 | inner.set_counting_mode(CountingMode::EdgeAlignedUp); | 47 | inner.set_counting_mode(CountingMode::EdgeAlignedUp); |
| 48 | inner.set_tick_freq(freq); | 48 | inner.set_tick_freq(freq); |
| 49 | inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details | 49 | inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details |
| 50 | inner.generate_update_event(); | ||
| 50 | inner.start(); | 51 | inner.start(); |
| 51 | 52 | ||
| 52 | // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 | 53 | // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 19a0b38d1..6c9ef17e0 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -198,7 +198,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 198 | this.inner.set_counting_mode(counting_mode); | 198 | this.inner.set_counting_mode(counting_mode); |
| 199 | this.set_frequency(freq); | 199 | this.set_frequency(freq); |
| 200 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details | 200 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details |
| 201 | this.inner.start(); | ||
| 202 | 201 | ||
| 203 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 202 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| 204 | .iter() | 203 | .iter() |
| @@ -207,6 +206,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 207 | 206 | ||
| 208 | this.inner.set_output_compare_preload(channel, true); | 207 | this.inner.set_output_compare_preload(channel, true); |
| 209 | }); | 208 | }); |
| 209 | this.inner.set_autoreload_preload(true); | ||
| 210 | |||
| 211 | // Generate update event so pre-load registers are written to the shadow registers | ||
| 212 | this.inner.generate_update_event(); | ||
| 213 | this.inner.start(); | ||
| 210 | 214 | ||
| 211 | this | 215 | this |
| 212 | } | 216 | } |
| @@ -285,8 +289,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 285 | 289 | ||
| 286 | /// Set PWM frequency. | 290 | /// Set PWM frequency. |
| 287 | /// | 291 | /// |
| 288 | /// Note: when you call this, the max duty value changes, so you will have to | 292 | /// Note: that the frequency will not be applied in the timer until an update event |
| 289 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | 293 | /// occurs. |
| 290 | pub fn set_frequency(&mut self, freq: Hertz) { | 294 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 291 | // TODO: prevent ARR = u16::MAX? | 295 | // TODO: prevent ARR = u16::MAX? |
| 292 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 296 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
