stm32f4xx_hal/
qei.rs

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