Skip to content

Commit 473e6f5

Browse files
authored
Merge pull request #134 from msmouni/master
Quadrature Encoder Interface API
2 parents 67ca8de + a86d466 commit 473e6f5

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ pub mod qspi;
154154
#[cfg(any(feature = "stm32f765", feature = "stm32f767", feature = "stm32f769"))]
155155
pub mod adc;
156156

157+
#[cfg(any(feature = "stm32f767", feature = "stm32f769"))]
158+
pub mod qei;
159+
157160
#[cfg(feature = "ltdc")]
158161
pub mod ltdc;
159162

src/qei.rs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//! Quadrature Encoder Interface API
2+
3+
use crate::rcc::APB1;
4+
#[cfg(feature = "stm32f767")]
5+
use stm32f7::stm32f7x7::{TIM2, TIM3, TIM4, TIM5};
6+
7+
#[cfg(feature = "stm32f769")]
8+
use stm32f7::stm32f7x9::{TIM2, TIM3, TIM4, TIM5};
9+
10+
#[derive(Debug)]
11+
pub enum Direction {
12+
Upcounting,
13+
Downcounting,
14+
}
15+
16+
/// SMS[3:0] (Slave Mode Selection) register
17+
#[derive(Debug, Clone, Copy)]
18+
pub enum SlaveMode {
19+
/// Slave mode disabled - if CEN = ‘1’ then the prescaler is clocked directly by the internal
20+
/// clock.
21+
Disable = 0b0000,
22+
23+
/// Counter counts up/down on TI2FP1 edge depending on TI1FP2 level.
24+
EncoderMode1 = 0b0001,
25+
26+
/// Encoder mode 2 - Counter counts up/down on TI1FP2 edge depending on TI2FP1 level.
27+
EncoderMode2 = 0b0010,
28+
29+
/// Encoder mode 3 - Counter counts up/down on both TI1FP1 and TI2FP2 edges depending on the
30+
/// level of the other input.
31+
EncoderMode3 = 0b0011,
32+
33+
/// Reset Mode - Rising edge of the selected trigger input (TRGI) reinitializes the counter and
34+
/// generates an update of the registers.
35+
ResetMode = 0b0100,
36+
37+
/// Gated Mode - The counter clock is enabled when the trigger input (TRGI) is high. The
38+
/// counter stops (but is not reset) as soon as the trigger becomes low. Both start and stop of
39+
/// the counter are controlled.
40+
GatedMode = 0b0101,
41+
42+
/// Trigger Mode - The counter starts at a rising edge of the trigger TRGI (but it is not
43+
/// reset). Only the start of the counter is controlled.
44+
TriggerMode = 0b0110,
45+
46+
/// External Clock Mode 1 - Rising edges of the selected trigger (TRGI) clock the counter.
47+
ExternalClockMode1 = 0b0111,
48+
49+
/// Combined reset + trigger mode - Rising edge of the selected trigger input (TRGI)
50+
/// reinitializes the counter, generates an update of the registers and starts the counter.
51+
Combined = 0b1000,
52+
}
53+
54+
/// Quadrature Encoder Interface (QEI) options
55+
#[derive(Debug, Clone, Copy)]
56+
pub struct QeiOptions {
57+
/// Encoder slave mode
58+
pub slave_mode: SlaveMode,
59+
60+
/// Autoreload value
61+
///
62+
/// This value allows the maximum count to be configured. Setting a lower value
63+
/// will overflow the counter to 0 sooner.
64+
pub auto_reload_value: u32,
65+
}
66+
67+
impl Default for QeiOptions {
68+
fn default() -> Self {
69+
Self {
70+
slave_mode: SlaveMode::EncoderMode3,
71+
auto_reload_value: core::u32::MAX,
72+
}
73+
}
74+
}
75+
76+
///
77+
/// Make sure that pin_ch1 and pin_ch2 are used in the corresponding alternative mode.
78+
/// ----------------------------------
79+
/// TIMx | PIN_CH1 | PIN_CH2 |
80+
/// -------|------------|------------|
81+
/// TIM2 | PA0\<AF1> | PB3\<AF1> |
82+
/// TIM2 | PA0\<AF1> | PA1\<AF1> |
83+
/// TIM2 | PA5\<AF1> | PB3\<AF1> |
84+
/// TIM2 | PA5\<AF1> | PA1\<AF1> |
85+
/// TIM2 | PA15\<AF1> | PB3\<AF1> |
86+
/// TIM2 | PA15\<AF1> | PA1\<AF1> |
87+
/// TIM3 | PA6\<AF2> | PA7\<AF2> |
88+
/// TIM3 | PA6\<AF2> | PB5\<AF2> |
89+
/// TIM3 | PA6\<AF2> | PC7\<AF2> |
90+
/// TIM3 | PB4\<AF2> | PA7\<AF2> |
91+
/// TIM3 | PB4\<AF2> | PB5\<AF2> |
92+
/// TIM3 | PB4\<AF2> | PC7\<AF2> |
93+
/// TIM3 | PC6\<AF2> | PA7\<AF2> |
94+
/// TIM3 | PC6\<AF2> | PB5\<AF2> |
95+
/// TIM3 | PC6\<AF2> | PC7\<AF2> |
96+
/// TIM4 | PB6\<AF2> | PB7\<AF2> |
97+
/// TIM4 | PB6\<AF2> | PD13\<AF2> |
98+
/// TIM4 | PD12\<AF2> | PB7\<AF2> |
99+
/// TIM4 | PD12\<AF2> | PD13\<AF2> |
100+
/// TIM4 | PD12\<AF2> | PD13\<AF2> |
101+
/// TIM5 | PA0\<AF2> | PA1\<AF2> |
102+
pub struct Qei<PIN1, PIN2, TIM> {
103+
tim: TIM,
104+
_pin_ch1: PIN1,
105+
_pin_ch2: PIN2,
106+
}
107+
108+
// General-purpose timers (TIM2/TIM3/TIM4/TIM5) : Up, Down, Up/Down
109+
macro_rules! hal_qei {
110+
($fct:ident,$TIMX:ty, $bits:ty, $timen:ident, $timrst:ident) => {
111+
//, $CH1:ident<$AFCH1:ty>, $CH2:ident<$AFCH2:ty>) => {
112+
impl<PIN1, PIN2> Qei<PIN1, PIN2, $TIMX> {
113+
//Qei<$CH1<Alternate<$AFCH1>>, $CH2<Alternate<$AFCH2>>, $TIM> {
114+
pub fn $fct(
115+
tim: $TIMX,
116+
pin_ch1: PIN1, //$CH1<Alternate<$AFCH1>>,
117+
pin_ch2: PIN2, //$CH2<Alternate<$AFCH2>>,
118+
apb1: &mut APB1,
119+
options: QeiOptions,
120+
) -> Self {
121+
// enable and reset peripheral to a clean slate state
122+
apb1.enr().modify(|_, w| w.$timen().set_bit());
123+
apb1.rstr().modify(|_, w| w.$timrst().set_bit());
124+
apb1.rstr().modify(|_, w| w.$timrst().clear_bit());
125+
126+
// Configure TxC1 and TxC2 as captures
127+
tim.ccmr1_output()
128+
.write(|w| unsafe { w.cc1s().bits(0b01).cc2s().bits(0b01) });
129+
130+
// enable and configure to capture on rising edge
131+
tim.ccer.write(|w| {
132+
w.cc1e()
133+
.set_bit()
134+
.cc1p()
135+
.clear_bit()
136+
.cc2e()
137+
.set_bit()
138+
.cc2p()
139+
.clear_bit()
140+
});
141+
142+
// configure as quadrature encoder
143+
tim.smcr.write(|w| w.sms().bits(options.slave_mode as u8));
144+
tim.arr
145+
.write(|w| unsafe { w.bits(options.auto_reload_value) });
146+
tim.cr1.write(|w| w.cen().set_bit());
147+
148+
Self {
149+
tim,
150+
_pin_ch1: pin_ch1,
151+
_pin_ch2: pin_ch2,
152+
}
153+
}
154+
155+
pub fn read_count(&self) -> $bits {
156+
self.tim.cnt.read().bits() as $bits
157+
}
158+
159+
pub fn read_direction(&self) -> Direction {
160+
if self.tim.cr1.read().dir().bit_is_clear() {
161+
Direction::Upcounting
162+
} else {
163+
Direction::Downcounting
164+
}
165+
}
166+
167+
pub fn release(self) -> ($TIMX, PIN1, PIN2) {
168+
(self.tim, self._pin_ch1, self._pin_ch2)
169+
}
170+
}
171+
};
172+
}
173+
174+
hal_qei! {qei_tim2, TIM2, u32, tim2en, tim2rst}
175+
hal_qei! {qei_tim3, TIM3, u16, tim3en, tim3rst}
176+
hal_qei! {qei_tim4, TIM4, u16, tim4en, tim4rst}
177+
hal_qei! {qei_tim5, TIM5, u32, tim5en, tim5rst}

0 commit comments

Comments
 (0)