embassy_stm32/timer/
input_capture.rs

1//! Input capture driver.
2
3use core::future::Future;
4use core::marker::PhantomData;
5use core::pin::Pin;
6use core::task::{Context, Poll};
7
8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
9use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin};
10pub use super::{Ch1, Ch2, Ch3, Ch4};
11use crate::gpio::{AfType, AnyPin, Pull};
12use crate::interrupt::typelevel::{Binding, Interrupt};
13use crate::time::Hertz;
14use crate::timer::TimerChannel;
15use crate::Peri;
16
17/// Capture pin wrapper.
18///
19/// This wraps a pin to make it usable with capture.
20pub struct CapturePin<'d, T, C> {
21    _pin: Peri<'d, AnyPin>,
22    phantom: PhantomData<(T, C)>,
23}
24impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> {
25    /// Create a new capture pin instance.
26    pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, pull: Pull) -> Self {
27        pin.set_as_af(pin.af_num(), AfType::input(pull));
28        CapturePin {
29            _pin: pin.into(),
30            phantom: PhantomData,
31        }
32    }
33}
34
35/// Input capture driver.
36pub struct InputCapture<'d, T: GeneralInstance4Channel> {
37    inner: Timer<'d, T>,
38}
39
40impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
41    /// Create a new input capture driver.
42    pub fn new(
43        tim: Peri<'d, T>,
44        _ch1: Option<CapturePin<'d, T, Ch1>>,
45        _ch2: Option<CapturePin<'d, T, Ch2>>,
46        _ch3: Option<CapturePin<'d, T, Ch3>>,
47        _ch4: Option<CapturePin<'d, T, Ch4>>,
48        _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
49        freq: Hertz,
50        counting_mode: CountingMode,
51    ) -> Self {
52        Self::new_inner(tim, freq, counting_mode)
53    }
54
55    fn new_inner(tim: Peri<'d, T>, freq: Hertz, counting_mode: CountingMode) -> Self {
56        let mut this = Self { inner: Timer::new(tim) };
57
58        this.inner.set_counting_mode(counting_mode);
59        this.inner.set_tick_freq(freq);
60        this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
61        this.inner.start();
62
63        // enable NVIC interrupt
64        T::CaptureCompareInterrupt::unpend();
65        unsafe { T::CaptureCompareInterrupt::enable() };
66
67        this
68    }
69
70    /// Enable the given channel.
71    pub fn enable(&mut self, channel: Channel) {
72        self.inner.enable_channel(channel, true);
73    }
74
75    /// Disable the given channel.
76    pub fn disable(&mut self, channel: Channel) {
77        self.inner.enable_channel(channel, false);
78    }
79
80    /// Check whether given channel is enabled
81    pub fn is_enabled(&self, channel: Channel) -> bool {
82        self.inner.get_channel_enable_state(channel)
83    }
84
85    /// Set the input capture mode for a given channel.
86    pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
87        self.inner.set_input_capture_mode(channel, mode);
88    }
89
90    /// Set input TI selection.
91    pub fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
92        self.inner.set_input_ti_selection(channel, tisel)
93    }
94
95    /// Get capture value for a channel.
96    pub fn get_capture_value(&self, channel: Channel) -> u32 {
97        self.inner.get_capture_value(channel)
98    }
99
100    /// Get input interrupt.
101    pub fn get_input_interrupt(&self, channel: Channel) -> bool {
102        self.inner.get_input_interrupt(channel)
103    }
104
105    fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture<T> {
106        // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.5
107        // or ST RM0008 (STM32F103) chapter 15.3.5 Input capture mode
108        self.inner.set_input_ti_selection(channel, tisel);
109        self.inner.set_input_capture_filter(channel, FilterValue::NO_FILTER);
110        self.inner.set_input_capture_mode(channel, mode);
111        self.inner.set_input_capture_prescaler(channel, 0);
112        self.inner.enable_channel(channel, true);
113        self.inner.enable_input_interrupt(channel, true);
114
115        InputCaptureFuture {
116            channel,
117            phantom: PhantomData,
118        }
119    }
120
121    /// Asynchronously wait until the pin sees a rising edge.
122    pub async fn wait_for_rising_edge(&mut self, channel: Channel) -> u32 {
123        self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Normal)
124            .await
125    }
126
127    /// Asynchronously wait until the pin sees a falling edge.
128    pub async fn wait_for_falling_edge(&mut self, channel: Channel) -> u32 {
129        self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Normal)
130            .await
131    }
132
133    /// Asynchronously wait until the pin sees any edge.
134    pub async fn wait_for_any_edge(&mut self, channel: Channel) -> u32 {
135        self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Normal)
136            .await
137    }
138
139    /// Asynchronously wait until the (alternate) pin sees a rising edge.
140    pub async fn wait_for_rising_edge_alternate(&mut self, channel: Channel) -> u32 {
141        self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Alternate)
142            .await
143    }
144
145    /// Asynchronously wait until the (alternate) pin sees a falling edge.
146    pub async fn wait_for_falling_edge_alternate(&mut self, channel: Channel) -> u32 {
147        self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Alternate)
148            .await
149    }
150
151    /// Asynchronously wait until the (alternate) pin sees any edge.
152    pub async fn wait_for_any_edge_alternate(&mut self, channel: Channel) -> u32 {
153        self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Alternate)
154            .await
155    }
156}
157
158#[must_use = "futures do nothing unless you `.await` or poll them"]
159struct InputCaptureFuture<T: GeneralInstance4Channel> {
160    channel: Channel,
161    phantom: PhantomData<T>,
162}
163
164impl<T: GeneralInstance4Channel> Drop for InputCaptureFuture<T> {
165    fn drop(&mut self) {
166        critical_section::with(|_| {
167            let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
168
169            // disable interrupt enable
170            regs.dier().modify(|w| w.set_ccie(self.channel.index(), false));
171        });
172    }
173}
174
175impl<T: GeneralInstance4Channel> Future for InputCaptureFuture<T> {
176    type Output = u32;
177
178    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
179        T::state().cc_waker[self.channel.index()].register(cx.waker());
180
181        let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
182
183        let dier = regs.dier().read();
184        if !dier.ccie(self.channel.index()) {
185            let val = regs.ccr(self.channel.index()).read().0;
186            Poll::Ready(val)
187        } else {
188            Poll::Pending
189        }
190    }
191}