Skip to content

Commit 0c6c397

Browse files
author
Marwan SMOUNI
committed
Quadrature Encoder Interface API
1 parent b2b9d6d commit 0c6c397

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed

src/lib.rs

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

159+
#[cfg(any(feature = "stm32f765", feature = "stm32f767", feature = "stm32f769"))]
160+
pub mod qei;
161+
159162
#[cfg(feature = "ltdc")]
160163
pub mod ltdc;
161164

src/qei.rs

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

0 commit comments

Comments
 (0)