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