mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-24 15:52:34 +00:00
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.
This commit is contained in:
parent
0f95c72e78
commit
3402e76f98
@ -116,7 +116,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
|
||||
} else {
|
||||
1u8
|
||||
};
|
||||
self.inner.set_frequency(freq * multiplier);
|
||||
self.inner.set_frequency_internal(freq * multiplier, 16);
|
||||
}
|
||||
|
||||
/// Get max duty value.
|
||||
|
@ -242,16 +242,28 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
|
||||
/// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
|
||||
/// because it needs to count up and down.
|
||||
pub fn set_frequency(&self, frequency: Hertz) {
|
||||
match T::BITS {
|
||||
TimerBits::Bits16 => {
|
||||
self.set_frequency_internal(frequency, 16);
|
||||
}
|
||||
#[cfg(not(stm32l0))]
|
||||
TimerBits::Bits32 => {
|
||||
self.set_frequency_internal(frequency, 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) {
|
||||
let f = frequency.0;
|
||||
assert!(f > 0);
|
||||
let timer_f = T::frequency().0;
|
||||
|
||||
let pclk_ticks_per_timer_period = (timer_f / f) as u64;
|
||||
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into());
|
||||
let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
|
||||
|
||||
match T::BITS {
|
||||
TimerBits::Bits16 => {
|
||||
let pclk_ticks_per_timer_period = timer_f / f;
|
||||
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
|
||||
let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1);
|
||||
|
||||
// the timer counts `0..=arr`, we want it to count `0..divide_by`
|
||||
let arr = unwrap!(u16::try_from(divide_by - 1));
|
||||
|
||||
@ -265,10 +277,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
|
||||
}
|
||||
#[cfg(not(stm32l0))]
|
||||
TimerBits::Bits32 => {
|
||||
let pclk_ticks_per_timer_period = (timer_f / f) as u64;
|
||||
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
|
||||
let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
|
||||
|
||||
// the timer counts `0..=arr`, we want it to count `0..divide_by`
|
||||
let arr: u32 = unwrap!(u32::try_from(divide_by - 1));
|
||||
|
||||
|
@ -278,7 +278,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
|
||||
} else {
|
||||
1u8
|
||||
};
|
||||
self.inner.set_frequency(freq * multiplier);
|
||||
self.inner.set_frequency_internal(freq * multiplier, 16);
|
||||
}
|
||||
|
||||
/// Get max duty value.
|
||||
|
Loading…
Reference in New Issue
Block a user