1
1
//! Quadrature decoder using a timer.
2
2
3
- use core:: marker:: PhantomData ;
4
-
5
3
use embassy_hal_internal:: { into_ref, PeripheralRef } ;
6
- use stm32_metapac:: timer:: vals;
4
+ use stm32_metapac:: timer:: vals:: { self , Sms } ;
7
5
8
6
use super :: low_level:: Timer ;
9
7
use super :: { Channel1Pin , Channel2Pin , GeneralInstance4Channel } ;
@@ -23,49 +21,120 @@ pub enum Ch1 {}
23
21
/// Channel 2 marker type.
24
22
pub enum Ch2 { }
25
23
26
- /// Wrapper for using a pin with QEI.
27
- pub struct QeiPin < ' d , T , Channel > {
28
- _pin : PeripheralRef < ' d , AnyPin > ,
29
- phantom : PhantomData < ( T , Channel ) > ,
24
+ #[ doc = "See STMicro AN4013 for §2.3 for more information" ]
25
+ #[ derive( Clone , Eq , PartialEq , Copy , Debug ) ]
26
+ pub enum QeiMode {
27
+ #[ doc = "Direct alias for Sms::ENCODER_MODE_1" ]
28
+ Mode1 ,
29
+ #[ doc = "Direct alias for Sms::ENCODER_MODE_2" ]
30
+ Mode2 ,
31
+ #[ doc = "Direct alias for Sms::ENCODER_MODE_3" ]
32
+ Mode3 ,
30
33
}
31
34
32
- macro_rules! channel_impl {
33
- ( $new_chx: ident, $channel: ident, $pin_trait: ident) => {
34
- impl <' d, T : GeneralInstance4Channel > QeiPin <' d, T , $channel> {
35
- #[ doc = concat!( "Create a new " , stringify!( $channel) , " QEI pin instance." ) ]
36
- pub fn $new_chx( pin: impl Peripheral <P = impl $pin_trait<T >> + ' d) -> Self {
37
- into_ref!( pin) ;
38
- critical_section:: with( |_| {
39
- pin. set_low( ) ;
40
- pin. set_as_af( pin. af_num( ) , AfType :: input( Pull :: None ) ) ;
41
- } ) ;
42
- QeiPin {
43
- _pin: pin. map_into( ) ,
44
- phantom: PhantomData ,
45
- }
46
- }
35
+ impl From < QeiMode > for Sms {
36
+ fn from ( mode : QeiMode ) -> Self {
37
+ match mode {
38
+ QeiMode :: Mode1 => Sms :: ENCODER_MODE_1 ,
39
+ QeiMode :: Mode2 => Sms :: ENCODER_MODE_2 ,
40
+ QeiMode :: Mode3 => Sms :: ENCODER_MODE_3 ,
47
41
}
48
- } ;
42
+ }
43
+ }
44
+
45
+ #[ non_exhaustive]
46
+ #[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
47
+ /// Config
48
+ pub struct QeiConfig {
49
+ /// Encoder Mode
50
+ pub encoder_mode : QeiMode ,
51
+
52
+ /// Set the pull configuration for the RX pin.
53
+ pub pull : Pull ,
49
54
}
50
55
51
- channel_impl ! ( new_ch1, Ch1 , Channel1Pin ) ;
52
- channel_impl ! ( new_ch2, Ch2 , Channel2Pin ) ;
56
+ impl QeiConfig {
57
+ /// Default constructor
58
+ pub fn new ( ) -> Self {
59
+ Self :: default ( )
60
+ }
61
+
62
+ /// Set the encoder mode
63
+ pub fn with_encoder_mode ( mut self , mode : QeiMode ) -> Self {
64
+ self . encoder_mode = mode;
65
+ self
66
+ }
67
+
68
+ /// Set the pull configuration
69
+ pub fn with_pull ( mut self , pull : Pull ) -> Self {
70
+ self . pull = pull;
71
+ self
72
+ }
73
+ }
74
+
75
+ impl Default for QeiConfig {
76
+ #[ doc = "Arbitrary defaults to preserve backwards compatibility" ]
77
+ fn default ( ) -> Self {
78
+ Self {
79
+ encoder_mode : QeiMode :: Mode3 ,
80
+ pull : Pull :: None ,
81
+ }
82
+ }
83
+ }
53
84
54
85
/// Quadrature decoder driver.
55
86
pub struct Qei < ' d , T : GeneralInstance4Channel > {
56
87
inner : Timer < ' d , T > ,
88
+ _ch1 : PeripheralRef < ' d , AnyPin > ,
89
+ _ch2 : PeripheralRef < ' d , AnyPin > ,
57
90
}
58
91
59
92
impl < ' d , T : GeneralInstance4Channel > Qei < ' d , T > {
60
93
/// Create a new quadrature decoder driver.
61
- pub fn new ( tim : impl Peripheral < P = T > + ' d , _ch1 : QeiPin < ' d , T , Ch1 > , _ch2 : QeiPin < ' d , T , Ch2 > ) -> Self {
62
- Self :: new_inner ( tim)
94
+ pub fn new (
95
+ tim : impl Peripheral < P = T > + ' d ,
96
+ ch1 : impl Peripheral < P = impl Channel1Pin < T > > + ' d ,
97
+ ch2 : impl Peripheral < P = impl Channel2Pin < T > > + ' d ,
98
+ ) -> Self {
99
+ Self :: new_inner ( tim, ch1, ch2, QeiConfig :: default ( ) )
100
+ }
101
+
102
+ /// Create new quadrature encoder driver with non-default config.
103
+ pub fn new_with_config (
104
+ tim : impl Peripheral < P = T > + ' d ,
105
+ ch1 : impl Peripheral < P = impl Channel1Pin < T > > + ' d ,
106
+ ch2 : impl Peripheral < P = impl Channel2Pin < T > > + ' d ,
107
+ config : QeiConfig ,
108
+ ) -> Self {
109
+ Self :: new_inner ( tim, ch1, ch2, config)
63
110
}
64
111
65
- fn new_inner ( tim : impl Peripheral < P = T > + ' d ) -> Self {
112
+ fn new_inner (
113
+ tim : impl Peripheral < P = T > + ' d ,
114
+ ch1 : impl Peripheral < P = impl Channel1Pin < T > > + ' d ,
115
+ ch2 : impl Peripheral < P = impl Channel2Pin < T > > + ' d ,
116
+ config : QeiConfig ,
117
+ ) -> Self {
66
118
let inner = Timer :: new ( tim) ;
67
119
let r = inner. regs_gp16 ( ) ;
68
120
121
+ // Due to generics and specific typesig of Peripheral<P> repeating
122
+ // this block of code twice is less bad than the alternative
123
+ // extra types and traits.
124
+ //
125
+ // Use of into_ref!() is destructive, and the resulting ref
126
+ // is later used when constructing the return type of this fn
127
+ into_ref ! ( ch1) ;
128
+ critical_section:: with ( |_| {
129
+ ch1. set_low ( ) ;
130
+ ch1. set_as_af ( ch1. af_num ( ) , AfType :: input ( config. pull ) ) ;
131
+ } ) ;
132
+ into_ref ! ( ch2) ;
133
+ critical_section:: with ( |_| {
134
+ ch2. set_low ( ) ;
135
+ ch2. set_as_af ( ch2. af_num ( ) , AfType :: input ( config. pull ) ) ;
136
+ } ) ;
137
+
69
138
// Configure TxC1 and TxC2 as captures
70
139
r. ccmr_input ( 0 ) . modify ( |w| {
71
140
w. set_ccs ( 0 , vals:: CcmrInputCcs :: TI4 ) ;
@@ -82,13 +151,17 @@ impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
82
151
} ) ;
83
152
84
153
r. smcr ( ) . modify ( |w| {
85
- w. set_sms ( vals :: Sms :: ENCODER_MODE_3 ) ;
154
+ w. set_sms ( config . encoder_mode . into ( ) ) ;
86
155
} ) ;
87
156
88
157
r. arr ( ) . modify ( |w| w. set_arr ( u16:: MAX ) ) ;
89
158
r. cr1 ( ) . modify ( |w| w. set_cen ( true ) ) ;
90
159
91
- Self { inner }
160
+ Self {
161
+ inner,
162
+ _ch1 : ch1. map_into ( ) ,
163
+ _ch2 : ch2. map_into ( ) ,
164
+ }
92
165
}
93
166
94
167
/// Get direction.
0 commit comments