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: TimGp16 = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
191
192 // disable interrupt enable
193 regs.dier().modify(|w: &mut DierGp16| w.set_ccie(self.channel.index(), val: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: TimGp16 = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
205
206 let dier: DierGp16 = regs.dier().read();
207 if !dier.ccie(self.channel.index()) {
208 let val: u32 = regs.ccr(self.channel.index()).read().0;
209 Poll::Ready(val)
210 } else {
211 Poll::Pending
212 }
213 }
214}
215