Skip to content

Commit 00aeb6b

Browse files
authored
Merge pull request #5468 from jepler/encoder-divisor
rotaryio: Add the ability to set the divisor
2 parents 6a5a88e + 9eebb3d commit 00aeb6b

File tree

10 files changed

+80
-24
lines changed

10 files changed

+80
-24
lines changed

locale/circuitpython.pot

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2976,6 +2976,10 @@ msgstr ""
29762976
msgid "division by zero"
29772977
msgstr ""
29782978

2979+
#: ports/espressif/common-hal/rotaryio/IncrementalEncoder.c
2980+
msgid "divisor must be 4"
2981+
msgstr ""
2982+
29792983
#: py/objdeque.c
29802984
msgid "empty"
29812985
msgstr ""

ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
6767
set_eic_channel_data(self->eic_channel_b, (void *)self);
6868

6969
self->position = 0;
70-
self->quarter_count = 0;
70+
self->sub_count = 0;
7171

7272
shared_module_softencoder_state_init(self,
7373
((uint8_t)gpio_get_pin_level(self->pin_a) << 1) |

ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ typedef struct {
3838
uint8_t eic_channel_a;
3939
uint8_t eic_channel_b;
4040
uint8_t state; // <old A><old B>
41-
int8_t quarter_count; // count intermediate transitions between detents
41+
int8_t sub_count; // count intermediate transitions between detents
42+
int8_t divisor; // Number of quadrature edges required per count
4243
mp_int_t position;
4344
} rotaryio_incrementalencoder_obj_t;
4445

ports/espressif/common-hal/rotaryio/IncrementalEncoder.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,13 @@ void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalenc
8484
self->position = new_position;
8585
pcnt_counter_clear(self->unit);
8686
}
87+
88+
mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self) {
89+
return 4;
90+
}
91+
92+
void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self, mp_int_t divisor) {
93+
if (divisor != 4) {
94+
mp_raise_ValueError(translate("divisor must be 4"));
95+
}
96+
}

ports/nrf/common-hal/rotaryio/IncrementalEncoder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ typedef struct {
3636
uint8_t pin_a;
3737
uint8_t pin_b;
3838
uint8_t state; // <old A><old B>
39-
int8_t quarter_count; // count intermediate transitions between detents
39+
int8_t sub_count; // count intermediate transitions between detents
40+
int8_t divisor; // Number of quadrature edges required per count
4041
mp_int_t position;
4142
} rotaryio_incrementalencoder_obj_t;
4243

ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
7373
}
7474

7575
self->position = 0;
76-
self->quarter_count = 0;
76+
self->sub_count = 0;
7777

