diff options
| author | Bruno Bousquet <[email protected]> | 2024-05-05 21:58:54 -0400 |
|---|---|---|
| committer | Bruno Bousquet <[email protected]> | 2024-05-05 21:58:54 -0400 |
| commit | ad66dc3aabe6ac11dd0f3aa4d9f403e3aac7e8f4 (patch) | |
| tree | 2c62239324aefb1515ae122b16b9be4297e6c1a2 /embassy-stm32/src/timer/input_capture.rs | |
| parent | 15c3ae8ef6abaf37704e3278a1de6b2ae259aa15 (diff) | |
create input_capture
Diffstat (limited to 'embassy-stm32/src/timer/input_capture.rs')
| -rw-r--r-- | embassy-stm32/src/timer/input_capture.rs | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs new file mode 100644 index 000000000..6401656c8 --- /dev/null +++ b/embassy-stm32/src/timer/input_capture.rs | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | //! Input capture driver. | ||
| 2 | |||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 6 | use embassy_sync::channel; | ||
| 7 | |||
| 8 | use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; | ||
| 9 | use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; | ||
| 10 | use crate::gpio::{AFType, AnyPin, Pull}; | ||
| 11 | use crate::time::Hertz; | ||
| 12 | use crate::Peripheral; | ||
| 13 | |||
| 14 | /// Channel 1 marker type. | ||
| 15 | pub enum Ch1 {} | ||
| 16 | /// Channel 2 marker type. | ||
| 17 | pub enum Ch2 {} | ||
| 18 | /// Channel 3 marker type. | ||
| 19 | pub enum Ch3 {} | ||
| 20 | /// Channel 4 marker type. | ||
| 21 | pub enum Ch4 {} | ||
| 22 | |||
| 23 | /// Capture pin wrapper. | ||
| 24 | /// | ||
| 25 | /// This wraps a pin to make it usable with capture. | ||
| 26 | pub struct CapturePin<'d, T, C> { | ||
| 27 | _pin: PeripheralRef<'d, AnyPin>, | ||
| 28 | phantom: PhantomData<(T, C)>, | ||
| 29 | } | ||
| 30 | |||
| 31 | macro_rules! channel_impl { | ||
| 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | ||
| 33 | impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> { | ||
| 34 | #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] | ||
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, pull_type: Pull) -> Self { | ||
| 36 | into_ref!(pin); | ||
| 37 | critical_section::with(|_| { | ||
| 38 | pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type); | ||
| 39 | #[cfg(gpio_v2)] | ||
| 40 | pin.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 41 | }); | ||
| 42 | CapturePin { | ||
| 43 | _pin: pin.map_into(), | ||
| 44 | phantom: PhantomData, | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | } | ||
| 50 | |||
| 51 | channel_impl!(new_ch1, Ch1, Channel1Pin); | ||
| 52 | channel_impl!(new_ch2, Ch2, Channel2Pin); | ||
| 53 | channel_impl!(new_ch3, Ch3, Channel3Pin); | ||
| 54 | channel_impl!(new_ch4, Ch4, Channel4Pin); | ||
| 55 | |||
| 56 | /// Input capture driver. | ||
| 57 | pub struct InputCapture<'d, T: GeneralInstance4Channel> { | ||
| 58 | inner: Timer<'d, T>, | ||
| 59 | } | ||
| 60 | |||
| 61 | impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { | ||
| 62 | /// Create a new input capture driver. | ||
| 63 | pub fn new( | ||
| 64 | tim: impl Peripheral<P = T> + 'd, | ||
| 65 | _ch1: Option<CapturePin<'d, T, Ch1>>, | ||
| 66 | _ch2: Option<CapturePin<'d, T, Ch2>>, | ||
| 67 | _ch3: Option<CapturePin<'d, T, Ch3>>, | ||
| 68 | _ch4: Option<CapturePin<'d, T, Ch4>>, | ||
| 69 | freq: Hertz, | ||
| 70 | counting_mode: CountingMode, | ||
| 71 | ) -> Self { | ||
| 72 | Self::new_inner(tim, freq, counting_mode) | ||
| 73 | } | ||
| 74 | |||
| 75 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { | ||
| 76 | let mut this = Self { inner: Timer::new(tim) }; | ||
| 77 | |||
| 78 | this.inner.set_counting_mode(counting_mode); | ||
| 79 | this.set_tick_freq(freq); | ||
| 80 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details | ||
| 81 | this.inner.start(); | ||
| 82 | |||
| 83 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | ||
| 84 | .iter() | ||
| 85 | .for_each(|&channel| { | ||
| 86 | this.inner.set_input_capture_mode(channel, InputCaptureMode::Rising); | ||
| 87 | |||
| 88 | this.inner.set_input_ti_selection(channel, InputTISelection::Normal); | ||
| 89 | }); | ||
| 90 | |||
| 91 | this | ||
| 92 | } | ||
| 93 | |||
| 94 | /// Enable the given channel. | ||
| 95 | pub fn enable(&mut self, channel: Channel) { | ||
| 96 | self.inner.enable_channel(channel, true); | ||
| 97 | } | ||
| 98 | |||
| 99 | /// Disable the given channel. | ||
| 100 | pub fn disable(&mut self, channel: Channel) { | ||
| 101 | self.inner.enable_channel(channel, false); | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Check whether given channel is enabled | ||
| 105 | pub fn is_enabled(&self, channel: Channel) -> bool { | ||
| 106 | self.inner.get_channel_enable_state(channel) | ||
| 107 | } | ||
| 108 | |||
| 109 | /// Set tick frequency. | ||
| 110 | /// | ||
| 111 | /// Note: when you call this, the max period value changes | ||
| 112 | pub fn set_tick_freq(&mut self, freq: Hertz) { | ||
| 113 | let f = freq; | ||
| 114 | assert!(f.0 > 0); | ||
| 115 | let timer_f = self.inner.get_clock_frequency(); | ||
| 116 | |||
| 117 | let pclk_ticks_per_timer_period = timer_f / f; | ||
| 118 | let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into()); | ||
| 119 | |||
| 120 | let regs = self.inner.regs_core(); | ||
| 121 | regs.psc().write_value(psc); | ||
| 122 | |||
| 123 | // Generate an Update Request | ||
| 124 | regs.egr().write(|r| r.set_ug(true)); | ||
| 125 | } | ||
| 126 | |||
| 127 | /// Set the input capture mode for a given channel. | ||
| 128 | pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { | ||
| 129 | self.inner.set_input_capture_mode(channel, mode); | ||
| 130 | } | ||
| 131 | |||
| 132 | /// Set input TI selection. | ||
| 133 | pub fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { | ||
| 134 | self.inner.set_input_ti_selection(channel, tisel) | ||
| 135 | } | ||
| 136 | |||
| 137 | /// Get capture value for a channel. | ||
| 138 | pub fn get_capture_value(&self, channel: Channel) -> u32 { | ||
| 139 | self.inner.get_capture_value(channel) | ||
| 140 | } | ||
| 141 | } | ||
