stm32f4xx_hal/timer/
capture.rs

1//! Provides the core functionality of the Input Capture mode.
2//!
3//! The main way to enable the Input Capture mode is by calling
4//! ```rust,ignore
5//! Timer::new(dp.TIM5, &clocks).capture_hz(24.MHz());
6//! ```
7//! In the `capture_hz` method, the desired timer counter frequency is specified.
8//! 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.
9//! 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.
10//!
11//! ```rust,ignore
12//! let (cc_manager, (cc_ch1, cc_ch2, ...)) = dp.TIM5.capture_hz(24.MHz(), &clocks);
13//! ```
14//!
15//! To enable a [`CaptureChannel`], you need to pass one or more valid pins supported by the channel using the `with` method.
16//!
17//! [`CaptureHzManager`] also provides additional methods for managing the Input Capture mode, such as `set_prescaler` and `set_filter`.
18
19use super::sealed::{Split, SplitCapture};
20use super::{
21    CPin, CaptureFilter, CaptureMode, CapturePolarity, CapturePrescaler, Instance, Timer,
22    WithCapture,
23};
24pub use super::{Ch, C1, C2, C3, C4};
25use crate::gpio::PushPull;
26use crate::rcc::Rcc;
27use core::ops::{Deref, DerefMut};
28use fugit::HertzU32 as Hertz;
29
30pub trait CaptureExt
31where
32    Self: Sized + Instance + WithCapture + SplitCapture,
33{
34    fn capture_hz(
35        self,
36        freq: Hertz,
37        rcc: &mut Rcc,
38    ) -> (CaptureHzManager<Self>, Self::CaptureChannels);
39}
40
41impl<TIM> CaptureExt for TIM
42where
43    Self: Sized + Instance + WithCapture + SplitCapture,
44{
45    fn capture_hz(
46        self,
47        time: Hertz,
48        rcc: &mut Rcc,
49    ) -> (CaptureHzManager<Self>, Self::CaptureChannels) {
50        Timer::new(self, rcc).capture_hz(time)
51    }
52}
53
54impl<TIM: Instance + WithCapture + SplitCapture> Timer<TIM> {
55    // At a timer clock frequency of 100 MHz,
56    // the frequency should be in the range from 2000 Hz to the timer clock frequency.
57    // It is recommended to use 32-bit timers (TIM2, TIM5).
58    pub fn capture_hz(mut self, freq: Hertz) -> (CaptureHzManager<TIM>, TIM::CaptureChannels) {
59        // The reference manual is a bit ambiguous about when enabling this bit is really
60        // necessary, but since we MUST enable the preload for the output channels then we
61        // might as well enable for the auto-reload too
62        self.tim.enable_preload(true);
63
64        let psc = self.clk.raw() / freq.raw();
65        assert!(self.clk.raw() % freq.raw() == 0);
66        assert!(
67            psc <= u16::MAX.into(),
68            "PSC value {} exceeds 16-bit limit (65535)",
69            psc
70        );
71
72        self.tim.set_prescaler(psc as u16 - 1);
73        self.tim.set_auto_reload(TIM::max_auto_reload()).unwrap();
74
75        // Trigger update event to load the registers
76        self.tim.trigger_update();
77
78        self.tim.start_capture();
79
80        (CaptureHzManager { timer: self }, TIM::split_capture())
81    }
82}
83
84pub struct CaptureChannelDisabled<TIM, const C: u8> {
85    pub(super) tim: TIM,
86}
87
88impl<TIM: crate::Steal, const C: u8> CaptureChannelDisabled<TIM, C> {
89    pub(crate) fn new() -> Self {
90        Self {
91            tim: unsafe { TIM::steal() },
92        }
93    }
94}
95impl<TIM: Instance + WithCapture + crate::Steal, const C: u8> CaptureChannelDisabled<TIM, C>
96where
97    TIM: CPin<C>,
98{
99    pub fn with(
100        mut self,
101        pin: impl Into<TIM::Ch<PushPull>>,
102    ) -> CaptureChannel<TIM, C, false, PushPull> {
103        self.tim.preload_capture(C, CaptureMode::InputCapture);
104        CaptureChannel {
105            tim: self.tim,
106            pin: pin.into(),
107        }
108    }
109}
110
111pub struct CaptureChannel<TIM: CPin<C>, const C: u8, const COMP: bool = false, Otype = PushPull> {
112    pub(super) tim: TIM,
113    pin: TIM::Ch<Otype>,
114    // TODO: add complementary pins
115}
116
117impl<TIM: Instance + WithCapture + CPin<C>, const C: u8, const COMP: bool, Otype>
118    CaptureChannel<TIM, C, COMP, Otype>
119{
120    pub const fn channel(&self) -> u8 {
121        C
122    }
123    pub fn release(mut self) -> (CaptureChannelDisabled<TIM, C>, TIM::Ch<Otype>) {
124        self.disable();
125        (CaptureChannelDisabled { tim: self.tim }, self.pin)
126    }
127    pub fn erase(self) -> CaptureErasedChannel<TIM> {
128        CaptureErasedChannel {
129            _tim: self.tim,
130            channel: C,
131        }
132    }
133
134    pub fn set_prescaler(&mut self, psc: CapturePrescaler) {
135        self.tim.prescaler_capture(C, psc);
136    }
137
138    pub fn set_filter(&mut self, filter: CaptureFilter) {
139        self.tim.filter_capture(C, filter);
140    }
141}
142
143pub struct CaptureErasedChannel<TIM> {
144    _tim: TIM,
145    channel: u8,
146}
147
148impl<TIM> CaptureErasedChannel<TIM> {
149    pub const fn channel(&self) -> u8 {
150        self.channel
151    }
152}
153
154macro_rules! ch_impl {
155    () => {
156        /// Disable input capture channel
157        #[inline]
158        pub fn disable(&mut self) {
159            TIM::enable_channel(self.channel(), false);
160        }
161
162        /// Enable input capture channel
163        #[inline]
164        pub fn enable(&mut self) {
165            TIM::enable_channel(self.channel(), true);
166        }
167
168        /// Get capture value
169        #[inline]
170        pub fn get_capture(&self) -> u32 {
171            TIM::read_cc_value(self.channel())
172        }
173
174        /// Set input capture channel polarity
175        #[inline]
176        pub fn set_polarity(&mut self, p: CapturePolarity) {
177            TIM::set_capture_channel_polarity(self.channel(), p);
178        }
179    };
180}
181
182impl<TIM: Instance + WithCapture + CPin<C>, const C: u8, const COMP: bool, Otype>
183    CaptureChannel<TIM, C, COMP, Otype>
184{
185    ch_impl!();
186}
187
188impl<TIM: Instance + WithCapture> CaptureErasedChannel<TIM> {
189    ch_impl!();
190}
191
192pub struct CaptureHzManager<TIM>
193where
194    TIM: Instance + WithCapture,
195{
196    pub(super) timer: Timer<TIM>,
197}
198
199impl<TIM> CaptureHzManager<TIM>
200where
201    TIM: Instance + WithCapture + Split,
202{
203    pub fn release(mut self, _channels: TIM::Channels) -> Timer<TIM> {
204        // stop timer
205        self.tim.cr1_reset();
206        self.timer
207    }
208}
209
210impl<TIM> Deref for CaptureHzManager<TIM>
211where
212    TIM: Instance + WithCapture,
213{
214    type Target = Timer<TIM>;
215    fn deref(&self) -> &Self::Target {
216        &self.timer
217    }
218}
219
220impl<TIM> DerefMut for CaptureHzManager<TIM>
221where
222    TIM: Instance + WithCapture,
223{
224    fn deref_mut(&mut self) -> &mut Self::Target {
225        &mut self.timer
226    }
227}
228
229impl<TIM> CaptureHzManager<TIM>
230where
231    TIM: Instance + WithCapture,
232{
233    /// Get the PWM frequency of the timer in Hertz
234    pub fn get_timer_clock(&self) -> u32 {
235        let clk = self.clk;
236        let psc = self.tim.read_prescaler() as u32;
237
238        // The frequency of the timer counter increment
239        (clk / (psc + 1)).raw()
240    }
241
242    /// Set the frequency of the timer counter increment
243    pub fn set_timer_clock(&mut self, freq: Hertz) {
244        let clk = self.clk;
245        let psc = clk.raw() / freq.raw();
246        assert!(self.clk.raw() % freq.raw() == 0);
247        assert!(
248            psc <= u16::MAX.into(),
249            "PSC value {} exceeds 16-bit limit (65535)",
250            psc
251        );
252
253        self.tim.set_prescaler(psc as u16 - 1);
254        self.tim.set_auto_reload(TIM::max_auto_reload()).unwrap();
255        self.tim.cnt_reset();
256    }
257
258    pub fn get_max_auto_reload(&mut self) -> u32 {
259        TIM::max_auto_reload()
260    }
261}