From 222d6919fe1833d14c3f147b3eab202f23e9a6a3 Mon Sep 17 00:00:00 2001 From: Nilolay Date: Wed, 1 Jan 2025 23:21:49 +0200 Subject: [PATCH 1/7] Added support for Input Capture timer mode for frequency and pulse duration measurement --- Cargo.toml | 4 + examples/rtic2-timer-input-capture.rs | 78 ++++++++ src/timer.rs | 155 ++++++++++++++- src/timer/capture_compare.rs | 270 ++++++++++++++++++++++++++ 4 files changed, 504 insertions(+), 3 deletions(-) create mode 100644 examples/rtic2-timer-input-capture.rs create mode 100644 src/timer/capture_compare.rs diff --git a/Cargo.toml b/Cargo.toml index caeaab35..8a7598c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -782,3 +782,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..1e3e5592 --- /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::{ + CcChannel, CcHzManager, Event, Flag, Polarity, PwmChannel, Timer, + }, +}; + +use rtic::app; + +#[app(device = pac, dispatchers = [USART1], peripherals = true)] +mod app { + use super::*; + + #[shared] + struct Shared {} + + #[local] + struct Local { + tim5: CcHzManager, + ch1: CcChannel, + } + + #[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(); + + // Configuration of TIM2 in input capture mode + let (mut tim5, (ch1, ..)) = Timer::new(dp.TIM5, &clocks).capture_compare_hz(48000.kHz()); + let mut ch1 = ch1.with(gpioa.pa0); + tim5.listen(Event::C1); + + ch1.set_polarity(Polarity::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) { + let timer_clock = cx.local.tim5.get_timer_clock(); + + if cx.local.tim5.flags().contains(Flag::C1) { + let current_capture = cx.local.ch1.get_capture(); + + let delta = if current_capture >= *cx.local.prev_capture { + current_capture - *cx.local.prev_capture + } else { + (u32::MAX - *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 f5b2e619..4b986355 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -26,6 +26,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_compare; +#[cfg(not(feature = "gpio-f410"))] +pub use capture_compare::*; #[cfg(feature = "rtic1")] pub mod monotonic; #[cfg(feature = "rtic1")] @@ -87,6 +91,7 @@ pub const C4: u8 = 3; pub enum Polarity { ActiveHigh, ActiveLow, + ActiveBoth, } /// Output Idle state @@ -306,6 +311,18 @@ pub enum Ocm { PwmMode2 = 7, } +/// Capture/Compare mode +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum Ccm { + // Todo Output compare (not tested) + // OutputCompare = 0, + InputCapture = 1, + InvChannelInputCapture = 2, + TriggerInputCapture = 3, +} + // Center-aligned mode selection pub use pac::tim1::cr1::CMS as CenterAlignedMode; @@ -320,7 +337,7 @@ pub type CCR4 = CCR; pub struct DMAR(T); mod sealed { - use super::{BitFlags, CenterAlignedMode, Event, Flag, IdleState, Ocm, Polarity}; + use super::{BitFlags, Ccm, CenterAlignedMode, Event, Flag, IdleState, Ocm, Polarity}; pub trait General { type Width: Into + From; fn max_auto_reload() -> u32; @@ -359,6 +376,14 @@ mod sealed { fn set_nchannel_polarity(channel: u8, p: Polarity); } + pub trait WithCcCommon: General { + const CC_CH_NUMBER: u8; + const CC_COMP_CH_NUMBER: u8; + fn read_cc_value(channel: u8) -> u32; + fn enable_channel(channel: u8, b: bool); + fn set_channel_polarity(channel: u8, p: Polarity); + } + pub trait Advanced: WithPwmCommon { fn enable_nchannel(channel: u8, b: bool); fn set_dtg_value(value: u8); @@ -373,6 +398,11 @@ mod sealed { fn start_pwm(&mut self); } + pub trait WithCc: WithCcCommon { + fn preload_capture_compare(&mut self, c: u8, mode: Ccm); + fn start_capture_compare(&mut self); + } + pub trait MasterTimer: General { type Mms; fn master_mode(&mut self, mode: Self::Mms); @@ -382,15 +412,23 @@ mod sealed { type Channels; fn split() -> Self::Channels; } + + pub trait SplitCc { + type CcChannels; + fn split_cc() -> Self::CcChannels; + } } -pub(crate) use sealed::{Advanced, General, MasterTimer, WithPwm, WithPwmCommon}; +pub(crate) use sealed::{ + Advanced, General, MasterTimer, WithCc, WithCcCommon, WithPwm, + WithPwmCommon, +}; pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + rcc::BusTimerClock + General { } -use sealed::Split; +use sealed::{Split, SplitCc}; macro_rules! split { ($TIM:ty: 1) => { split!($TIM, C1); @@ -411,6 +449,26 @@ macro_rules! split { }; } +macro_rules! split_cc { + ($TIM:ty: 1) => { + split_cc!($TIM, C1); + }; + ($TIM:ty: 2) => { + split_cc!($TIM, C1, C2); + }; + ($TIM:ty: 4) => { + split_cc!($TIM, C1, C2, C3, C4); + }; + ($TIM:ty, $($C:ident),+) => { + impl SplitCc for $TIM { + type CcChannels = ($(CcChannelDisabled<$TIM, $C>,)+); + fn split_cc() -> Self::CcChannels { + ($(CcChannelDisabled::<_, $C>::new(),)+) + } + } + }; +} + macro_rules! hal { ($TIM:ty: [ $Timer:ident, @@ -580,6 +638,50 @@ macro_rules! hal { } } + impl WithCcCommon for $TIM { + const CC_CH_NUMBER: u8 = $cnum; + const CC_COMP_CH_NUMBER: u8 = $cnum; + #[inline(always)] + fn read_cc_value(c: u8) -> u32 { + let tim = unsafe { &*<$TIM>::ptr() }; + if c < Self::CC_CH_NUMBER { + tim.ccr(c as usize).read().bits() + } else { + 0 + } + } + + #[inline(always)] + fn enable_channel(c: u8, b: bool) { + let tim = unsafe { &*<$TIM>::ptr() }; + if c < Self::CC_CH_NUMBER { + unsafe { bb::write(tim.ccer(), c*4, b); } + } + } + + #[inline(always)] + fn set_channel_polarity(c: u8, p: Polarity) { + let tim = unsafe { &*<$TIM>::ptr() }; + if c < Self::CC_CH_NUMBER { + match p { + Polarity::ActiveLow => { + unsafe { bb::write(tim.ccer(), c*4 + 3, false); } + unsafe { bb::write(tim.ccer(), c*4 + 1, true); } + } + Polarity::ActiveHigh => { + unsafe { bb::write(tim.ccer(), c*4 + 3, false); } + unsafe { bb::write(tim.ccer(), c*4 + 1, false); } + } + Polarity::ActiveBoth => { + unsafe { bb::write(tim.ccer(), c*4 + 3, true); } + unsafe { bb::write(tim.ccer(), c*4 + 1, true); } + } + } + + } + } + } + $( impl Advanced for $TIM { fn enable_nchannel(c: u8, b: bool) { @@ -618,7 +720,9 @@ macro_rules! hal { )? with_pwm!($TIM: $cnum $(, $aoe)?); + with_cc!($TIM: $cnum $(, $aoe)?); split!($TIM: $cnum); + split_cc!($TIM: $cnum); unsafe impl PeriAddress for CCR<$TIM, C> { #[inline(always)] fn address(&self) -> u32 { @@ -709,6 +813,51 @@ macro_rules! with_pwm { }; } +macro_rules! with_cc { + ($TIM:ty: [$($Cx:literal, $ccmrx_output:ident, $ccxs:ident;)+] $(, $aoe:ident)?) => { + impl WithCc for $TIM { + #[inline(always)] + fn preload_capture_compare(&mut self, c: u8, mode: Ccm) { + match c { + $( + $Cx => { + self.$ccmrx_output() + .modify(|_, w| unsafe { w.$ccxs().bits(mode as _) } ); + } + )+ + #[allow(unreachable_patterns)] + _ => {}, + } + } + + #[inline(always)] + fn start_capture_compare(&mut self) { + // $(let $aoe = self.bdtr().modify(|_, w| w.aoe().set_bit());)? + self.cr1().modify(|_, w| w.cen().set_bit()); + } + } + }; + ($TIM:ty: 1) => { + with_cc!($TIM: [ + 0, ccmr1_output, cc1s; + ]); + }; + ($TIM:ty: 2) => { + with_cc!($TIM: [ + 0, ccmr1_output, cc1s; + 1, ccmr1_output, cc2s; + ]); + }; + ($TIM:ty: 4 $(, $aoe:ident)?) => { + with_cc!($TIM: [ + 0, ccmr1_output, cc1s; + 1, ccmr1_output, cc2s; + 2, ccmr2_output, cc3s; + 3, ccmr2_output, cc4s; + ] $(, $aoe)?); + }; +} + impl Timer { /// Initialize timer pub fn new(tim: TIM, clocks: &Clocks) -> Self { diff --git a/src/timer/capture_compare.rs b/src/timer/capture_compare.rs new file mode 100644 index 00000000..fd9ab705 --- /dev/null +++ b/src/timer/capture_compare.rs @@ -0,0 +1,270 @@ +use super::sealed::{Split, SplitCc}; +use super::{CPin, Ccm, Instance, Polarity, Timer, WithCc}; +pub use super::{Ch, C1, C2, C3, C4}; +use crate::gpio::PushPull; +use crate::rcc::Clocks; +use core::ops::{Deref, DerefMut}; +use fugit::HertzU32 as Hertz; + +pub trait CcExt +where + Self: Sized + Instance + WithCc + SplitCc, +{ + fn capture_compare_hz( + self, + freq: Hertz, + clocks: &Clocks, + ) -> (CcHzManager, Self::CcChannels); +} + +impl CcExt for TIM +where + Self: Sized + Instance + WithCc + SplitCc, +{ + fn capture_compare_hz( + self, + time: Hertz, + clocks: &Clocks, + ) -> (CcHzManager, Self::CcChannels) { + Timer::new(self, clocks).capture_compare_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_compare_hz( + mut self, + freq: Hertz, + ) -> (CcHzManager, TIM::CcChannels) { + // 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_compare(); + + (CcHzManager { timer: self }, TIM::split_cc()) + } +} + +pub struct CcChannelDisabled { + pub(super) tim: TIM, +} + +impl CcChannelDisabled { + pub(crate) fn new() -> Self { + Self { + tim: unsafe { TIM::steal() }, + } + } +} +impl + CcChannelDisabled +where + TIM: CPin, +{ + pub fn with( + mut self, + pin: impl Into>, + ) -> CcChannel { + self.tim.preload_capture_compare(C, Ccm::InputCapture); + CcChannel { + tim: self.tim, + lines: CaptureLines::One(pin.into()), + } + } +} + +#[derive(Debug)] +pub enum CaptureLines

