aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurĂ©lien Jacobs <[email protected]>2024-11-19 17:26:45 +0100
committerAurĂ©lien Jacobs <[email protected]>2024-11-20 16:21:20 +0100
commit3402e76f9876d58d271501102e2d80c9b2c389b3 (patch)
tree6bec1545e52ad49b665a35b380d983215bf10668
parent0f95c72e78e411e0fd10420ebee3c4bd323a210a (diff)
stm32/timer: avoid max_compare_value >= u16::MAX
With STM32 32 bits timers, the max_compare_value (AKA, ARR register) can currently be set greater than u16::MAX, which leads to the following assert!(max < u16::MAX as u32) in max_duty_cycle() when setting up a 1 kHz SimplePwm on 84 MHz MCU. The issue is fixed by forcing a max_compare_value that fits into 16 bits when setting the frequency for a PWM.
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs2
-rw-r--r--embassy-stm32/src/timer/low_level.rs24
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs2
3 files changed, 18 insertions, 10 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 46ccbf3df..02c01e900 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -116,7 +116,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
116 } else { 116 } else {
117 1u8 117 1u8
118 }; 118 };
119 self.inner.set_frequency(freq * multiplier); 119 self.inner.set_frequency_internal(freq * multiplier, 16);
120 } 120 }
121 121
122 /// Get max duty value. 122 /// Get max duty value.
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index 3136ea4e9..7360d6aef 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -242,16 +242,28 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
242 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved 242 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
243 /// because it needs to count up and down. 243 /// because it needs to count up and down.
244 pub fn set_frequency(&self, frequency: Hertz) { 244 pub fn set_frequency(&self, frequency: Hertz) {
245 match T::BITS {
246 TimerBits::Bits16 => {
247 self.set_frequency_internal(frequency, 16);
248 }
249 #[cfg(not(stm32l0))]
250 TimerBits::Bits32 => {
251 self.set_frequency_internal(frequency, 32);
252 }
253 }
254 }
255
256 pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) {
245 let f = frequency.0; 257 let f = frequency.0;
246 assert!(f > 0); 258 assert!(f > 0);
247 let timer_f = T::frequency().0; 259 let timer_f = T::frequency().0;
248 260
261 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
262 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into());
263 let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
264
249 match T::BITS { 265 match T::BITS {
250 TimerBits::Bits16 => { 266 TimerBits::Bits16 => {
251 let pclk_ticks_per_timer_period = timer_f / f;
252 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
253 let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1);
254
255 // the timer counts `0..=arr`, we want it to count `0..divide_by` 267 // the timer counts `0..=arr`, we want it to count `0..divide_by`
256 let arr = unwrap!(u16::try_from(divide_by - 1)); 268 let arr = unwrap!(u16::try_from(divide_by - 1));
257 269
@@ -265,10 +277,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
265 } 277 }
266 #[cfg(not(stm32l0))] 278 #[cfg(not(stm32l0))]
267 TimerBits::Bits32 => { 279 TimerBits::Bits32 => {
268 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
269 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
270 let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
271
272 // the timer counts `0..=arr`, we want it to count `0..divide_by` 280 // the timer counts `0..=arr`, we want it to count `0..divide_by`
273 let arr: u32 = unwrap!(u32::try_from(divide_by - 1)); 281 let arr: u32 = unwrap!(u32::try_from(divide_by - 1));
274 282
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 9e4a09095..56fb1871e 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -278,7 +278,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
278 } else { 278 } else {
279 1u8 279 1u8
280 }; 280 };
281 self.inner.set_frequency(freq * multiplier); 281 self.inner.set_frequency_internal(freq * multiplier, 16);
282 } 282 }
283 283
284 /// Get max duty value. 284 /// Get max duty value.