@@ -63,17 +63,14 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
63
63
set_eic_channel_data (self -> eic_channel_a , (void * ) self );
64
64
set_eic_channel_data (self -> eic_channel_b , (void * ) self );
65
65
66
- bool pin_a_level = gpio_get_pin_level (self -> pin_a );
67
- bool pin_b_level = gpio_get_pin_level (self -> pin_b );
68
- if (!pin_a_level && !pin_b_level ) {
69
- self -> last_state = 1 ;
70
- } else if (!pin_a_level && pin_b_level ) {
71
- self -> last_state = 2 ;
72
- } else if (pin_a_level && pin_b_level ) {
73
- self -> last_state = 3 ;
74
- } else {
75
- self -> last_state = 4 ;
76
- }
66
+ self -> position = 0 ;
67
+ self -> quarter_count = 0 ;
68
+
69
+ // Top two bits of self->last_state don't matter, because they'll be gone as soon as
70
+ // interrupt handler is called.
71
+ self -> last_state =
72
+ ((uint8_t ) gpio_get_pin_level (self -> pin_a ) << 1 ) |
73
+ (uint8_t ) gpio_get_pin_level (self -> pin_b );
77
74
78
75
turn_on_eic_channel (self -> eic_channel_a , EIC_CONFIG_SENSE0_BOTH_Val , EIC_HANDLER_INCREMENTAL_ENCODER );
79
76
turn_on_eic_channel (self -> eic_channel_b , EIC_CONFIG_SENSE0_BOTH_Val , EIC_HANDLER_INCREMENTAL_ENCODER );
@@ -101,29 +98,55 @@ mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementa
101
98
102
99
void incrementalencoder_interrupt_handler (uint8_t channel ) {
103
100
rotaryio_incrementalencoder_obj_t * self = get_eic_channel_data (channel );
101
+
102
+ // This table also works for detent both at 11 and 00
103
+ // For 11 at detent:
104
+ // Turning cw: 11->01->00->10->11
105
+ // Turning ccw: 11->10->00->01->11
106
+ // For 00 at detent:
107
+ // Turning cw: 00->10->11->10->00
108
+ // Turning ccw: 00->01->11->10->00
109
+
110
+ // index table by state <oldA><oldB><newA><newB>
111
+ #define BAD 7
112
+ static const int8_t transitions [16 ] = {
113
+ 0 , // 00 -> 00 no movement
114
+ -1 , // 00 -> 01 3/4 ccw (11 detent) or 1/4 ccw (00 at detent)
115
+ +1 , // 00 -> 10 3/4 cw or 1/4 cw
116
+ BAD , // 00 -> 11 non-Gray-code transition
117
+ +1 , // 01 -> 00 2/4 or 4/4 cw
118
+ 0 , // 01 -> 01 no movement
119
+ BAD , // 01 -> 10 non-Gray-code transition
120
+ -1 , // 01 -> 11 4/4 or 2/4 ccw
121
+ -1 , // 10 -> 00 2/4 or 4/4 ccw
122
+ BAD , // 10 -> 01 non-Gray-code transition
123
+ 0 , // 10 -> 10 no movement
124
+ +1 , // 10 -> 11 4/4 or 2/4 cw
125
+ BAD , // 11 -> 00 non-Gray-code transition
126
+ +1 , // 11 -> 01 1/4 or 3/4 cw
127
+ -1 , // 11 -> 10 1/4 or 3/4 ccw
128
+ 0 , // 11 -> 11 no movement
129
+ };
130
+
131
+ // Shift the old AB bits to the "old" position, and set the new AB bits.
104
132
// TODO(tannewt): If we need more speed then read the pin directly. gpio_get_pin_level has
105
133
// smarts to compensate for pin direction we don't need.
106
- bool pin_a = gpio_get_pin_level (self -> pin_a );
107
- bool pin_b = gpio_get_pin_level (self -> pin_b );
108
-
109
- uint8_t this_state ;
110
- if (!pin_a && !pin_b ) {
111
- this_state = 1 ;
112
- } else if (!pin_a && pin_b ) {
113
- this_state = 2 ;
114
- } else if (pin_a && pin_b ) {
115
- this_state = 3 ;
116
- } else {
117
- this_state = 4 ;
134
+ self -> last_state = (self -> last_state & 0x3 ) << 2 |
135
+ ((uint8_t ) gpio_get_pin_level (self -> pin_a ) << 1 ) |
136
+ (uint8_t ) gpio_get_pin_level (self -> pin_b );
137
+
138
+ int8_t quarter_incr = transitions [self -> last_state ];
139
+ if (quarter_incr == BAD ) {
140
+ // Missed a transition. We don't know which way we're going, so do nothing.
141
+ return ;
118
142
}
119
143
120
- // Handle wrap around explicitly.
121
- if (this_state == 4 && self -> last_state == 1 ) {
122
- self -> position -= 1 ;
123
- } else if (this_state == 1 && self -> last_state == 4 ) {
144
+ self -> quarter_count += quarter_incr ;
145
+ if (self -> quarter_count >= 4 ) {
124
146
self -> position += 1 ;
125
- } else {
126
- self -> position += (this_state - self -> last_state );
147
+ self -> quarter_count = 0 ;
148
+ } else if (self -> quarter_count <= -4 ) {
149
+ self -> position -= 1 ;
150
+ self -> quarter_count = 0 ;
127
151
}
128
- self -> last_state = this_state ;
129
152
}
0 commit comments