diff options
| author | Jakob <[email protected]> | 2025-11-15 20:19:06 +0100 |
|---|---|---|
| committer | Jakob <[email protected]> | 2025-11-15 20:19:06 +0100 |
| commit | 4793f59cde20203b33dca7222d12cbd9f95d5e1c (patch) | |
| tree | d6f12fcc9efa82f87907b80666b7ab07742f84c0 /embassy-stm32/src/timer | |
| parent | 67af86d664cd84122824d0a039ce366f2dcdae03 (diff) | |
Add separate method for generating update event. Make sure values are loaded into shadow registers before starting the timer.
Diffstat (limited to 'embassy-stm32/src/timer')
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 14 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/input_capture.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/low_level.rs | 26 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/pwm_input.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 14 |
5 files changed, 35 insertions, 21 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 90ba196fc..3331e5b6b 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,17 +162,15 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 160 | 162 | ||
| 161 | /// Set PWM frequency. | 163 | /// Set PWM frequency. |
| 162 | /// | 164 | /// |
| 163 | /// Returns the applied ARR value which can be used to calculate CCR values. | ||
| 164 | /// | ||
| 165 | /// Note: that the frequency will not be applied in the timer until an update event | 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 | 166 | /// occurs. |
| 167 | pub fn set_frequency(&mut self, freq: Hertz) -> u32 { | 167 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 168 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 168 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 169 | 2u8 | 169 | 2u8 |
| 170 | } else { | 170 | } else { |
| 171 | 1u8 | 171 | 1u8 |
| 172 | }; | 172 | }; |
| 173 | self.inner.set_frequency_internal(freq * multiplier, 16) | 173 | self.inner.set_frequency_internal(freq * multiplier, 16); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | /// Get max duty value. | 176 | /// Get max duty value. |
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 f6af8be8c..55e1160ef 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -272,6 +272,16 @@ 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. | ||
| 279 | pub fn generate_update_event(&self) { | ||
| 280 | self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | ||
| 281 | self.regs_core().egr().write(|r| r.set_ug(true)); | ||
| 282 | self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | ||
| 283 | } | ||
| 284 | |||
| 275 | /// Stop the timer. | 285 | /// Stop the timer. |
| 276 | pub fn stop(&self) { | 286 | pub fn stop(&self) { |
| 277 | self.regs_core().cr1().modify(|r| r.set_cen(false)); | 287 | self.regs_core().cr1().modify(|r| r.set_cen(false)); |
| @@ -293,17 +303,19 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 293 | /// the timer counter will wrap around at the same frequency as is being set. | 303 | /// 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 | 304 | /// 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. | 305 | /// because it needs to count up and down. |
| 296 | pub fn set_frequency(&self, frequency: Hertz) -> u32 { | 306 | pub fn set_frequency(&self, frequency: Hertz) { |
| 297 | match T::BITS { | 307 | match T::BITS { |
| 298 | TimerBits::Bits16 => self.set_frequency_internal(frequency, 16), | 308 | TimerBits::Bits16 => { |
| 309 | self.set_frequency_internal(frequency, 16); | ||
| 310 | } | ||
| 299 | #[cfg(not(stm32l0))] | 311 | #[cfg(not(stm32l0))] |
| 300 | TimerBits::Bits32 => self.set_frequency_internal(frequency, 32), | 312 | TimerBits::Bits32 => { |
| 313 | self.set_frequency_internal(frequency, 32); | ||
| 314 | } | ||
| 301 | } | 315 | } |
| 302 | } | 316 | } |
| 303 | 317 | ||
| 304 | /// Calculate ARR based on desired frequency | 318 | pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) { |
| 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 { | ||
| 307 | let f = frequency.0; | 319 | let f = frequency.0; |
| 308 | assert!(f > 0); | 320 | assert!(f > 0); |
| 309 | let timer_f = T::frequency().0; | 321 | let timer_f = T::frequency().0; |
| @@ -320,7 +332,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 320 | let regs = self.regs_core(); | 332 | let regs = self.regs_core(); |
| 321 | regs.psc().write_value(psc); | 333 | regs.psc().write_value(psc); |
| 322 | regs.arr().write(|r| r.set_arr(arr)); | 334 | regs.arr().write(|r| r.set_arr(arr)); |
| 323 | arr as u32 | ||
| 324 | } | 335 | } |
| 325 | #[cfg(not(stm32l0))] | 336 | #[cfg(not(stm32l0))] |
| 326 | TimerBits::Bits32 => { | 337 | TimerBits::Bits32 => { |
| @@ -330,7 +341,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 330 | let regs = self.regs_gp32_unchecked(); | 341 | let regs = self.regs_gp32_unchecked(); |
| 331 | regs.psc().write_value(psc); | 342 | regs.psc().write_value(psc); |
| 332 | regs.arr().write_value(arr); | 343 | regs.arr().write_value(arr); |
| 333 | arr | ||
| 334 | } | 344 | } |
| 335 | } | 345 | } |
| 336 | } | 346 | } |
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 01996c969..58a2e2685 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,18 +289,16 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 285 | 289 | ||
| 286 | /// Set PWM frequency. | 290 | /// Set PWM frequency. |
| 287 | /// | 291 | /// |
| 288 | /// Returns the applied ARR value which can be used to calculate CCR values. | ||
| 289 | /// | ||
| 290 | /// Note: that the frequency will not be applied in the timer until an update event | 292 | /// 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 | 293 | /// occurs. |
| 292 | pub fn set_frequency(&mut self, freq: Hertz) -> u32 { | 294 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 293 | // TODO: prevent ARR = u16::MAX? | 295 | // TODO: prevent ARR = u16::MAX? |
| 294 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 296 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 295 | 2u8 | 297 | 2u8 |
| 296 | } else { | 298 | } else { |
| 297 | 1u8 | 299 | 1u8 |
| 298 | }; | 300 | }; |
| 299 | self.inner.set_frequency_internal(freq * multiplier, 16) | 301 | self.inner.set_frequency_internal(freq * multiplier, 16); |
| 300 | } | 302 | } |
| 301 | 303 | ||
| 302 | /// Get max duty value. | 304 | /// Get max duty value. |
