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