{ + One(P), + Two(P, P), + Three(P, P, P), + Four(P, P, P, P), +} +impl

CaptureLines

{ + pub fn and(self, pin: P) -> Self { + match self { + Self::One(p) => Self::Two(p, pin), + Self::Two(p1, p2) => Self::Three(p1, p2, pin), + Self::Three(p1, p2, p3) => Self::Four(p1, p2, p3, pin), + Self::Four(_, _, _, _) => unreachable!(), + } + } +} + +pub struct CcChannel< + TIM: CPin, + const C: u8, + const COMP: bool = false, + Otype = PushPull, +> { + pub(super) tim: TIM, + lines: CaptureLines>, + // TODO: add complementary pins +} + +impl, const C: u8, const COMP: bool, Otype> + CcChannel +{ + pub const fn channel(&self) -> u8 { + C + } + pub fn release( + mut self, + ) -> ( + CcChannelDisabled, + CaptureLines>, + ) { + self.disable(); + (CcChannelDisabled { tim: self.tim }, self.lines) + } + pub fn erase(self) -> CaptureErasedChannel { + CaptureErasedChannel { + _tim: self.tim, + channel: C, + } + } +} +impl, const C: u8, const COMP: bool, Otype> + CcChannel +{ + pub fn with(self, pin: impl Into>) -> Self { + Self { + tim: self.tim, + lines: self.lines.and(pin.into()), + } + } +} + +pub struct CaptureErasedChannel { + _tim: TIM, + channel: u8, +} + +impl CaptureErasedChannel { + pub const fn channel(&self) -> u8 { + self.channel + } +} + +macro_rules! ch_impl { + () => { + /// Disable input capture/output compare channel + #[inline] + pub fn disable(&mut self) { + TIM::enable_channel(self.channel(), false); + } + + /// Enable input capture/output compare 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/Output compare channel polarity + #[inline] + pub fn set_polarity(&mut self, p: Polarity) { + TIM::set_channel_polarity(self.channel(), p); + } + }; +} + +impl, const C: u8, const COMP: bool, Otype> + CcChannel +{ + ch_impl!(); +} + +impl CaptureErasedChannel { + ch_impl!(); +} + +pub struct CcHzManager +where + TIM: Instance + WithCc, +{ + pub(super) timer: Timer, +} + +impl CcHzManager +where + TIM: Instance + WithCc + Split, +{ + pub fn release(mut self, _channels: TIM::Channels) -> Timer { + // stop timer + self.tim.cr1_reset(); + self.timer + } +} + +impl Deref for CcHzManager +where + TIM: Instance + WithCc, +{ + type Target = Timer; + fn deref(&self) -> &Self::Target { + &self.timer + } +} + +impl DerefMut for CcHzManager +where + TIM: Instance + WithCc, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.timer + } +} + +impl CcHzManager +where + TIM: Instance + WithCc, +{ + /// 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(1 << 16).unwrap(); + self.tim.cnt_reset(); + } +} From f3b531659a2423dca34889eb946fcc2db004ce88 Mon Sep 17 00:00:00 2001 From: Nilolay Date: Wed, 1 Jan 2025 23:52:11 +0200 Subject: [PATCH 2/7] Added support for Input Capture timer mode for frequency and pulse duration measurement --- examples/rtic2-timer-input-capture.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/rtic2-timer-input-capture.rs b/examples/rtic2-timer-input-capture.rs index 1e3e5592..bbb54e97 100644 --- a/examples/rtic2-timer-input-capture.rs +++ b/examples/rtic2-timer-input-capture.rs @@ -41,6 +41,8 @@ mod app { 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 TIM2 in input capture mode let (mut tim5, (ch1, ..)) = Timer::new(dp.TIM5, &clocks).capture_compare_hz(48000.kHz()); let mut ch1 = ch1.with(gpioa.pa0); From 2b625794b856102550b3c42120f87e9b76d6da59 Mon Sep 17 00:00:00 2001 From: Nilolay Date: Wed, 1 Jan 2025 23:54:45 +0200 Subject: [PATCH 3/7] fix comment --- examples/rtic2-timer-input-capture.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rtic2-timer-input-capture.rs b/examples/rtic2-timer-input-capture.rs index bbb54e97..a51998ce 100644 --- a/examples/rtic2-timer-input-capture.rs +++ b/examples/rtic2-timer-input-capture.rs @@ -43,7 +43,7 @@ mod app { // It is necessary to connect pins PA0 and PA5 through a resistor of 1 kΩ - 10 kΩ - // Configuration of TIM2 in input capture mode + // Configuration of TIM5 in input capture mode let (mut tim5, (ch1, ..)) = Timer::new(dp.TIM5, &clocks).capture_compare_hz(48000.kHz()); let mut ch1 = ch1.with(gpioa.pa0); tim5.listen(Event::C1); From 561999868091ae8654179049709cedf66f402062 Mon Sep 17 00:00:00 2001 From: Nilolay Date: Thu, 2 Jan 2025 00:12:48 +0200 Subject: [PATCH 4/7] add func --- examples/rtic2-timer-input-capture.rs | 6 +++--- src/timer/capture_compare.rs | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/rtic2-timer-input-capture.rs b/examples/rtic2-timer-input-capture.rs index a51998ce..bf8de3eb 100644 --- a/examples/rtic2-timer-input-capture.rs +++ b/examples/rtic2-timer-input-capture.rs @@ -58,15 +58,15 @@ mod app { #[task(binds = TIM5, local = [tim5, ch1, prev_capture: u32 = 0], priority = 3)] fn tim5_interrupt(cx: tim5_interrupt::Context) { - let timer_clock = cx.local.tim5.get_timer_clock(); - 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 { - (u32::MAX - *cx.local.prev_capture) + current_capture + (max_auto_reload - *cx.local.prev_capture) + current_capture }; let freq = timer_clock as f32 / delta as f32; diff --git a/src/timer/capture_compare.rs b/src/timer/capture_compare.rs index fd9ab705..6a52f1cc 100644 --- a/src/timer/capture_compare.rs +++ b/src/timer/capture_compare.rs @@ -264,7 +264,11 @@ where ); self.tim.set_prescaler(psc as u16 - 1); - self.tim.set_auto_reload(1 << 16).unwrap(); + 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() + } } From 2097b16968c3413019044ec751e8ef42171be7ad Mon Sep 17 00:00:00 2001 From: Nilolay Date: Thu, 2 Jan 2025 01:36:46 +0200 Subject: [PATCH 5/7] add function --- examples/rtic2-timer-input-capture.rs | 2 +- src/timer.rs | 106 ++++++++++++++++++++++---- src/timer/capture_compare.rs | 12 ++- 3 files changed, 104 insertions(+), 16 deletions(-) diff --git a/examples/rtic2-timer-input-capture.rs b/examples/rtic2-timer-input-capture.rs index bf8de3eb..2988df7a 100644 --- a/examples/rtic2-timer-input-capture.rs +++ b/examples/rtic2-timer-input-capture.rs @@ -44,7 +44,7 @@ mod app { // 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_compare_hz(48000.kHz()); + let (mut tim5, (ch1, ..)) = Timer::new(dp.TIM5, &clocks).capture_compare_hz(48.MHz()); let mut ch1 = ch1.with(gpioa.pa0); tim5.listen(Event::C1); diff --git a/src/timer.rs b/src/timer.rs index 4b986355..6d4abbd5 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -315,7 +315,7 @@ pub enum Ocm { #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] -pub enum Ccm { +pub enum CcMode { // Todo Output compare (not tested) // OutputCompare = 0, InputCapture = 1, @@ -323,6 +323,56 @@ pub enum Ccm { TriggerInputCapture = 3, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum CapturePrescaler { + No = 0, + Two = 1, + Four = 2, + 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; @@ -337,7 +387,7 @@ pub type CCR4 = CCR; pub struct DMAR(T); mod sealed { - use super::{BitFlags, Ccm, CenterAlignedMode, Event, Flag, IdleState, Ocm, Polarity}; + use super::{BitFlags, CaptureFilter, CapturePrescaler, CcMode, CenterAlignedMode, Event, Flag, IdleState, Ocm, Polarity}; pub trait General { type Width: Into + From; fn max_auto_reload() -> u32; @@ -399,7 +449,9 @@ mod sealed { } pub trait WithCc: WithCcCommon { - fn preload_capture_compare(&mut self, c: u8, mode: Ccm); + fn preload_capture_compare(&mut self, c: u8, mode: CcMode); + fn prescaler_capture(&mut self, c: u8, psc: CapturePrescaler); + fn filter_capture(&mut self, c: u8, filter: CaptureFilter); fn start_capture_compare(&mut self); } @@ -814,14 +866,14 @@ macro_rules! with_pwm { } macro_rules! with_cc { - ($TIM:ty: [$($Cx:literal, $ccmrx_output:ident, $ccxs:ident;)+] $(, $aoe:ident)?) => { + ($TIM:ty: [$($Cx:literal, $ccmrx_input:ident, $ccxs:ident, $icx_psc:ident, $icxf:ident;)+] $(, $aoe:ident)?) => { impl WithCc for $TIM { #[inline(always)] - fn preload_capture_compare(&mut self, c: u8, mode: Ccm) { + fn preload_capture_compare(&mut self, c: u8, mode: CcMode) { match c { $( $Cx => { - self.$ccmrx_output() + self.$ccmrx_input() .modify(|_, w| unsafe { w.$ccxs().bits(mode as _) } ); } )+ @@ -830,6 +882,34 @@ macro_rules! with_cc { } } + #[inline(always)] + fn prescaler_capture(&mut self, c: u8, psc: CapturePrescaler) { + match c { + $( + $Cx => { + self.$ccmrx_input() + .modify(|_, w| unsafe { w.$icx_psc().bits(psc as _) } ); + } + )+ + #[allow(unreachable_patterns)] + _ => {}, + } + } + + fn filter_capture(&mut self, c: u8, filter: CaptureFilter) { + match c { + $( + $Cx => { + self.$ccmrx_input() + .modify(|_, w| unsafe { w.$icxf().bits(filter as _) } ); + } + )+ + #[allow(unreachable_patterns)] + _ => {}, + } + } + + #[inline(always)] fn start_capture_compare(&mut self) { // $(let $aoe = self.bdtr().modify(|_, w| w.aoe().set_bit());)? @@ -839,21 +919,21 @@ macro_rules! with_cc { }; ($TIM:ty: 1) => { with_cc!($TIM: [ - 0, ccmr1_output, cc1s; + 0, ccmr1_input, cc1s, ic1psc, ic1f; ]); }; ($TIM:ty: 2) => { with_cc!($TIM: [ - 0, ccmr1_output, cc1s; - 1, ccmr1_output, cc2s; + 0, ccmr1_input, cc1s, ic1psc, ic1f; + 1, ccmr1_input, cc2s, ic2psc, ic2f; ]); }; ($TIM:ty: 4 $(, $aoe:ident)?) => { with_cc!($TIM: [ - 0, ccmr1_output, cc1s; - 1, ccmr1_output, cc2s; - 2, ccmr2_output, cc3s; - 3, ccmr2_output, cc4s; + 0, ccmr1_input, cc1s, ic1psc, ic1f; + 1, ccmr1_input, cc2s, ic2psc, ic2f; + 2, ccmr2_input, cc3s, ic3psc, ic3f; + 3, ccmr2_input, cc4s, ic4psc, ic4f; ] $(, $aoe)?); }; } diff --git a/src/timer/capture_compare.rs b/src/timer/capture_compare.rs index 6a52f1cc..4b8d2e23 100644 --- a/src/timer/capture_compare.rs +++ b/src/timer/capture_compare.rs @@ -1,5 +1,5 @@ use super::sealed::{Split, SplitCc}; -use super::{CPin, Ccm, Instance, Polarity, Timer, WithCc}; +use super::{CPin, CcMode, Instance, Polarity, Timer, WithCc, CapturePrescaler, CaptureFilter}; pub use super::{Ch, C1, C2, C3, C4}; use crate::gpio::PushPull; use crate::rcc::Clocks; @@ -83,7 +83,7 @@ where mut self, pin: impl Into>, ) -> CcChannel { - self.tim.preload_capture_compare(C, Ccm::InputCapture); + self.tim.preload_capture_compare(C, CcMode::InputCapture); CcChannel { tim: self.tim, lines: CaptureLines::One(pin.into()), @@ -141,6 +141,14 @@ impl, const C: u8, const COMP: bool, Otype> 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); + } } impl, const C: u8, const COMP: bool, Otype> CcChannel From 65e96ee1728f446eaee5c1437a416f59f20b70c7 Mon Sep 17 00:00:00 2001 From: Nilolay Date: Thu, 2 Jan 2025 13:54:32 +0200 Subject: [PATCH 6/7] refactoring --- examples/rtic2-timer-input-capture.rs | 10 +- src/timer.rs | 137 +++++++------------ src/timer/{capture_compare.rs => capture.rs} | 122 +++++++++-------- src/timer/pwm.rs | 4 +- 4 files changed, 120 insertions(+), 153 deletions(-) rename src/timer/{capture_compare.rs => capture.rs} (58%) diff --git a/examples/rtic2-timer-input-capture.rs b/examples/rtic2-timer-input-capture.rs index 2988df7a..8e058878 100644 --- a/examples/rtic2-timer-input-capture.rs +++ b/examples/rtic2-timer-input-capture.rs @@ -7,9 +7,7 @@ use stm32f4xx_hal::{ pac, pac::{TIM2, TIM5}, prelude::*, - timer::{ - CcChannel, CcHzManager, Event, Flag, Polarity, PwmChannel, Timer, - }, + timer::{CaptureChannel, CaptureHzManager, Event, Flag, Polarity, PwmChannel, Timer}, }; use rtic::app; @@ -23,8 +21,8 @@ mod app { #[local] struct Local { - tim5: CcHzManager, - ch1: CcChannel, + tim5: CaptureHzManager, + ch1: CaptureChannel, } #[init] @@ -44,7 +42,7 @@ mod app { // 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_compare_hz(48.MHz()); + let (mut tim5, (ch1, ..)) = Timer::new(dp.TIM5, &clocks).capture_hz(48.MHz()); let mut ch1 = ch1.with(gpioa.pa0); tim5.listen(Event::C1); diff --git a/src/timer.rs b/src/timer.rs index 6d4abbd5..97bc9d28 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -27,9 +27,9 @@ pub mod pwm_input; #[cfg(not(feature = "gpio-f410"))] pub use pwm_input::PwmInput; #[cfg(not(feature = "gpio-f410"))] -pub mod capture_compare; +pub mod capture; #[cfg(not(feature = "gpio-f410"))] -pub use capture_compare::*; +pub use capture::*; #[cfg(feature = "rtic1")] pub mod monotonic; #[cfg(feature = "rtic1")] @@ -311,25 +311,32 @@ pub enum Ocm { PwmMode2 = 7, } -/// Capture/Compare mode #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] -pub enum CcMode { - // Todo Output compare (not tested) - // OutputCompare = 0, +/// 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, - TriggerInputCapture = 3, } #[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, } @@ -372,7 +379,6 @@ pub enum CaptureFilter { FdtsDiv32N8, } - // Center-aligned mode selection pub use pac::tim1::cr1::CMS as CenterAlignedMode; @@ -387,7 +393,10 @@ pub type CCR4 = CCR; pub struct DMAR(T); mod sealed { - use super::{BitFlags, CaptureFilter, CapturePrescaler, CcMode, CenterAlignedMode, Event, Flag, IdleState, Ocm, Polarity}; + use super::{ + BitFlags, CaptureFilter, CaptureMode, CapturePrescaler, CenterAlignedMode, Event, Flag, + IdleState, Ocm, Polarity, + }; pub trait General { type Width: Into + From; fn max_auto_reload() -> u32; @@ -416,25 +425,19 @@ mod sealed { fn cnt_reset(&mut self); } - pub trait WithPwmCommon: General { + pub trait WithTimerCommon: 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); - pub trait WithCcCommon: General { - const CC_CH_NUMBER: u8; - const CC_COMP_CH_NUMBER: u8; - fn read_cc_value(channel: u8) -> u32; - fn enable_channel(channel: u8, b: bool); - fn set_channel_polarity(channel: u8, p: Polarity); + fn set_capture_channel_polarity(channel: u8, p: Polarity); } - pub trait Advanced: WithPwmCommon { + pub trait Advanced: WithTimerCommon { fn enable_nchannel(channel: u8, b: bool); fn set_dtg_value(value: u8); fn read_dtg_value() -> u8; @@ -442,17 +445,17 @@ mod sealed { fn set_cms(mode: CenterAlignedMode); } - pub trait WithPwm: WithPwmCommon { + pub trait WithPwm: WithTimerCommon { 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 WithCc: WithCcCommon { - fn preload_capture_compare(&mut self, c: u8, mode: CcMode); + pub trait WithCapture: WithTimerCommon { + 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_compare(&mut self); + fn start_capture(&mut self); } pub trait MasterTimer: General { @@ -465,22 +468,19 @@ mod sealed { fn split() -> Self::Channels; } - pub trait SplitCc { - type CcChannels; - fn split_cc() -> Self::CcChannels; + pub trait SplitCapture { + type CaptureChannels; + fn split_capture() -> Self::CaptureChannels; } } -pub(crate) use sealed::{ - Advanced, General, MasterTimer, WithCc, WithCcCommon, WithPwm, - WithPwmCommon, -}; +pub(crate) use sealed::{Advanced, General, MasterTimer, WithCapture, WithPwm, WithTimerCommon}; pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + rcc::BusTimerClock + General { } -use sealed::{Split, SplitCc}; +use sealed::{Split, SplitCapture}; macro_rules! split { ($TIM:ty: 1) => { split!($TIM, C1); @@ -498,24 +498,10 @@ macro_rules! split { ($(PwmChannelDisabled::<_, $C>::new(),)+) } } - }; -} - -macro_rules! split_cc { - ($TIM:ty: 1) => { - split_cc!($TIM, C1); - }; - ($TIM:ty: 2) => { - split_cc!($TIM, C1, C2); - }; - ($TIM:ty: 4) => { - split_cc!($TIM, C1, C2, C3, C4); - }; - ($TIM:ty, $($C:ident),+) => { - impl SplitCc for $TIM { - type CcChannels = ($(CcChannelDisabled<$TIM, $C>,)+); - fn split_cc() -> Self::CcChannels { - ($(CcChannelDisabled::<_, $C>::new(),)+) + impl SplitCapture for $TIM { + type CaptureChannels = ($(CaptureChannelDisabled<$TIM, $C>,)+); + fn split_capture() -> Self::CaptureChannels { + ($(CaptureChannelDisabled::<_, $C>::new(),)+) } } }; @@ -643,7 +629,7 @@ macro_rules! hal { $(with_dmar!($TIM, $memsize);)? $( - impl WithPwmCommon for $TIM { + impl WithTimerCommon for $TIM { const CH_NUMBER: u8 = $cnum; const COMP_CH_NUMBER: u8 = $cnum; @@ -674,7 +660,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); } @@ -682,39 +668,17 @@ 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); } } } - } - - impl WithCcCommon for $TIM { - const CC_CH_NUMBER: u8 = $cnum; - const CC_COMP_CH_NUMBER: u8 = $cnum; - #[inline(always)] - fn read_cc_value(c: u8) -> u32 { - let tim = unsafe { &*<$TIM>::ptr() }; - if c < Self::CC_CH_NUMBER { - tim.ccr(c as usize).read().bits() - } else { - 0 - } - } #[inline(always)] - fn enable_channel(c: u8, b: bool) { + fn set_capture_channel_polarity(c: u8, p: Polarity) { let tim = unsafe { &*<$TIM>::ptr() }; - if c < Self::CC_CH_NUMBER { - unsafe { bb::write(tim.ccer(), c*4, b); } - } - } - - #[inline(always)] - fn set_channel_polarity(c: u8, p: Polarity) { - let tim = unsafe { &*<$TIM>::ptr() }; - if c < Self::CC_CH_NUMBER { + if c < Self::CH_NUMBER { match p { Polarity::ActiveLow => { unsafe { bb::write(tim.ccer(), c*4 + 3, false); } @@ -772,9 +736,8 @@ macro_rules! hal { )? with_pwm!($TIM: $cnum $(, $aoe)?); - with_cc!($TIM: $cnum $(, $aoe)?); + with_capture!($TIM: $cnum $(, $aoe)?); split!($TIM: $cnum); - split_cc!($TIM: $cnum); unsafe impl PeriAddress for CCR<$TIM, C> { #[inline(always)] fn address(&self) -> u32 { @@ -865,11 +828,11 @@ macro_rules! with_pwm { }; } -macro_rules! with_cc { +macro_rules! with_capture { ($TIM:ty: [$($Cx:literal, $ccmrx_input:ident, $ccxs:ident, $icx_psc:ident, $icxf:ident;)+] $(, $aoe:ident)?) => { - impl WithCc for $TIM { + impl WithCapture for $TIM { #[inline(always)] - fn preload_capture_compare(&mut self, c: u8, mode: CcMode) { + fn preload_capture(&mut self, c: u8, mode: CaptureMode) { match c { $( $Cx => { @@ -908,28 +871,28 @@ macro_rules! with_cc { _ => {}, } } - + #[inline(always)] - fn start_capture_compare(&mut self) { + fn start_capture(&mut self) { // $(let $aoe = self.bdtr().modify(|_, w| w.aoe().set_bit());)? self.cr1().modify(|_, w| w.cen().set_bit()); } } }; ($TIM:ty: 1) => { - with_cc!($TIM: [ + with_capture!($TIM: [ 0, ccmr1_input, cc1s, ic1psc, ic1f; ]); }; ($TIM:ty: 2) => { - with_cc!($TIM: [ + with_capture!($TIM: [ 0, ccmr1_input, cc1s, ic1psc, ic1f; 1, ccmr1_input, cc2s, ic2psc, ic2f; ]); }; ($TIM:ty: 4 $(, $aoe:ident)?) => { - with_cc!($TIM: [ + with_capture!($TIM: [ 0, ccmr1_input, cc1s, ic1psc, ic1f; 1, ccmr1_input, cc2s, ic2psc, ic2f; 2, ccmr2_input, cc3s, ic3psc, ic3f; diff --git a/src/timer/capture_compare.rs b/src/timer/capture.rs similarity index 58% rename from src/timer/capture_compare.rs rename to src/timer/capture.rs index 4b8d2e23..02bfdbf2 100644 --- a/src/timer/capture_compare.rs +++ b/src/timer/capture.rs @@ -1,43 +1,60 @@ -use super::sealed::{Split, SplitCc}; -use super::{CPin, CcMode, Instance, Polarity, Timer, WithCc, CapturePrescaler, CaptureFilter}; +//! 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, CapturePrescaler, Instance, Polarity, Timer, WithCapture, +}; pub use super::{Ch, C1, C2, C3, C4}; use crate::gpio::PushPull; use crate::rcc::Clocks; use core::ops::{Deref, DerefMut}; use fugit::HertzU32 as Hertz; -pub trait CcExt +pub trait CaptureExt where - Self: Sized + Instance + WithCc + SplitCc, + Self: Sized + Instance + WithCapture + SplitCapture, { - fn capture_compare_hz( + fn capture_hz( self, freq: Hertz, clocks: &Clocks, - ) -> (CcHzManager, Self::CcChannels); + ) -> (CaptureHzManager, Self::CaptureChannels); } -impl CcExt for TIM +impl CaptureExt for TIM where - Self: Sized + Instance + WithCc + SplitCc, + Self: Sized + Instance + WithCapture + SplitCapture, { - fn capture_compare_hz( + fn capture_hz( self, time: Hertz, clocks: &Clocks, - ) -> (CcHzManager, Self::CcChannels) { - Timer::new(self, clocks).capture_compare_hz(time) + ) -> (CaptureHzManager, Self::CaptureChannels) { + Timer::new(self, clocks).capture_hz(time) } } -impl Timer { +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_compare_hz( - mut self, - freq: Hertz, - ) -> (CcHzManager, TIM::CcChannels) { + 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 @@ -57,34 +74,33 @@ impl Timer { // Trigger update event to load the registers self.tim.trigger_update(); - self.tim.start_capture_compare(); + self.tim.start_capture(); - (CcHzManager { timer: self }, TIM::split_cc()) + (CaptureHzManager { timer: self }, TIM::split_capture()) } } -pub struct CcChannelDisabled { +pub struct CaptureChannelDisabled { pub(super) tim: TIM, } -impl CcChannelDisabled { +impl CaptureChannelDisabled { pub(crate) fn new() -> Self { Self { tim: unsafe { TIM::steal() }, } } } -impl - CcChannelDisabled +impl CaptureChannelDisabled where TIM: CPin, { pub fn with( mut self, pin: impl Into>, - ) -> CcChannel { - self.tim.preload_capture_compare(C, CcMode::InputCapture); - CcChannel { + ) -> CaptureChannel { + self.tim.preload_capture(C, CaptureMode::InputCapture); + CaptureChannel { tim: self.tim, lines: CaptureLines::One(pin.into()), } @@ -109,31 +125,21 @@ impl

CaptureLines

{ } } -pub struct CcChannel< - TIM: CPin, - const C: u8, - const COMP: bool = false, - Otype = PushPull, -> { +pub struct CaptureChannel, const C: u8, const COMP: bool = false, Otype = PushPull> { pub(super) tim: TIM, lines: CaptureLines>, // TODO: add complementary pins } -impl, const C: u8, const COMP: bool, Otype> - CcChannel +impl, const C: u8, const COMP: bool, Otype> + CaptureChannel { pub const fn channel(&self) -> u8 { C } - pub fn release( - mut self, - ) -> ( - CcChannelDisabled, - CaptureLines>, - ) { + pub fn release(mut self) -> (CaptureChannelDisabled, CaptureLines>) { self.disable(); - (CcChannelDisabled { tim: self.tim }, self.lines) + (CaptureChannelDisabled { tim: self.tim }, self.lines) } pub fn erase(self) -> CaptureErasedChannel { CaptureErasedChannel { @@ -151,7 +157,7 @@ impl, const C: u8, const COMP: bool, Otype> } } impl, const C: u8, const COMP: bool, Otype> - CcChannel + CaptureChannel { pub fn with(self, pin: impl Into>) -> Self { Self { @@ -174,13 +180,13 @@ impl CaptureErasedChannel { macro_rules! ch_impl { () => { - /// Disable input capture/output compare channel + /// Disable input capture channel #[inline] pub fn disable(&mut self) { TIM::enable_channel(self.channel(), false); } - /// Enable input capture/output compare channel + /// Enable input capture channel #[inline] pub fn enable(&mut self) { TIM::enable_channel(self.channel(), true); @@ -192,34 +198,34 @@ macro_rules! ch_impl { TIM::read_cc_value(self.channel()) } - /// Set Input capture/Output compare channel polarity + /// Set input capture channel polarity #[inline] pub fn set_polarity(&mut self, p: Polarity) { - TIM::set_channel_polarity(self.channel(), p); + TIM::set_capture_channel_polarity(self.channel(), p); } }; } -impl, const C: u8, const COMP: bool, Otype> - CcChannel +impl, const C: u8, const COMP: bool, Otype> + CaptureChannel { ch_impl!(); } -impl CaptureErasedChannel { +impl CaptureErasedChannel { ch_impl!(); } -pub struct CcHzManager +pub struct CaptureHzManager where - TIM: Instance + WithCc, + TIM: Instance + WithCapture, { pub(super) timer: Timer, } -impl CcHzManager +impl CaptureHzManager where - TIM: Instance + WithCc + Split, + TIM: Instance + WithCapture + Split, { pub fn release(mut self, _channels: TIM::Channels) -> Timer { // stop timer @@ -228,9 +234,9 @@ where } } -impl Deref for CcHzManager +impl Deref for CaptureHzManager where - TIM: Instance + WithCc, + TIM: Instance + WithCapture, { type Target = Timer; fn deref(&self) -> &Self::Target { @@ -238,18 +244,18 @@ where } } -impl DerefMut for CcHzManager +impl DerefMut for CaptureHzManager where - TIM: Instance + WithCc, + TIM: Instance + WithCapture, { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.timer } } -impl CcHzManager +impl CaptureHzManager where - TIM: Instance + WithCc, + TIM: Instance + WithCapture, { /// Get the PWM frequency of the timer in Hertz pub fn get_timer_clock(&self) -> u32 { diff --git a/src/timer/pwm.rs b/src/timer/pwm.rs index 0943d15a..0ef72644 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); } }; } From 422772b98805829f914e68d3861feff6592809da Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 7 Jan 2025 14:06:05 +0300 Subject: [PATCH 7/7] remove Lines --- src/timer.rs | 1 + src/timer/capture.rs | 38 +++++--------------------------------- 2 files changed, 6 insertions(+), 33 deletions(-) diff --git a/src/timer.rs b/src/timer.rs index 97bc9d28..30bce86c 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -498,6 +498,7 @@ 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 { diff --git a/src/timer/capture.rs b/src/timer/capture.rs index 02bfdbf2..4576a40b 100644 --- a/src/timer/capture.rs +++ b/src/timer/capture.rs @@ -5,7 +5,7 @@ //! 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. +//! 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 @@ -102,32 +102,14 @@ where self.tim.preload_capture(C, CaptureMode::InputCapture); CaptureChannel { tim: self.tim, - lines: CaptureLines::One(pin.into()), - } - } -} - -#[derive(Debug)] -pub enum CaptureLines

{ - One(P), - Two(P, P), - Three(P, P, P), - Four(P, P, P, P), -} -impl

CaptureLines

{ - pub fn and(self, pin: P) -> Self { - match self { - Self::One(p) => Self::Two(p, pin), - Self::Two(p1, p2) => Self::Three(p1, p2, pin), - Self::Three(p1, p2, p3) => Self::Four(p1, p2, p3, pin), - Self::Four(_, _, _, _) => unreachable!(), + pin: pin.into(), } } } pub struct CaptureChannel, const C: u8, const COMP: bool = false, Otype = PushPull> { pub(super) tim: TIM, - lines: CaptureLines>, + pin: TIM::Ch, // TODO: add complementary pins } @@ -137,9 +119,9 @@ impl, const C: u8, const COMP: bool, Otype pub const fn channel(&self) -> u8 { C } - pub fn release(mut self) -> (CaptureChannelDisabled, CaptureLines>) { + pub fn release(mut self) -> (CaptureChannelDisabled, TIM::Ch) { self.disable(); - (CaptureChannelDisabled { tim: self.tim }, self.lines) + (CaptureChannelDisabled { tim: self.tim }, self.pin) } pub fn erase(self) -> CaptureErasedChannel { CaptureErasedChannel { @@ -156,16 +138,6 @@ impl, const C: u8, const COMP: bool, Otype self.tim.filter_capture(C, filter); } } -impl, const C: u8, const COMP: bool, Otype> - CaptureChannel -{ - pub fn with(self, pin: impl Into>) -> Self { - Self { - tim: self.tim, - lines: self.lines.and(pin.into()), - } - } -} pub struct CaptureErasedChannel { _tim: TIM,