1 | //! Input capture driver. |
2 | |
3 | use core::future::Future; |
4 | use core::marker::PhantomData; |
5 | use core::pin::Pin; |
6 | use core::task::{Context, Poll}; |
7 | |
8 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
9 | |
10 | use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; |
11 | use super::{ |
12 | CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, |
13 | GeneralInstance4Channel, |
14 | }; |
15 | use crate::gpio::{AfType, AnyPin, Pull}; |
16 | use crate::interrupt::typelevel::{Binding, Interrupt}; |
17 | use crate::time::Hertz; |
18 | use crate::Peripheral; |
19 | |
20 | /// Channel 1 marker type. |
21 | pub enum Ch1 {} |
22 | /// Channel 2 marker type. |
23 | pub enum Ch2 {} |
24 | /// Channel 3 marker type. |
25 | pub enum Ch3 {} |
26 | /// Channel 4 marker type. |
27 | pub enum Ch4 {} |
28 | |
29 | /// Capture pin wrapper. |
30 | /// |
31 | /// This wraps a pin to make it usable with capture. |
32 | pub struct CapturePin<'d, T, C> { |
33 | _pin: PeripheralRef<'d, AnyPin>, |
34 | phantom: PhantomData<(T, C)>, |
35 | } |
36 | |
37 | macro_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 | |
53 | channel_impl!(new_ch1, Ch1, Channel1Pin); |
54 | channel_impl!(new_ch2, Ch2, Channel2Pin); |
55 | channel_impl!(new_ch3, Ch3, Channel3Pin); |
56 | channel_impl!(new_ch4, Ch4, Channel4Pin); |
57 | |
58 | /// Input capture driver. |
59 | pub struct InputCapture<'d, T: GeneralInstance4Channel> { |
60 | inner: Timer<'d, T>, |
61 | } |
62 | |
63 | impl<'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" ] |
182 | struct InputCaptureFuture<T: GeneralInstance4Channel> { |
183 | channel: Channel, |
184 | phantom: PhantomData<T>, |
185 | } |
186 | |
187 | impl<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 | |
198 | impl<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 | |