7878
common_hal_rp2pio_statemachine_construct(&self->state_machine,
7979
encoder, MP_ARRAY_SIZE(encoder),

ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ typedef struct {
3535
mp_obj_base_t base;
3636
rp2pio_statemachine_obj_t state_machine;
3737
uint8_t state; // <old A><old B>
38-
int8_t quarter_count; // count intermediate transitions between detents
38+
int8_t sub_count; // count intermediate transitions between detents
39+
int8_t divisor; // Number of quadrature edges required per count
3940
bool swapped; // Did the pins need to be swapped to be sequential?
4041
mp_int_t position;
4142
} rotaryio_incrementalencoder_obj_t;

shared-bindings/rotaryio/IncrementalEncoder.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@
3737
//| class IncrementalEncoder:
3838
//| """IncrementalEncoder determines the relative rotational position based on two series of pulses."""
3939
//|
40-
//| def __init__(self, pin_a: microcontroller.Pin, pin_b: microcontroller.Pin) -> None:
40+
//| def __init__(self, pin_a: microcontroller.Pin, pin_b: microcontroller.Pin, divisor: int = 4) -> None:
4141
//| """Create an IncrementalEncoder object associated with the given pins. It tracks the positional
4242
//| state of an incremental rotary encoder (also known as a quadrature encoder.) Position is
4343
//| relative to the position when the object is contructed.
4444
//|
4545
//| :param ~microcontroller.Pin pin_a: First pin to read pulses from.
4646
//| :param ~microcontroller.Pin pin_b: Second pin to read pulses from.
47+
//| :param int divisor: The divisor of the quadrature signal.
4748
//|
4849
//| For example::
4950
//|
@@ -61,10 +62,11 @@
6162
//| ...
6263
//|
6364
STATIC mp_obj_t rotaryio_incrementalencoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
64-
enum { ARG_pin_a, ARG_pin_b };
65+
enum { ARG_pin_a, ARG_pin_b, ARG_divisor };
6566
static const mp_arg_t allowed_args[] = {
6667
{ MP_QSTR_pin_a, MP_ARG_REQUIRED | MP_ARG_OBJ },
6768
{ MP_QSTR_pin_b, MP_ARG_REQUIRED | MP_ARG_OBJ },
69+
{ MP_QSTR_divisor, MP_ARG_INT, { .u_int = 4 } },
6870
};
6971
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
7072
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -77,6 +79,7 @@ STATIC mp_obj_t rotaryio_incrementalencoder_make_new(const mp_obj_type_t *type,
7779

7880
common_hal_rotaryio_incrementalencoder_construct(self, pin_a, pin_b);
7981

82+
common_hal_rotaryio_incrementalencoder_set_divisor(self, args[ARG_divisor].u_int);
8083
return MP_OBJ_FROM_PTR(self);
8184
}
8285

@@ -116,9 +119,38 @@ STATIC mp_obj_t rotaryio_incrementalencoder_obj___exit__(size_t n_args, const mp
116119
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rotaryio_incrementalencoder___exit___obj, 4, 4, rotaryio_incrementalencoder_obj___exit__);
117120

118121

122+
//| divisor: int
123+
//| """The divisor of the quadrature signal. Use 1 for encoders without
124+
//| detents, or encoders with 4 detents per cycle. Use 2 for encoders with 2
125+
//| detents per cycle. Use 4 for encoders with 1 detent per cycle."""
126+
//|
127+
STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_divisor(mp_obj_t self_in) {
128+
rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
129+
check_for_deinit(self);
130+
131+
return mp_obj_new_int(common_hal_rotaryio_incrementalencoder_get_divisor(self));
132+
}
133+
MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_get_divisor_obj, rotaryio_incrementalencoder_obj_get_divisor);
134+
135+
STATIC mp_obj_t rotaryio_incrementalencoder_obj_set_divisor(mp_obj_t self_in, mp_obj_t new_divisor) {
136+
rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
137+
check_for_deinit(self);
138+
139+
common_hal_rotaryio_incrementalencoder_set_divisor(self, mp_obj_get_int(new_divisor));
140+
return mp_const_none;
141+
}
142+
MP_DEFINE_CONST_FUN_OBJ_2(rotaryio_incrementalencoder_set_divisor_obj, rotaryio_incrementalencoder_obj_set_divisor);
143+
144+
const mp_obj_property_t rotaryio_incrementalencoder_divisor_obj = {
145+
.base.type = &mp_type_property,
146+
.proxy = {(mp_obj_t)&rotaryio_incrementalencoder_get_divisor_obj,
147+
(mp_obj_t)&rotaryio_incrementalencoder_set_divisor_obj,
148+
MP_ROM_NONE},
149+
};
150+
119151
//| position: int
120152
//| """The current position in terms of pulses. The number of pulses per rotation is defined by the
121-
//| specific hardware."""
153+
//| specific hardware and by the divisor."""
122154
//|
123155
STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_position(mp_obj_t self_in) {
124156
rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -150,6 +182,7 @@ STATIC const mp_rom_map_elem_t rotaryio_incrementalencoder_locals_dict_table[] =
150182
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
151183
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&rotaryio_incrementalencoder___exit___obj) },
152184
{ MP_ROM_QSTR(MP_QSTR_position), MP_ROM_PTR(&rotaryio_incrementalencoder_position_obj) },
185+
{ MP_ROM_QSTR(MP_QSTR_divisor), MP_ROM_PTR(&rotaryio_incrementalencoder_divisor_obj) },
153186
};
154187
STATIC MP_DEFINE_CONST_DICT(rotaryio_incrementalencoder_locals_dict, rotaryio_incrementalencoder_locals_dict_table);
155188

