stm32f1xx_hal_bxcan/
qei.rs

1/**
2  # Quadrature Encoder Interface
3
4  NOTE: In some cases you need to specify remap you need, especially for TIM2
5  (see [Alternate function remapping](super::timer)):
6*/
7use core::u16;
8
9use core::marker::PhantomData;
10
11use crate::hal::{self, Direction};
12#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
13use crate::pac::TIM1;
14#[cfg(feature = "medium")]
15use crate::pac::TIM4;
16use crate::pac::{TIM2, TIM3};
17
18use crate::afio::MAPR;
19
20use crate::pwm_input::Pins;
21use crate::timer::{sealed::Remap, Timer};
22
23/// SMS (Slave Mode Selection) register
24#[derive(Copy, Clone, Debug)]
25pub enum SlaveMode {
26    /// Counter counts up/down on TI2FP1 edge depending on TI1FP2 level.
27    EncoderMode1 = 0b001,
28    /// Encoder mode 2 - Counter counts up/down on TI1FP2 edge depending on TI2FP1 level.
29    EncoderMode2 = 0b010,
30    /// Encoder mode 3 - Counter counts up/down on both TI1FP1 and TI2FP2 edges depending on the
31    /// level of the other input.
32    EncoderMode3 = 0b011,
33    /// Reset Mode - Rising edge of the selected trigger input (TRGI) reinitializes the counter and
34    /// generates an update of the registers.
35    ResetMode = 0b100,
36    /// Trigger Mode - The counter starts at a rising edge of the trigger TRGI (but it is not
37    /// reset). Only the start of the counter is controlled.
38    TriggerMode = 0b110,
39    /// External Clock Mode 1 - Rising edges of the selected trigger (TRGI) clock the counter.
40    ExternalClockMode1 = 0b111,
41}
42
43/// Quadrature Encoder Interface (QEI) options
44///
45/// The `Default` implementation provides a configuration for a 4-count pulse which counts from
46/// 0-65535. The counter wraps back to 0 on overflow.
47#[derive(Copy, Clone, Debug)]
48pub struct QeiOptions {
49    /// Encoder slave mode
50    pub slave_mode: SlaveMode,
51
52    /// Autoreload value
53    ///
54    /// This value allows the maximum count to be configured, up to 65535. Setting a lower value
55    /// will overflow the counter to 0 sooner.
56    pub auto_reload_value: u16,
57}
58
59impl Default for QeiOptions {
60    fn default() -> Self {
61        Self {
62            slave_mode: SlaveMode::EncoderMode3,
63            auto_reload_value: u16::MAX,
64        }
65    }
66}
67
68pub struct Qei<TIM, REMAP, PINS> {
69    tim: TIM,
70    pins: PINS,
71    _remap: PhantomData<REMAP>,
72}
73
74#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
75impl Timer<TIM1> {
76    pub fn qei<REMAP, PINS>(
77        self,
78        pins: PINS,
79        mapr: &mut MAPR,
80        options: QeiOptions,
81    ) -> Qei<TIM1, REMAP, PINS>
82    where
83        REMAP: Remap<Periph = TIM1>,
84        PINS: Pins<REMAP>,
85    {
86        mapr.modify_mapr(|_, w| unsafe { w.tim1_remap().bits(REMAP::REMAP) });
87
88        let Self { tim, clk: _ } = self;
89        Qei::_tim1(tim, pins, options)
90    }
91}
92
93impl Timer<TIM2> {
94    pub fn qei<REMAP, PINS>(
95        self,
96        pins: PINS,
97        mapr: &mut MAPR,
98        options: QeiOptions,
99    ) -> Qei<TIM2, REMAP, PINS>
100    where
101        REMAP: Remap<Periph = TIM2>,
102        PINS: Pins<REMAP>,
103    {
104        mapr.modify_mapr(|_, w| unsafe { w.tim2_remap().bits(REMAP::REMAP) });
105
106        let Self { tim, clk: _ } = self;
107        Qei::_tim2(tim, pins, options)
108    }
109}
110
111impl Timer<TIM3> {
112    pub fn qei<REMAP, PINS>(
113        self,
114        pins: PINS,
115        mapr: &mut MAPR,
116        options: QeiOptions,
117    ) -> Qei<TIM3, REMAP, PINS>
118    where
119        REMAP: Remap<Periph = TIM3>,
120        PINS: Pins<REMAP>,
121    {
122        mapr.modify_mapr(|_, w| unsafe { w.tim3_remap().bits(REMAP::REMAP) });
123
124        let Self { tim, clk: _ } = self;
125        Qei::_tim3(tim, pins, options)
126    }
127}
128
129#[cfg(feature = "medium")]
130impl Timer<TIM4> {
131    pub fn qei<REMAP, PINS>(
132        self,
133        pins: PINS,
134        mapr: &mut MAPR,
135        options: QeiOptions,
136    ) -> Qei<TIM4, REMAP, PINS>
137    where
138        REMAP: Remap<Periph = TIM4>,
139        PINS: Pins<REMAP>,
140    {
141        mapr.modify_mapr(|_, w| w.tim4_remap().bit(REMAP::REMAP == 1));
142
143        let Self { tim, clk: _ } = self;
144        Qei::_tim4(tim, pins, options)
145    }
146}
147
148macro_rules! hal {
149    ($($TIMX:ident: ($timX:ident, $timXen:ident, $timXrst:ident),)+) => {
150        $(
151            impl<REMAP, PINS> Qei<$TIMX, REMAP, PINS> {
152                fn $timX(tim: $TIMX, pins: PINS, options: QeiOptions) -> Self {
153                    // Configure TxC1 and TxC2 as captures
154                    tim.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2());
155
156                    // enable and configure to capture on rising edge
157                    tim.ccer.write(|w| {
158                        w.cc1e()
159                            .set_bit()
160                            .cc1p()
161                            .clear_bit()
162                            .cc2e()
163                            .set_bit()
164                            .cc2p()
165                            .clear_bit()
166                    });
167
168                    // configure as quadrature encoder
169                    tim.smcr.write(|w| w.sms().bits(options.slave_mode as u8));
170
171                    tim.arr.write(|w| w.arr().bits(options.auto_reload_value));
172                    tim.cr1.write(|w| w.cen().set_bit());
173
174                    Qei { tim, pins, _remap: PhantomData }
175                }
176
177                pub fn release(self) -> ($TIMX, PINS) {
178                    (self.tim, self.pins)
179                }
180            }
181
182            impl<REMAP, PINS> hal::Qei for Qei<$TIMX, REMAP, PINS> {
183                type Count = u16;
184
185                fn count(&self) -> u16 {
186                    self.tim.cnt.read().cnt().bits()
187                }
188
189                fn direction(&self) -> Direction {
190                    if self.tim.cr1.read().dir().bit_is_clear() {
191                        hal::Direction::Upcounting
192                    } else {
193                        hal::Direction::Downcounting
194                    }
195                }
196            }
197
198        )+
199    }
200}
201
202#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
203hal! {
204    TIM1: (_tim1, tim1en, tim1rst),
205}
206hal! {
207    TIM2: (_tim2, tim2en, tim2rst),
208    TIM3: (_tim3, tim3en, tim3rst),
209}
210#[cfg(feature = "medium")]
211hal! {
212    TIM4: (_tim4, tim4en, tim4rst),
213}