1use 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
30pub 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 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 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 #[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 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 self.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2());
109 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 }