diff options
| author | xoviat <[email protected]> | 2023-08-29 20:06:53 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-08-29 20:06:53 -0500 |
| commit | 416ecc73d8211e348bf51a5cfe84075673b18963 (patch) | |
| tree | 722771ef54d896fae8739948279db8d667ead3d6 /embassy-stm32/src/timer/qei.rs | |
| parent | fdb2c4946aeef968704c358fb52d5fea69e80dcc (diff) | |
add qei draft
Diffstat (limited to 'embassy-stm32/src/timer/qei.rs')
| -rw-r--r-- | embassy-stm32/src/timer/qei.rs | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs new file mode 100644 index 000000000..fa8814722 --- /dev/null +++ b/embassy-stm32/src/timer/qei.rs | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | //! # Quadrature Encoder Interface | ||
| 2 | use crate::{ | ||
| 3 | gpio::PushPull, | ||
| 4 | pac, rcc, | ||
| 5 | timer::{CPin, General}, | ||
| 6 | }; | ||
| 7 | |||
| 8 | pub trait QeiExt: Sized + Instance { | ||
| 9 | fn qei( | ||
| 10 | self, | ||
| 11 | pins: ( | ||
| 12 | impl Into<<Self as CPin<0>>::Ch<PushPull>>, | ||
| 13 | impl Into<<Self as CPin<1>>::Ch<PushPull>>, | ||
| 14 | ), | ||
| 15 | ) -> Qei<Self>; | ||
| 16 | } | ||
| 17 | |||
| 18 | impl<TIM: Instance> QeiExt for TIM { | ||
| 19 | fn qei( | ||
| 20 | self, | ||
| 21 | pins: ( | ||
| 22 | impl Into<<Self as CPin<0>>::Ch<PushPull>>, | ||
| 23 | impl Into<<Self as CPin<1>>::Ch<PushPull>>, | ||
| 24 | ), | ||
| 25 | ) -> Qei<Self> { | ||
| 26 | Qei::new(self, pins) | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | /// Hardware quadrature encoder interface peripheral | ||
| 31 | pub struct Qei<TIM: Instance> { | ||
| 32 | tim: TIM, | ||
| 33 | pins: ( | ||
| 34 | <TIM as CPin<0>>::Ch<PushPull>, | ||
| 35 | <TIM as CPin<1>>::Ch<PushPull>, | ||
| 36 | ), | ||
| 37 | } | ||
| 38 | |||
| 39 | impl<TIM: Instance> Qei<TIM> { | ||
| 40 | /// Configures a TIM peripheral as a quadrature encoder interface input | ||
| 41 | pub fn new( | ||
| 42 | mut tim: TIM, | ||
| 43 | pins: ( | ||
| 44 | impl Into<<TIM as CPin<0>>::Ch<PushPull>>, | ||
| 45 | impl Into<<TIM as CPin<1>>::Ch<PushPull>>, | ||
| 46 | ), | ||
| 47 | ) -> Self { | ||
| 48 | // Enable and reset clock. | ||
| 49 | unsafe { | ||
| 50 | TIM::enable_unchecked(); | ||
| 51 | TIM::reset_unchecked(); | ||
| 52 | } | ||
| 53 | |||
| 54 | let pins = (pins.0.into(), pins.1.into()); | ||
| 55 | tim.setup_qei(); | ||
| 56 | |||
| 57 | Qei { tim, pins } | ||
| 58 | } | ||
| 59 | |||
| 60 | /// Releases the TIM peripheral and QEI pins | ||
| 61 | #[allow(clippy::type_complexity)] | ||
| 62 | pub fn release( | ||
| 63 | self, | ||
| 64 | ) -> ( | ||
| 65 | TIM, | ||
| 66 | ( | ||
| 67 | <TIM as CPin<0>>::Ch<PushPull>, | ||
| 68 | <TIM as CPin<1>>::Ch<PushPull>, | ||
| 69 | ), | ||
| 70 | ) { | ||
| 71 | (self.tim, self.pins) | ||
| 72 | } | ||
| 73 | |||
| 74 | /// Set current count number | ||
| 75 | pub fn set_count(&mut self, value: TIM::Width) -> &mut Self { | ||
| 76 | self.tim.write_count(value); | ||
| 77 | self | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | impl<TIM: Instance> embedded_hal::Qei for Qei<TIM> { | ||
| 82 | type Count = TIM::Width; | ||
| 83 | |||
| 84 | fn count(&self) -> Self::Count { | ||
| 85 | self.tim.read_count() | ||
| 86 | } | ||
| 87 | |||
| 88 | fn direction(&self) -> embedded_hal::Direction { | ||
| 89 | if self.tim.read_direction() { | ||
| 90 | embedded_hal::Direction::Upcounting | ||
| 91 | } else { | ||
| 92 | embedded_hal::Direction::Downcounting | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + General + CPin<0> + CPin<1> { | ||
| 98 | fn setup_qei(&mut self); | ||
| 99 | |||
| 100 | fn read_direction(&self) -> bool; | ||
| 101 | } | ||
| 102 | |||
| 103 | macro_rules! hal { | ||
| 104 | ($TIM:ty) => { | ||
| 105 | impl Instance for $TIM { | ||
| 106 | fn setup_qei(&mut self) { | ||
| 107 | // Configure TxC1 and TxC2 as captures | ||
| 108 | #[cfg(not(feature = "gpio-f410"))] | ||
| 109 | self.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2()); | ||
| 110 | #[cfg(feature = "gpio-f410")] | ||
| 111 | self.ccmr1_input() | ||
| 112 | .write(|w| unsafe { w.cc1s().bits(0b01).cc2s().bits(0b01) }); | ||
| 113 | // enable and configure to capture on rising edge | ||
| 114 | self.ccer.write(|w| { | ||
| 115 | w.cc1e().set_bit().cc1p().clear_bit(); | ||
| 116 | w.cc2e().set_bit().cc2p().clear_bit() | ||
| 117 | }); | ||
| 118 | self.smcr.write(|w| w.sms().encoder_mode_3()); | ||
| 119 | self.set_auto_reload(<$TIM as General>::Width::MAX as u32) | ||
| 120 | .unwrap(); | ||
| 121 | self.cr1.write(|w| w.cen().set_bit()); | ||
| 122 | } | ||
| 123 | |||
| 124 | fn read_direction(&self) -> bool { | ||
| 125 | self.cr1.read().dir().bit_is_clear() | ||
| 126 | } | ||
| 127 | } | ||
| 128 | }; | ||
| 129 | } | ||
| 130 | |||
| 131 | #[cfg(feature = "tim1")] | ||
| 132 | hal! { pac::TIM1 } | ||
| 133 | #[cfg(feature = "tim2")] | ||
| 134 | hal! { pac::TIM2 } | ||
| 135 | #[cfg(feature = "tim3")] | ||
| 136 | hal! { pac::TIM3 } | ||
| 137 | #[cfg(feature = "tim4")] | ||
| 138 | hal! { pac::TIM4 } | ||
| 139 | #[cfg(feature = "tim5")] | ||
| 140 | hal! { pac::TIM5 } | ||
| 141 | #[cfg(feature = "tim8")] | ||
| 142 | hal! { pac::TIM8 } | ||
