stm32f4xx_hal/
qei.rs

1//! # Quadrature Encoder Interface
2use crate::{
3    gpio::PushPull,
4    pac, rcc,
5    timer::{CPin, General},
6};
7
8pub 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
18impl<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
31pub 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
39impl<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
81impl<TIM: Instance> embedded_hal_02::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_02::Direction {
89        if self.tim.read_direction() {
90            embedded_hal_02::Direction::Upcounting
91        } else {
92            embedded_hal_02::Direction::Downcounting
93        }
94    }
95}
96
97pub 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
103macro_rules! hal {
104    ($TIM:ty) => {
105        impl Instance for $TIM {
106            fn setup_qei(&mut self) {
107                // Configure TxC1 and TxC2 as captures
108                self.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2());
109                // enable and configure to capture on rising edge
110                self.ccer().write(|w| {
111                    w.cc1e().set_bit().cc1p().clear_bit();
112                    w.cc2e().set_bit().cc2p().clear_bit()
113                });
114                self.smcr().write(|w| w.sms().encoder_mode_3());
115                self.set_auto_reload(<$TIM as General>::Width::MAX as u32)
116                    .unwrap();
117                self.cr1().write(|w| w.cen().set_bit());
118            }
119
120            fn read_direction(&self) -> bool {
121                self.cr1().read().dir().bit_is_clear()
122            }
123        }
124    };
125}
126
127#[cfg(feature = "tim1")]
128hal! { pac::TIM1 }
129#[cfg(feature = "tim2")]
130hal! { pac::TIM2 }
131#[cfg(feature = "tim3")]
132hal! { pac::TIM3 }
133#[cfg(feature = "tim4")]
134hal! { pac::TIM4 }
135#[cfg(feature = "tim5")]
136hal! { pac::TIM5 }
137#[cfg(feature = "tim8")]
138hal! { pac::TIM8 }