| 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 | |