From 561126b0d6068d189477af18461bf1e467532516 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sun, 1 Oct 2023 23:09:01 +0200 Subject: [PATCH] stm32: Add the ability to center-align timers --- embassy-stm32/src/timer/complementary_pwm.rs | 6 ++- embassy-stm32/src/timer/mod.rs | 49 +++++++++++++++++++- embassy-stm32/src/timer/simple_pwm.rs | 6 ++- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 4f033e3a..bfe5137e 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -57,11 +57,12 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { _ch4: Option>, _ch4n: Option>, freq: Hertz, + counting_mode: CountingMode, ) -> Self { - Self::new_inner(tim, freq) + Self::new_inner(tim, freq, counting_mode) } - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { + fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { into_ref!(tim); T::enable(); @@ -70,6 +71,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { let mut this = Self { inner: tim }; this.inner.set_frequency(freq); + this.inner.set_counting_mode(counting_mode); this.inner.start(); this.inner.enable_outputs(true); diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index d88fbcfd..52d1dc11 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -75,8 +75,16 @@ pub(crate) mod sealed { pub trait GeneralPurpose16bitInstance: Basic16bitInstance { fn regs_gp16() -> crate::pac::timer::TimGp16; - fn set_count_direction(&mut self, direction: vals::Dir) { - Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); + fn set_counting_mode(&mut self, mode: CountingMode) { + let (cms, dir) = mode.values(); + + let timer_enabled = Self::regs().cr1().read().cen(); + // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. + // Changing direction is discouraged while the timer is running. + assert!(timer_enabled); + + Self::regs_gp16().cr1().modify(|r| r.set_dir(dir)); + Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) } fn set_clock_division(&mut self, ckd: vals::Ckd) { @@ -265,6 +273,43 @@ impl From for stm32_metapac::timer::vals::CcmrInputCcs { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum CountingMode { + #[default] + /// The timer counts up to the reload value and then resets back to 0. + EdgeAlignedUp, + /// The timer counts down to 0 and then resets back to the reload value. + EdgeAlignedDown, + /// The timer counts up to the reload value and then counts back to 0. + /// + /// The output compare interrupt flags of channels configured in output are + /// set when the counter is counting down. + CenterAlignedDownInterrupts, + /// The timer counts up to the reload value and then counts back to 0. + /// + /// The output compare interrupt flags of channels configured in output are + /// set when the counter is counting up. + CenterAlignedUpInterrupts, + /// The timer counts up to the reload value and then counts back to 0. + /// + /// The output compare interrupt flags of channels configured in output are + /// set when the counter is counting both up or down. + CenterAlignedBothInterrupts, +} + +impl CountingMode { + /// Get the register values to set the timer mode to the current variant + pub fn values(&self) -> (vals::Cms, vals::Dir) { + match self { + CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), + CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), + CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), + CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), + CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), + } + } +} + #[derive(Clone, Copy)] pub enum OutputCompareMode { Frozen, diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 9e28878b..cdf12189 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -56,11 +56,12 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { _ch3: Option>, _ch4: Option>, freq: Hertz, + counting_mode: CountingMode, ) -> Self { - Self::new_inner(tim, freq) + Self::new_inner(tim, freq, counting_mode) } - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { + fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { into_ref!(tim); T::enable(); @@ -69,6 +70,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { let mut this = Self { inner: tim }; this.inner.set_frequency(freq); + this.inner.set_counting_mode(counting_mode); this.inner.start(); this.inner.enable_outputs(true);