From d38e2dbf225352e0c89f6e429989fd21b1afd132 Mon Sep 17 00:00:00 2001 From: Nilolay Date: Wed, 1 Jan 2025 23:21:49 +0200 Subject: [PATCH] Added support for Input Capture timer mode for frequency and pulse duration measurement --- CHANGELOG.md | 2 + Cargo.toml | 4 + examples/rtic2-timer-input-capture.rs | 78 ++++++++ src/timer.rs | 233 ++++++++++++++++++++--- src/timer/capture.rs | 261 ++++++++++++++++++++++++++ src/timer/pwm.rs | 4 +- 6 files changed, 553 insertions(+), 29 deletions(-) create mode 100644 examples/rtic2-timer-input-capture.rs create mode 100644 src/timer/capture.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 833043c0..a24312e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Use `write` instead of `modify` to clear flags [#829] - Bump `stm32f4-staging` to 0.18, update other dependencies [#831] - `serial` mod refactor [#833] [#839] + - Add "capture" support for timers [#830] - FMPI2c APB timings [#770] - Fefactor FMPI2c `embedded-hal` implementations [#784] - remove `NoPin`, use `Option` instead [#813] @@ -23,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [#784]: https://github.com/stm32-rs/stm32f4xx-hal/pull/784 [#813]: https://github.com/stm32-rs/stm32f4xx-hal/pull/813 [#829]: https://github.com/stm32-rs/stm32f4xx-hal/pull/829 +[#830]: https://github.com/stm32-rs/stm32f4xx-hal/pull/830 [#831]: https://github.com/stm32-rs/stm32f4xx-hal/pull/831 [#832]: https://github.com/stm32-rs/stm32f4xx-hal/pull/832 [#833]: https://github.com/stm32-rs/stm32f4xx-hal/pull/833 diff --git a/Cargo.toml b/Cargo.toml index a31d7597..bf124a1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -781,3 +781,7 @@ required-features = [] [[example]] name = "fmc-sdram" required-features = ["stm32f469", "stm32-fmc"] + +[[example]] +name = "rtic2-timer-input-capture" +required-features = ["rtic2"] diff --git a/examples/rtic2-timer-input-capture.rs b/examples/rtic2-timer-input-capture.rs new file mode 100644 index 00000000..7bb74b8b --- /dev/null +++ b/examples/rtic2-timer-input-capture.rs @@ -0,0 +1,78 @@ +#![no_main] +#![no_std] + +use defmt_rtt as _; +use panic_probe as _; +use stm32f4xx_hal::{ + pac, + pac::{TIM2, TIM5}, + prelude::*, + timer::{CaptureChannel, CaptureHzManager, CapturePolarity, Event, Flag, PwmChannel, Timer}, +}; + +use rtic::app; + +#[app(device = pac, dispatchers = [USART1], peripherals = true)] +mod app { + use super::*; + + #[shared] + struct Shared {} + + #[local] + struct Local { + tim5: CaptureHzManager, + ch1: CaptureChannel, + } + + #[init] + fn init(ctx: init::Context) -> (Shared, Local) { + let dp = ctx.device; + let rcc = dp.RCC.constrain(); + let clocks = rcc.cfgr.sysclk(48.MHz()).freeze(); + let gpioa = dp.GPIOA.split(); + + // Configuration of TIM2 in PWM mode + let timer = Timer::new(dp.TIM2, &clocks); + let (_, (ch1, ..)) = timer.pwm_hz(893.Hz()); + let mut tim_2: PwmChannel = ch1.with(gpioa.pa5); + tim_2.set_duty(50); + tim_2.enable(); + + // It is necessary to connect pins PA0 and PA5 through a resistor of 1 kΩ - 10 kΩ + + // Configuration of TIM5 in input capture mode + let (mut tim5, (ch1, ..)) = Timer::new(dp.TIM5, &clocks).capture_hz(48.MHz()); + let mut ch1 = ch1.with(gpioa.pa0); + tim5.listen(Event::C1); + + ch1.set_polarity(CapturePolarity::ActiveHigh); + ch1.enable(); + + defmt::info!("Start"); + + (Shared {}, Local { tim5, ch1 }) + } + + #[task(binds = TIM5, local = [tim5, ch1, prev_capture: u32 = 0], priority = 3)] + fn tim5_interrupt(cx: tim5_interrupt::Context) { + if cx.local.tim5.flags().contains(Flag::C1) { + let timer_clock = cx.local.tim5.get_timer_clock(); + let max_auto_reload = cx.local.tim5.get_max_auto_reload(); + let current_capture = cx.local.ch1.get_capture(); + + let delta = if current_capture >= *cx.local.prev_capture { + current_capture - *cx.local.prev_capture + } else { + (max_auto_reload - *cx.local.prev_capture) + current_capture + }; + + let freq = timer_clock as f32 / delta as f32; + + defmt::info!("Freq: {} Hz", freq); // Output = Freq: 893.00665 Hz + + *cx.local.prev_capture = current_capture; + cx.local.tim5.clear_flags(Flag::C1); + } + } +} diff --git a/src/timer.rs b/src/timer.rs index 88cd7d8b..f24e9d9d 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -27,6 +27,10 @@ pub use pwm::*; pub mod pwm_input; #[cfg(not(feature = "gpio-f410"))] pub use pwm_input::PwmInput; +#[cfg(not(feature = "gpio-f410"))] +pub mod capture; +#[cfg(not(feature = "gpio-f410"))] +pub use capture::*; #[cfg(feature = "rtic1")] pub mod monotonic; #[cfg(feature = "rtic1")] @@ -83,13 +87,21 @@ pub const C2: u8 = 1; pub const C3: u8 = 2; pub const C4: u8 = 3; -/// Enum for IO polarity +/// Compare/PWM polarity #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Polarity { ActiveHigh, ActiveLow, } +/// Capture polarity +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CapturePolarity { + ActiveHigh, + ActiveLow, + ActiveBoth, +} + /// Output Idle state #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum IdleState { @@ -307,6 +319,74 @@ pub enum Ocm { PwmMode2 = 7, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +/// Capture mode +/// Enum for configuring the mode of the Capture channels (CC1S, CC2S, CC3S, CC4S). +/// Defines how each channel is used in Input Capture mode, considering TI1, TI2, TI3, and TI4. +pub enum CaptureMode { + /// Input Capture on the corresponding channel (e.g., CC1 -> TI1, CC2 -> TI2, etc.). + InputCapture = 1, + /// Input Capture on the inverted channel (e.g., CC1 -> TI2, CC2 -> TI1, CC3 -> TI4, CC4 -> TI3). + InvChannelInputCapture = 2, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +/// Enum for configuring the Input Capture prescaler. +/// Determines how many input events are required for one capture. +pub enum CapturePrescaler { + /// No prescaler (00): Capture every input event. + No = 0, + /// Prescaler 2 (01): Capture every second input event. + Two = 1, + /// Prescaler 4 (10): Capture every fourth input event. + Four = 2, + /// Prescaler 8 (11): Capture every eighth input event. + Eight = 3, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +/// Enum representing the input capture filter settings. +pub enum CaptureFilter { + /// No filter, sampling frequency = fDTS, N = 1 + NoFilter, + /// Sampling frequency = fCK_INT, N = 2 + FckIntN2, + /// Sampling frequency = fCK_INT, N = 4 + FckIntN4, + /// Sampling frequency = fCK_INT, N = 8 + FckIntN8, + /// Sampling frequency = fDTS/2, N = 6 + FdtsDiv2N6, + /// Sampling frequency = fDTS/2, N = 8 + FdtsDiv2N8, + /// Sampling frequency = fDTS/4, N = 6 + FdtsDiv4N6, + /// Sampling frequency = fDTS/4, N = 8 + FdtsDiv4N8, + /// Sampling frequency = fDTS/8, N = 6 + FdtsDiv8N6, + /// Sampling frequency = fDTS/8, N = 8 + FdtsDiv8N8, + /// Sampling frequency = fDTS/16, N = 5 + FdtsDiv16N5, + /// Sampling frequency = fDTS/16, N = 6 + FdtsDiv16N6, + /// Sampling frequency = fDTS/16, N = 8 + FdtsDiv16N8, + /// Sampling frequency = fDTS/32, N = 5 + FdtsDiv32N5, + /// Sampling frequency = fDTS/32, N = 6 + FdtsDiv32N6, + /// Sampling frequency = fDTS/32, N = 8 + FdtsDiv32N8, +} + // Center-aligned mode selection pub use pac::tim1::cr1::CMS as CenterAlignedMode; @@ -321,7 +401,10 @@ pub type CCR4 = CCR; pub struct DMAR(T); mod sealed { - use super::{BitFlags, CenterAlignedMode, Event, Flag, IdleState, Ocm, Polarity}; + use super::{ + BitFlags, CaptureFilter, CaptureMode, CapturePolarity, CapturePrescaler, CenterAlignedMode, + Event, Flag, IdleState, Ocm, Polarity, + }; pub trait General { type Width: Into + From; fn max_auto_reload() -> u32; @@ -350,17 +433,19 @@ mod sealed { fn cnt_reset(&mut self); } - pub trait WithPwmCommon: General { + pub trait WithChannel: General { const CH_NUMBER: u8; const COMP_CH_NUMBER: u8; fn read_cc_value(channel: u8) -> u32; fn set_cc_value(channel: u8, value: u32); fn enable_channel(channel: u8, b: bool); - fn set_channel_polarity(channel: u8, p: Polarity); - fn set_nchannel_polarity(channel: u8, p: Polarity); + fn set_pwm_channel_polarity(channel: u8, p: Polarity); + fn set_pwm_nchannel_polarity(channel: u8, p: Polarity); + + fn set_capture_channel_polarity(channel: u8, p: CapturePolarity); } - pub trait Advanced: WithPwmCommon { + pub trait Advanced: WithChannel { fn enable_nchannel(channel: u8, b: bool); fn set_dtg_value(value: u8); fn read_dtg_value() -> u8; @@ -368,12 +453,19 @@ mod sealed { fn set_cms(mode: CenterAlignedMode); } - pub trait WithPwm: WithPwmCommon { + pub trait WithPwm: WithChannel { fn preload_output_channel_in_mode(&mut self, c: u8, mode: Ocm); fn freeze_output_channel(&mut self, c: u8); fn start_pwm(&mut self); } + pub trait WithCapture: WithChannel { + fn preload_capture(&mut self, c: u8, mode: CaptureMode); + fn prescaler_capture(&mut self, c: u8, psc: CapturePrescaler); + fn filter_capture(&mut self, c: u8, filter: CaptureFilter); + fn start_capture(&mut self); + } + pub trait MasterTimer: General { type Mms; fn master_mode(&mut self, mode: Self::Mms); @@ -383,15 +475,20 @@ mod sealed { type Channels; fn split() -> Self::Channels; } + + pub trait SplitCapture { + type CaptureChannels; + fn split_capture() -> Self::CaptureChannels; + } } -pub(crate) use sealed::{Advanced, General, MasterTimer, WithPwm, WithPwmCommon}; +pub(crate) use sealed::{Advanced, General, MasterTimer, WithCapture, WithChannel, WithPwm}; pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + rcc::BusTimerClock + General { } -use sealed::Split; +use sealed::{Split, SplitCapture}; macro_rules! split { ($TIM:ty: 1) => { split!($TIM, C1); @@ -409,6 +506,13 @@ macro_rules! split { ($(PwmChannelDisabled::<_, $C>::new(),)+) } } + #[cfg(not(feature = "gpio-f410"))] + impl SplitCapture for $TIM { + type CaptureChannels = ($(CaptureChannelDisabled<$TIM, $C>,)+); + fn split_capture() -> Self::CaptureChannels { + ($(CaptureChannelDisabled::<_, $C>::new(),)+) + } + } }; } @@ -529,7 +633,7 @@ macro_rules! hal { $(with_dmar!($TIM, $memsize);)? $( - impl WithPwmCommon for $TIM { + impl WithChannel for $TIM { const CH_NUMBER: u8 = $cnum; const COMP_CH_NUMBER: u8 = $cnum; @@ -560,7 +664,7 @@ macro_rules! hal { } #[inline(always)] - fn set_channel_polarity(c: u8, p: Polarity) { + fn set_pwm_channel_polarity(c: u8, p: Polarity) { let tim = unsafe { &*<$TIM>::ptr() }; if c < Self::CH_NUMBER { unsafe { bb::write(tim.ccer(), c*4 + 1, p == Polarity::ActiveLow); } @@ -568,12 +672,34 @@ macro_rules! hal { } #[inline(always)] - fn set_nchannel_polarity(c: u8, p: Polarity) { + fn set_pwm_nchannel_polarity(c: u8, p: Polarity) { let tim = unsafe { &*<$TIM>::ptr() }; if c < Self::COMP_CH_NUMBER { unsafe { bb::write(tim.ccer(), c*4 + 3, p == Polarity::ActiveLow); } } } + + #[inline(always)] + fn set_capture_channel_polarity(c: u8, p: CapturePolarity) { + let tim = unsafe { &*<$TIM>::ptr() }; + if c < Self::CH_NUMBER { + match p { + CapturePolarity::ActiveLow => { + unsafe { bb::write(tim.ccer(), c*4 + 3, false); } + unsafe { bb::write(tim.ccer(), c*4 + 1, true); } + } + CapturePolarity::ActiveHigh => { + unsafe { bb::write(tim.ccer(), c*4 + 3, false); } + unsafe { bb::write(tim.ccer(), c*4 + 1, false); } + } + CapturePolarity::ActiveBoth => { + unsafe { bb::write(tim.ccer(), c*4 + 3, true); } + unsafe { bb::write(tim.ccer(), c*4 + 1, true); } + } + } + + } + } } $( @@ -613,7 +739,7 @@ macro_rules! hal { } )? - with_pwm!($TIM: $cnum $(, $aoe)?); + with_output!($TIM: $cnum $(, $aoe)?); split!($TIM: $cnum); unsafe impl PeriAddress for CCR<$TIM, C> { #[inline(always)] @@ -648,16 +774,17 @@ macro_rules! with_dmar { }; } -macro_rules! with_pwm { - ($TIM:ty: [$($Cx:literal, $ccmrx_output:ident, $ocxpe:ident, $ocxm:ident;)+] $(, $aoe:ident)?) => { +macro_rules! with_output { + ($TIM:ty: [$($Cx:literal, $ccmrx_input:ident, $ccmrx_output:ident, $ccxs:ident, $dc:literal;)+] $(, $aoe:ident)?) => { impl WithPwm for $TIM { #[inline(always)] fn preload_output_channel_in_mode(&mut self, c: u8, mode: Ocm) { match c { $( $Cx => { + let c = c-$dc; self.$ccmrx_output() - .modify(|_, w| w.$ocxpe().set_bit().$ocxm().set(mode as _) ); + .modify(|_, w| w.ocpe(c).set_bit().ocm(c).set(mode as _) ); } )+ #[allow(unreachable_patterns)] @@ -668,8 +795,9 @@ macro_rules! with_pwm { match c { $( $Cx => { + let c = c-$dc; self.$ccmrx_output() - .modify(|_, w| w.$ocxpe().clear_bit().$ocxm().set(Ocm::Frozen as _) ); + .modify(|_, w| w.ocpe(c).clear_bit().ocm(c).set(Ocm::Frozen as _) ); } )+ #[allow(unreachable_patterns)] @@ -683,24 +811,75 @@ macro_rules! with_pwm { self.cr1().modify(|_, w| w.cen().set_bit()); } } + + impl WithCapture for $TIM { + #[inline(always)] + fn preload_capture(&mut self, c: u8, mode: CaptureMode) { + match c { + $( + $Cx => { + self.$ccmrx_input() + .modify(|_, w| unsafe { w.$ccxs().bits(mode as _) } ); + } + )+ + #[allow(unreachable_patterns)] + _ => {}, + } + } + + #[inline(always)] + fn prescaler_capture(&mut self, c: u8, psc: CapturePrescaler) { + match c { + $( + $Cx => { + let c = c-$dc; + self.$ccmrx_input() + .modify(|_, w| unsafe { w.icpsc(c).bits(psc as _) } ); + } + )+ + #[allow(unreachable_patterns)] + _ => {}, + } + } + + fn filter_capture(&mut self, c: u8, filter: CaptureFilter) { + match c { + $( + $Cx => { + let c = c-$dc; + self.$ccmrx_input() + .modify(|_, w| unsafe { w.icf(c).bits(filter as _) } ); + } + )+ + #[allow(unreachable_patterns)] + _ => {}, + } + } + + + #[inline(always)] + fn start_capture(&mut self) { + self.cr1().modify(|_, w| w.cen().set_bit()); + } + } }; ($TIM:ty: 1) => { - with_pwm!($TIM: [ - 0, ccmr1_output, oc1pe, oc1m; + with_output!($TIM: [ + 0, ccmr1_input, ccmr1_output, cc1s, 0; ]); }; ($TIM:ty: 2) => { - with_pwm!($TIM: [ - 0, ccmr1_output, oc1pe, oc1m; - 1, ccmr1_output, oc2pe, oc2m; + with_output!($TIM: [ + 0, ccmr1_input, ccmr1_output, cc1s, 0; + 1, ccmr1_input, ccmr1_output, cc2s, 0; ]); }; ($TIM:ty: 4 $(, $aoe:ident)?) => { - with_pwm!($TIM: [ - 0, ccmr1_output, oc1pe, oc1m; - 1, ccmr1_output, oc2pe, oc2m; - 2, ccmr2_output, oc3pe, oc3m; - 3, ccmr2_output, oc4pe, oc4m; + with_output!($TIM: [ + 0, ccmr1_input, ccmr1_output, cc1s, 0; + 1, ccmr1_input, ccmr1_output, cc2s, 0; + 2, ccmr2_input, ccmr2_output, cc3s, 2; + 3, ccmr2_input, ccmr2_output, cc4s, 2; ] $(, $aoe)?); }; } diff --git a/src/timer/capture.rs b/src/timer/capture.rs new file mode 100644 index 00000000..710e8c52 --- /dev/null +++ b/src/timer/capture.rs @@ -0,0 +1,261 @@ +//! Provides the core functionality of the Input Capture mode. +//! +//! The main way to enable the Input Capture mode is by calling +//! ```rust,ignore +//! Timer::new(dp.TIM5, &clocks).capture_hz(24.MHz()); +//! ``` +//! In the `capture_hz` method, the desired timer counter frequency is specified. +//! For high accuracy, it is recommended to use 32-bit timers (TIM2, TIM5) and to select the highest possible frequency, ideally the maximum frequency equal to the timer's clock frequency. +//! This returns a `CaptureHzManager` and a tuple of all `CaptureChannel`s supported by the timer. Additionally, the [`CaptureExt`] trait is implemented for `pac::TIMx` to simplify the creation of a new structure. +//! +//! ```rust,ignore +//! let (cc_manager, (cc_ch1, cc_ch2, ...)) = dp.TIM5.capture_hz(24.MHz(), &clocks); +//! ``` +//! +//! To enable a [`CaptureChannel`], you need to pass one or more valid pins supported by the channel using the `with` method. +//! +//! [`CaptureHzManager`] also provides additional methods for managing the Input Capture mode, such as `set_prescaler` and `set_filter`. + +use super::sealed::{Split, SplitCapture}; +use super::{ + CPin, CaptureFilter, CaptureMode, CapturePolarity, CapturePrescaler, Instance, Timer, + WithCapture, +}; +pub use super::{Ch, C1, C2, C3, C4}; +use crate::gpio::PushPull; +use crate::rcc::Rcc; +use core::ops::{Deref, DerefMut}; +use fugit::HertzU32 as Hertz; + +pub trait CaptureExt +where + Self: Sized + Instance + WithCapture + SplitCapture, +{ + fn capture_hz( + self, + freq: Hertz, + rcc: &mut Rcc, + ) -> (CaptureHzManager, Self::CaptureChannels); +} + +impl CaptureExt for TIM +where + Self: Sized + Instance + WithCapture + SplitCapture, +{ + fn capture_hz( + self, + time: Hertz, + rcc: &mut Rcc, + ) -> (CaptureHzManager, Self::CaptureChannels) { + Timer::new(self, rcc).capture_hz(time) + } +} + +impl Timer { + // At a timer clock frequency of 100 MHz, + // the frequency should be in the range from 2000 Hz to the timer clock frequency. + // It is recommended to use 32-bit timers (TIM2, TIM5). + pub fn capture_hz(mut self, freq: Hertz) -> (CaptureHzManager, TIM::CaptureChannels) { + // The reference manual is a bit ambiguous about when enabling this bit is really + // necessary, but since we MUST enable the preload for the output channels then we + // might as well enable for the auto-reload too + self.tim.enable_preload(true); + + let psc = self.clk.raw() / freq.raw(); + assert!(self.clk.raw() % freq.raw() == 0); + assert!( + psc <= u16::MAX.into(), + "PSC value {} exceeds 16-bit limit (65535)", + psc + ); + + self.tim.set_prescaler(psc as u16 - 1); + self.tim.set_auto_reload(TIM::max_auto_reload()).unwrap(); + + // Trigger update event to load the registers + self.tim.trigger_update(); + + self.tim.start_capture(); + + (CaptureHzManager { timer: self }, TIM::split_capture()) + } +} + +pub struct CaptureChannelDisabled { + pub(super) tim: TIM, +} + +impl CaptureChannelDisabled { + pub(crate) fn new() -> Self { + Self { + tim: unsafe { TIM::steal() }, + } + } +} +impl CaptureChannelDisabled +where + TIM: CPin, +{ + pub fn with( + mut self, + pin: impl Into>, + ) -> CaptureChannel { + self.tim.preload_capture(C, CaptureMode::InputCapture); + CaptureChannel { + tim: self.tim, + pin: pin.into(), + } + } +} + +pub struct CaptureChannel, const C: u8, const COMP: bool = false, Otype = PushPull> { + pub(super) tim: TIM, + pin: TIM::Ch, + // TODO: add complementary pins +} + +impl, const C: u8, const COMP: bool, Otype> + CaptureChannel +{ + pub const fn channel(&self) -> u8 { + C + } + pub fn release(mut self) -> (CaptureChannelDisabled, TIM::Ch) { + self.disable(); + (CaptureChannelDisabled { tim: self.tim }, self.pin) + } + pub fn erase(self) -> CaptureErasedChannel { + CaptureErasedChannel { + _tim: self.tim, + channel: C, + } + } + + pub fn set_prescaler(&mut self, psc: CapturePrescaler) { + self.tim.prescaler_capture(C, psc); + } + + pub fn set_filter(&mut self, filter: CaptureFilter) { + self.tim.filter_capture(C, filter); + } +} + +pub struct CaptureErasedChannel { + _tim: TIM, + channel: u8, +} + +impl CaptureErasedChannel { + pub const fn channel(&self) -> u8 { + self.channel + } +} + +macro_rules! ch_impl { + () => { + /// Disable input capture channel + #[inline] + pub fn disable(&mut self) { + TIM::enable_channel(self.channel(), false); + } + + /// Enable input capture channel + #[inline] + pub fn enable(&mut self) { + TIM::enable_channel(self.channel(), true); + } + + /// Get capture value + #[inline] + pub fn get_capture(&self) -> u32 { + TIM::read_cc_value(self.channel()) + } + + /// Set input capture channel polarity + #[inline] + pub fn set_polarity(&mut self, p: CapturePolarity) { + TIM::set_capture_channel_polarity(self.channel(), p); + } + }; +} + +impl, const C: u8, const COMP: bool, Otype> + CaptureChannel +{ + ch_impl!(); +} + +impl CaptureErasedChannel { + ch_impl!(); +} + +pub struct CaptureHzManager +where + TIM: Instance + WithCapture, +{ + pub(super) timer: Timer, +} + +impl CaptureHzManager +where + TIM: Instance + WithCapture + Split, +{ + pub fn release(mut self, _channels: TIM::Channels) -> Timer { + // stop timer + self.tim.cr1_reset(); + self.timer + } +} + +impl Deref for CaptureHzManager +where + TIM: Instance + WithCapture, +{ + type Target = Timer; + fn deref(&self) -> &Self::Target { + &self.timer + } +} + +impl DerefMut for CaptureHzManager +where + TIM: Instance + WithCapture, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.timer + } +} + +impl CaptureHzManager +where + TIM: Instance + WithCapture, +{ + /// Get the PWM frequency of the timer in Hertz + pub fn get_timer_clock(&self) -> u32 { + let clk = self.clk; + let psc = self.tim.read_prescaler() as u32; + + // The frequency of the timer counter increment + (clk / (psc + 1)).raw() + } + + /// Set the frequency of the timer counter increment + pub fn set_timer_clock(&mut self, freq: Hertz) { + let clk = self.clk; + let psc = clk.raw() / freq.raw(); + assert!(self.clk.raw() % freq.raw() == 0); + assert!( + psc <= u16::MAX.into(), + "PSC value {} exceeds 16-bit limit (65535)", + psc + ); + + self.tim.set_prescaler(psc as u16 - 1); + self.tim.set_auto_reload(TIM::max_auto_reload()).unwrap(); + self.tim.cnt_reset(); + } + + pub fn get_max_auto_reload(&mut self) -> u32 { + TIM::max_auto_reload() + } +} diff --git a/src/timer/pwm.rs b/src/timer/pwm.rs index cfd5a217..97031d8d 100644 --- a/src/timer/pwm.rs +++ b/src/timer/pwm.rs @@ -273,13 +273,13 @@ macro_rules! ch_impl { /// Set PWM channel polarity #[inline] pub fn set_polarity(&mut self, p: Polarity) { - TIM::set_channel_polarity(self.channel(), p); + TIM::set_pwm_channel_polarity(self.channel(), p); } /// Set complementary PWM channel polarity #[inline] pub fn set_complementary_polarity(&mut self, p: Polarity) { - TIM::set_nchannel_polarity(self.channel(), p); + TIM::set_pwm_nchannel_polarity(self.channel(), p); } }; }