shared-bindings/rotaryio/IncrementalEncoder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,8 @@ extern bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incremental
3939
extern mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t *self);
4040
extern void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self,
4141
mp_int_t new_position);
42+
extern mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self);
43+
extern void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self,
44+
mp_int_t new_divisor);
4245

4346
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H

shared-module/rotaryio/IncrementalEncoder.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,25 @@
3030

3131
void shared_module_softencoder_state_init(rotaryio_incrementalencoder_obj_t *self, uint8_t quiescent_state) {
3232
self->state = quiescent_state;
33-
self->quarter_count = 0;
33+
self->sub_count = 0;
3434
common_hal_rotaryio_incrementalencoder_set_position(self, 0);
3535
}
3636

3737
void shared_module_softencoder_state_update(rotaryio_incrementalencoder_obj_t *self, uint8_t new_state) {
38-
#define BAD 7
3938
static const int8_t transitions[16] = {
4039
0, // 00 -> 00 no movement
4140
-1, // 00 -> 01 3/4 ccw (11 detent) or 1/4 ccw (00 at detent)
4241
+1, // 00 -> 10 3/4 cw or 1/4 cw
43-
BAD, // 00 -> 11 non-Gray-code transition
42+
0, // 00 -> 11 non-Gray-code transition
4443
+1, // 01 -> 00 2/4 or 4/4 cw
4544
0, // 01 -> 01 no movement
46-
BAD, // 01 -> 10 non-Gray-code transition
45+
0, // 01 -> 10 non-Gray-code transition
4746
-1, // 01 -> 11 4/4 or 2/4 ccw
4847
-1, // 10 -> 00 2/4 or 4/4 ccw
49-
BAD, // 10 -> 01 non-Gray-code transition
48+
0, // 10 -> 01 non-Gray-code transition
5049
0, // 10 -> 10 no movement
5150
+1, // 10 -> 11 4/4 or 2/4 cw
52-
BAD, // 11 -> 00 non-Gray-code transition
51+
0, // 11 -> 00 non-Gray-code transition
5352
+1, // 11 -> 01 1/4 or 3/4 cw
5453
-1, // 11 -> 10 1/4 or 3/4 ccw
5554
0, // 11 -> 11 no movement
@@ -59,20 +58,16 @@ void shared_module_softencoder_state_update(rotaryio_incrementalencoder_obj_t *s
5958
int idx = (self->state << 2) | new_state;
6059
self->state = new_state;
6160

62-
int8_t quarter_incr = transitions[idx];
63-
if (quarter_incr == BAD) {
64-
// Missed a transition. We don't know which way we're going, so do nothing.
65-
return;
66-
}
61+
int8_t sub_incr = transitions[idx];
6762

68-
self->quarter_count += quarter_incr;
63+
self->sub_count += sub_incr;
6964

70-
if (self->quarter_count >= 4) {
65+
if (self->sub_count >= self->divisor) {
7166
self->position += 1;
72-
self->quarter_count = 0;
73-
} else if (self->quarter_count <= -4) {
67+
self->sub_count = 0;
68+
} else if (self->sub_count <= -self->divisor) {
7469
self->position -= 1;
75-
self->quarter_count = 0;
70+
self->sub_count = 0;
7671
}
7772
}
7873

@@ -83,4 +78,12 @@ mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementa
8378
void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self, mp_int_t position) {
8479
self->position = position;
8580
}
81+
82+
mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self) {
83+
return self->divisor;
84+
}
85+
86+
void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self, mp_int_t divisor) {
87+
self->divisor = divisor;
88+
}
8689
#endif

0 commit comments

Comments
 (0)