py32_hal/timer/
input_capture.rs

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