aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob <[email protected]>2025-11-15 20:19:06 +0100
committerJakob <[email protected]>2025-11-15 20:19:06 +0100
commit4793f59cde20203b33dca7222d12cbd9f95d5e1c (patch)
treed6f12fcc9efa82f87907b80666b7ab07742f84c0
parent67af86d664cd84122824d0a039ce366f2dcdae03 (diff)
Add separate method for generating update event. Make sure values are loaded into shadow registers before starting the timer.
-rw-r--r--embassy-stm32/CHANGELOG.md2
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs14
-rw-r--r--embassy-stm32/src/timer/input_capture.rs1
-rw-r--r--embassy-stm32/src/timer/low_level.rs26
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs1
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs14
6 files changed, 36 insertions, 22 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index b0287f73a..71b8cdafa 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
9 9
10- fix: Avoid generating timer update events when updating the frequency, add ARR as return value ([#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- fix: flash erase on dual-bank STM32Gxxx 11- fix: flash erase on dual-bank STM32Gxxx
12- feat: Add support for STM32N657X0 12- 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)) 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))
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.