stm32g0xx_hal/timer/
qei.rs

1//! Quadrature Encoder Interface
2use crate::hal::{self, Direction};
3use crate::rcc::*;
4
5#[cfg(feature = "stm32g0x1")]
6use crate::stm32::{TIM1, TIM2, TIM3};
7#[cfg(feature = "stm32g0x0")]
8use crate::stm32::{TIM1, TIM3};
9
10use crate::timer::pins::TimerPin;
11use crate::timer::*;
12
13pub struct Qei<TIM, PINS> {
14    tim: TIM,
15    pins: PINS,
16}
17
18pub trait QeiPins<TIM> {
19    fn setup(&self);
20    fn release(self) -> Self;
21}
22
23impl<TIM, P1, P2> QeiPins<TIM> for (P1, P2)
24where
25    P1: TimerPin<TIM, Channel = Channel1>,
26    P2: TimerPin<TIM, Channel = Channel2>,
27{
28    fn setup(&self) {
29        self.0.setup();
30        self.1.setup();
31    }
32
33    fn release(self) -> Self {
34        (self.0.release(), self.1.release())
35    }
36}
37
38pub trait QeiExt<TIM, PINS>
39where
40    PINS: QeiPins<TIM>,
41{
42    fn qei(self, pins: PINS, rcc: &mut Rcc) -> Qei<TIM, PINS>;
43}
44
45macro_rules! qei {
46    ($($TIMX:ident: ($tim:ident, $arr:ident, $cnt:ident),)+) => {
47        $(
48            impl<PINS> Qei<$TIMX, PINS> where PINS: QeiPins<$TIMX> {
49                fn $tim(tim: $TIMX, pins: PINS, rcc: &mut Rcc) -> Self {
50                    // enable and reset peripheral to a clean slate state
51                    $TIMX::enable(rcc);
52                    $TIMX::reset(rcc);
53
54                    // Configure TxC1 and TxC2 as captures
55                    tim.ccmr1_output().write(|w| unsafe {
56                        w.cc1s().bits(0b01).cc2s().bits(0b01)
57                    });
58
59                    // Encoder mode 2.
60                    tim.smcr.write(|w| unsafe { w.sms().bits(0b010) });
61
62                    // Enable and configure to capture on rising edge
63                    tim.ccer.write(|w| {
64                        w.cc1e()
65                            .set_bit()
66                            .cc2e()
67                            .set_bit()
68                            .cc1p()
69                            .clear_bit()
70                            .cc2p()
71                            .clear_bit()
72                            .cc1np()
73                            .clear_bit()
74                            .cc2np()
75                            .clear_bit()
76                    });
77
78                    pins.setup();
79
80                    tim.cr1.write(|w| w.cen().set_bit());
81                    Qei { tim, pins }
82                }
83
84                pub fn release(self) -> ($TIMX, PINS) {
85                    (self.tim, self.pins.release())
86                }
87            }
88
89            impl<PINS> hal::Qei for Qei<$TIMX, PINS> {
90                type Count = u16;
91
92                fn count(&self) -> u16 {
93                    self.tim.cnt.read().$cnt().bits()
94                }
95
96                fn direction(&self) -> Direction {
97                    if self.tim.cr1.read().dir().bit_is_clear() {
98                        hal::Direction::Upcounting
99                    } else {
100                        hal::Direction::Downcounting
101                    }
102                }
103            }
104
105            impl<PINS> QeiExt<$TIMX, PINS> for $TIMX where PINS: QeiPins<$TIMX> {
106                fn qei(self, pins: PINS, rcc: &mut Rcc) -> Qei<$TIMX, PINS> {
107                    Qei::$tim(self, pins, rcc)
108                }
109            }
110        )+
111    }
112}
113
114qei! {
115    TIM1: (tim1, arr, cnt),
116    TIM3: (tim3, arr_l, cnt_l),
117}
118
119#[cfg(feature = "stm32g0x1")]
120qei! {
121    TIM2: (tim2, arr_l, cnt_l),
122}