aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/timer')
-rw-r--r--embassy-stm32/src/timer/qei.rs100
1 files changed, 67 insertions, 33 deletions
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 82b5968b0..bb152731c 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -1,8 +1,6 @@
1//! Quadrature decoder using a timer. 1//! Quadrature decoder using a timer.
2 2
3use core::marker::PhantomData; 3use stm32_metapac::timer::vals::{self, Sms};
4
5use stm32_metapac::timer::vals;
6 4
7use super::low_level::Timer; 5use super::low_level::Timer;
8pub use super::{Ch1, Ch2}; 6pub use super::{Ch1, Ch2};
@@ -11,35 +9,59 @@ use crate::gpio::{AfType, AnyPin, Pull};
11use crate::timer::TimerChannel; 9use crate::timer::TimerChannel;
12use crate::Peri; 10use crate::Peri;
13 11
14/// Counting direction 12/// Qei driver config.
15pub enum Direction { 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16 /// Counting up. 14#[derive(Clone, Copy)]
17 Upcounting, 15pub struct Config {
18 /// Counting down. 16 /// Configures the internal pull up/down resistor for Qei's channel 1 pin.
19 Downcounting, 17 pub ch1_pull: Pull,
18 /// Configures the internal pull up/down resistor for Qei's channel 2 pin.
19 pub ch2_pull: Pull,
20 /// Specifies the encoder mode to use for the Qei peripheral.
21 pub mode: QeiMode,
20} 22}
21 23
22/// Wrapper for using a pin with QEI. 24impl Default for Config {
23pub struct QeiPin<'d, T, Channel, #[cfg(afio)] A> { 25 /// Arbitrary defaults to preserve backwards compatibility
24 #[allow(unused)] 26 fn default() -> Self {
25 pin: Peri<'d, AnyPin>, 27 Self {
26 phantom: PhantomData<if_afio!((T, Channel, A))>, 28 ch1_pull: Pull::None,
29 ch2_pull: Pull::None,
30 mode: QeiMode::Mode3,
31 }
32 }
27} 33}
28 34
29impl<'d, T: GeneralInstance4Channel, C: QeiChannel, #[cfg(afio)] A> if_afio!(QeiPin<'d, T, C, A>) { 35/// See STMicro AN4013 for ยง2.3 for more information
30 /// Create a new QEI pin instance. 36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31 pub fn new(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>) -> Self { 37#[derive(Clone, Copy)]
32 critical_section::with(|_| { 38pub enum QeiMode {
33 pin.set_low(); 39 /// Direct alias for [`Sms::ENCODER_MODE_1`]
34 set_as_af!(pin, AfType::input(Pull::None)); 40 Mode1,
35 }); 41 /// Direct alias for [`Sms::ENCODER_MODE_2`]
36 QeiPin { 42 Mode2,
37 pin: pin.into(), 43 /// Direct alias for [`Sms::ENCODER_MODE_3`]
38 phantom: PhantomData, 44 Mode3,
45}
46
47impl From<QeiMode> for Sms {
48 fn from(mode: QeiMode) -> Self {
49 match mode {
50 QeiMode::Mode1 => Sms::ENCODER_MODE_1,
51 QeiMode::Mode2 => Sms::ENCODER_MODE_2,
52 QeiMode::Mode3 => Sms::ENCODER_MODE_3,
39 } 53 }
40 } 54 }
41} 55}
42 56
57/// Counting direction
58pub enum Direction {
59 /// Counting up.
60 Upcounting,
61 /// Counting down.
62 Downcounting,
63}
64
43trait SealedQeiChannel: TimerChannel {} 65trait SealedQeiChannel: TimerChannel {}
44 66
45/// Marker trait for a timer channel eligible for use with QEI. 67/// Marker trait for a timer channel eligible for use with QEI.
@@ -55,20 +77,28 @@ impl SealedQeiChannel for Ch2 {}
55/// Quadrature decoder driver. 77/// Quadrature decoder driver.
56pub struct Qei<'d, T: GeneralInstance4Channel> { 78pub struct Qei<'d, T: GeneralInstance4Channel> {
57 inner: Timer<'d, T>, 79 inner: Timer<'d, T>,
80 _ch1: Peri<'d, AnyPin>,
81 _ch2: Peri<'d, AnyPin>,
58} 82}
59 83
60impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { 84impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
61 /// Create a new quadrature decoder driver. 85 /// Create a new quadrature decoder driver, with a given [`Config`].
62 #[allow(unused)] 86 #[allow(unused)]
63 pub fn new<#[cfg(afio)] A>( 87 pub fn new<CH1: QeiChannel, CH2: QeiChannel, #[cfg(afio)] A>(
64 tim: Peri<'d, T>, 88 tim: Peri<'d, T>,
65 ch1: if_afio!(QeiPin<'d, T, Ch1, A>), 89 ch1: Peri<'d, if_afio!(impl TimerPin<T, CH1, A>)>,
66 ch2: if_afio!(QeiPin<'d, T, Ch2, A>), 90 ch2: Peri<'d, if_afio!(impl TimerPin<T, CH2, A>)>,
91 config: Config,
67 ) -> Self { 92 ) -> Self {
68 Self::new_inner(tim) 93 // Configure the pins to be used for the QEI peripheral.
69 } 94 critical_section::with(|_| {
95 ch1.set_low();
96 set_as_af!(ch1, AfType::input(config.ch1_pull));
97
98 ch2.set_low();
99 set_as_af!(ch2, AfType::input(config.ch2_pull));
100 });
70 101
71 fn new_inner(tim: Peri<'d, T>) -> Self {
72 let inner = Timer::new(tim); 102 let inner = Timer::new(tim);
73 let r = inner.regs_gp16(); 103 let r = inner.regs_gp16();
74 104
@@ -88,13 +118,17 @@ impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
88 }); 118 });
89 119
90 r.smcr().modify(|w| { 120 r.smcr().modify(|w| {
91 w.set_sms(vals::Sms::ENCODER_MODE_3); 121 w.set_sms(config.mode.into());
92 }); 122 });
93 123
94 r.arr().modify(|w| w.set_arr(u16::MAX)); 124 r.arr().modify(|w| w.set_arr(u16::MAX));
95 r.cr1().modify(|w| w.set_cen(true)); 125 r.cr1().modify(|w| w.set_cen(true));
96 126
97 Self { inner } 127 Self {
128 inner,
129 _ch1: ch1.into(),
130 _ch2: ch2.into(),
131 }
98 } 132 }
99 133
100 /// Get direction. 134 /// Get direction.