diff options
| author | Matteo Meluzzi <[email protected]> | 2025-10-02 10:53:31 +0200 |
|---|---|---|
| committer | Matteo Meluzzi <[email protected]> | 2025-10-02 10:53:31 +0200 |
| commit | 828a8df18d04877df1f55f04354980b28ff2f2f8 (patch) | |
| tree | c4fa405f5eba7a14b6d435d6cc746c9e0dc52632 /embassy-stm32/src/timer/qei.rs | |
| parent | 176649e71ad442ca9856af6c11989b0b2f228c4b (diff) | |
| parent | 194a721d0eab929a2af0a2a4e45ca8e70e0d3f0a (diff) | |
Merge branch 'main' into 17-add-support-for-boot-protocol
Diffstat (limited to 'embassy-stm32/src/timer/qei.rs')
| -rw-r--r-- | embassy-stm32/src/timer/qei.rs | 100 |
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 | ||
| 3 | use core::marker::PhantomData; | 3 | use stm32_metapac::timer::vals::{self, Sms}; |
| 4 | |||
| 5 | use stm32_metapac::timer::vals; | ||
| 6 | 4 | ||
| 7 | use super::low_level::Timer; | 5 | use super::low_level::Timer; |
| 8 | pub use super::{Ch1, Ch2}; | 6 | pub use super::{Ch1, Ch2}; |
| @@ -11,35 +9,59 @@ use crate::gpio::{AfType, AnyPin, Pull}; | |||
| 11 | use crate::timer::TimerChannel; | 9 | use crate::timer::TimerChannel; |
| 12 | use crate::Peri; | 10 | use crate::Peri; |
| 13 | 11 | ||
| 14 | /// Counting direction | 12 | /// Qei driver config. |
| 15 | pub enum Direction { | 13 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 16 | /// Counting up. | 14 | #[derive(Clone, Copy)] |
| 17 | Upcounting, | 15 | pub 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. | 24 | impl Default for Config { |
| 23 | pub 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 | ||
| 29 | impl<'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(|_| { | 38 | pub 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 | |||
| 47 | impl 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 | ||
| 58 | pub enum Direction { | ||
| 59 | /// Counting up. | ||
| 60 | Upcounting, | ||
| 61 | /// Counting down. | ||
| 62 | Downcounting, | ||
| 63 | } | ||
| 64 | |||
| 43 | trait SealedQeiChannel: TimerChannel {} | 65 | trait 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. |
| 56 | pub struct Qei<'d, T: GeneralInstance4Channel> { | 78 | pub 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 | ||
| 60 | impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { | 84 | impl<'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. |
