Merge pull request #5468 from jepler/encoder-divisor

rotaryio: Add the ability to set the divisor
This commit is contained in:
Dan Halbert 2021-10-18 08:13:56 -04:00 committed by GitHub
commit 00aeb6b9d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 80 additions and 24 deletions

View File

@ -2976,6 +2976,10 @@ msgstr ""
msgid "division by zero" msgid "division by zero"
msgstr "" msgstr ""
#: ports/espressif/common-hal/rotaryio/IncrementalEncoder.c
msgid "divisor must be 4"
msgstr ""
#: py/objdeque.c #: py/objdeque.c
msgid "empty" msgid "empty"
msgstr "" msgstr ""

View File

@ -67,7 +67,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
set_eic_channel_data(self->eic_channel_b, (void *)self); set_eic_channel_data(self->eic_channel_b, (void *)self);
self->position = 0; self->position = 0;
self->quarter_count = 0; self->sub_count = 0;
shared_module_softencoder_state_init(self, shared_module_softencoder_state_init(self,
((uint8_t)gpio_get_pin_level(self->pin_a) << 1) | ((uint8_t)gpio_get_pin_level(self->pin_a) << 1) |

View File

@ -38,7 +38,8 @@ typedef struct {
uint8_t eic_channel_a; uint8_t eic_channel_a;
uint8_t eic_channel_b; uint8_t eic_channel_b;
uint8_t state; // <old A><old B> uint8_t state; // <old A><old B>
int8_t quarter_count; // count intermediate transitions between detents int8_t sub_count; // count intermediate transitions between detents
int8_t divisor; // Number of quadrature edges required per count
mp_int_t position; mp_int_t position;
} rotaryio_incrementalencoder_obj_t; } rotaryio_incrementalencoder_obj_t;

View File

@ -84,3 +84,13 @@ void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalenc
self->position = new_position; self->position = new_position;
pcnt_counter_clear(self->unit); pcnt_counter_clear(self->unit);
} }
mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self) {
return 4;
}
void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self, mp_int_t divisor) {
if (divisor != 4) {
mp_raise_ValueError(translate("divisor must be 4"));
}
}

View File

@ -36,7 +36,8 @@ typedef struct {
uint8_t pin_a; uint8_t pin_a;
uint8_t pin_b; uint8_t pin_b;
uint8_t state; // <old A><old B> uint8_t state; // <old A><old B>
int8_t quarter_count; // count intermediate transitions between detents int8_t sub_count; // count intermediate transitions between detents
int8_t divisor; // Number of quadrature edges required per count
mp_int_t position; mp_int_t position;
} rotaryio_incrementalencoder_obj_t; } rotaryio_incrementalencoder_obj_t;

View File

@ -73,7 +73,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
} }
self->position = 0; self->position = 0;
self->quarter_count = 0; self->sub_count = 0;
common_hal_rp2pio_statemachine_construct(&self->state_machine, common_hal_rp2pio_statemachine_construct(&self->state_machine,
encoder, MP_ARRAY_SIZE(encoder), encoder, MP_ARRAY_SIZE(encoder),

View File

@ -35,7 +35,8 @@ typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
rp2pio_statemachine_obj_t state_machine; rp2pio_statemachine_obj_t state_machine;
uint8_t state; // <old A><old B> uint8_t state; // <old A><old B>
int8_t quarter_count; // count intermediate transitions between detents int8_t sub_count; // count intermediate transitions between detents
int8_t divisor; // Number of quadrature edges required per count
bool swapped; // Did the pins need to be swapped to be sequential? bool swapped; // Did the pins need to be swapped to be sequential?
mp_int_t position; mp_int_t position;
} rotaryio_incrementalencoder_obj_t; } rotaryio_incrementalencoder_obj_t;

View File

@ -37,13 +37,14 @@
//| class IncrementalEncoder: //| class IncrementalEncoder:
//| """IncrementalEncoder determines the relative rotational position based on two series of pulses.""" //| """IncrementalEncoder determines the relative rotational position based on two series of pulses."""
//| //|
//| def __init__(self, pin_a: microcontroller.Pin, pin_b: microcontroller.Pin) -> None: //| def __init__(self, pin_a: microcontroller.Pin, pin_b: microcontroller.Pin, divisor: int = 4) -> None:
//| """Create an IncrementalEncoder object associated with the given pins. It tracks the positional //| """Create an IncrementalEncoder object associated with the given pins. It tracks the positional
//| state of an incremental rotary encoder (also known as a quadrature encoder.) Position is //| state of an incremental rotary encoder (also known as a quadrature encoder.) Position is
//| relative to the position when the object is contructed. //| relative to the position when the object is contructed.
//| //|
//| :param ~microcontroller.Pin pin_a: First pin to read pulses from. //| :param ~microcontroller.Pin pin_a: First pin to read pulses from.
//| :param ~microcontroller.Pin pin_b: Second pin to read pulses from. //| :param ~microcontroller.Pin pin_b: Second pin to read pulses from.
//| :param int divisor: The divisor of the quadrature signal.
//| //|
//| For example:: //| For example::
//| //|
@ -61,10 +62,11 @@
//| ... //| ...
//| //|
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) { 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) {
enum { ARG_pin_a, ARG_pin_b }; enum { ARG_pin_a, ARG_pin_b, ARG_divisor };
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pin_a, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_pin_a, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_pin_b, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_pin_b, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_divisor, MP_ARG_INT, { .u_int = 4 } },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); 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,
common_hal_rotaryio_incrementalencoder_construct(self, pin_a, pin_b); common_hal_rotaryio_incrementalencoder_construct(self, pin_a, pin_b);
common_hal_rotaryio_incrementalencoder_set_divisor(self, args[ARG_divisor].u_int);
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
} }
@ -116,9 +119,38 @@ STATIC mp_obj_t rotaryio_incrementalencoder_obj___exit__(size_t n_args, const mp
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rotaryio_incrementalencoder___exit___obj, 4, 4, rotaryio_incrementalencoder_obj___exit__); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rotaryio_incrementalencoder___exit___obj, 4, 4, rotaryio_incrementalencoder_obj___exit__);
//| divisor: int
//| """The divisor of the quadrature signal. Use 1 for encoders without
//| detents, or encoders with 4 detents per cycle. Use 2 for encoders with 2
//| detents per cycle. Use 4 for encoders with 1 detent per cycle."""
//|
STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_divisor(mp_obj_t self_in) {
rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return mp_obj_new_int(common_hal_rotaryio_incrementalencoder_get_divisor(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_get_divisor_obj, rotaryio_incrementalencoder_obj_get_divisor);
STATIC mp_obj_t rotaryio_incrementalencoder_obj_set_divisor(mp_obj_t self_in, mp_obj_t new_divisor) {
rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
common_hal_rotaryio_incrementalencoder_set_divisor(self, mp_obj_get_int(new_divisor));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(rotaryio_incrementalencoder_set_divisor_obj, rotaryio_incrementalencoder_obj_set_divisor);
const mp_obj_property_t rotaryio_incrementalencoder_divisor_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&rotaryio_incrementalencoder_get_divisor_obj,
(mp_obj_t)&rotaryio_incrementalencoder_set_divisor_obj,
MP_ROM_NONE},
};
//| position: int //| position: int
//| """The current position in terms of pulses. The number of pulses per rotation is defined by the //| """The current position in terms of pulses. The number of pulses per rotation is defined by the
//| specific hardware.""" //| specific hardware and by the divisor."""
//| //|
STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_position(mp_obj_t self_in) { STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_position(mp_obj_t self_in) {
rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in); 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[] =
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&rotaryio_incrementalencoder___exit___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&rotaryio_incrementalencoder___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_position), MP_ROM_PTR(&rotaryio_incrementalencoder_position_obj) }, { MP_ROM_QSTR(MP_QSTR_position), MP_ROM_PTR(&rotaryio_incrementalencoder_position_obj) },
{ MP_ROM_QSTR(MP_QSTR_divisor), MP_ROM_PTR(&rotaryio_incrementalencoder_divisor_obj) },
}; };
STATIC MP_DEFINE_CONST_DICT(rotaryio_incrementalencoder_locals_dict, rotaryio_incrementalencoder_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(rotaryio_incrementalencoder_locals_dict, rotaryio_incrementalencoder_locals_dict_table);

View File

@ -39,5 +39,8 @@ extern bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incremental
extern mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t *self); extern mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t *self);
extern void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self, extern void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self,
mp_int_t new_position); mp_int_t new_position);
extern mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self);
extern void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self,
mp_int_t new_divisor);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H #endif // MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H

View File

@ -30,26 +30,25 @@
void shared_module_softencoder_state_init(rotaryio_incrementalencoder_obj_t *self, uint8_t quiescent_state) { void shared_module_softencoder_state_init(rotaryio_incrementalencoder_obj_t *self, uint8_t quiescent_state) {
self->state = quiescent_state; self->state = quiescent_state;
self->quarter_count = 0; self->sub_count = 0;
common_hal_rotaryio_incrementalencoder_set_position(self, 0); common_hal_rotaryio_incrementalencoder_set_position(self, 0);
} }
void shared_module_softencoder_state_update(rotaryio_incrementalencoder_obj_t *self, uint8_t new_state) { void shared_module_softencoder_state_update(rotaryio_incrementalencoder_obj_t *self, uint8_t new_state) {
#define BAD 7
static const int8_t transitions[16] = { static const int8_t transitions[16] = {
0, // 00 -> 00 no movement 0, // 00 -> 00 no movement
-1, // 00 -> 01 3/4 ccw (11 detent) or 1/4 ccw (00 at detent) -1, // 00 -> 01 3/4 ccw (11 detent) or 1/4 ccw (00 at detent)
+1, // 00 -> 10 3/4 cw or 1/4 cw +1, // 00 -> 10 3/4 cw or 1/4 cw
BAD, // 00 -> 11 non-Gray-code transition 0, // 00 -> 11 non-Gray-code transition
+1, // 01 -> 00 2/4 or 4/4 cw +1, // 01 -> 00 2/4 or 4/4 cw
0, // 01 -> 01 no movement 0, // 01 -> 01 no movement
BAD, // 01 -> 10 non-Gray-code transition 0, // 01 -> 10 non-Gray-code transition
-1, // 01 -> 11 4/4 or 2/4 ccw -1, // 01 -> 11 4/4 or 2/4 ccw
-1, // 10 -> 00 2/4 or 4/4 ccw -1, // 10 -> 00 2/4 or 4/4 ccw
BAD, // 10 -> 01 non-Gray-code transition 0, // 10 -> 01 non-Gray-code transition
0, // 10 -> 10 no movement 0, // 10 -> 10 no movement
+1, // 10 -> 11 4/4 or 2/4 cw +1, // 10 -> 11 4/4 or 2/4 cw
BAD, // 11 -> 00 non-Gray-code transition 0, // 11 -> 00 non-Gray-code transition
+1, // 11 -> 01 1/4 or 3/4 cw +1, // 11 -> 01 1/4 or 3/4 cw
-1, // 11 -> 10 1/4 or 3/4 ccw -1, // 11 -> 10 1/4 or 3/4 ccw
0, // 11 -> 11 no movement 0, // 11 -> 11 no movement
@ -59,20 +58,16 @@ void shared_module_softencoder_state_update(rotaryio_incrementalencoder_obj_t *s
int idx = (self->state << 2) | new_state; int idx = (self->state << 2) | new_state;
self->state = new_state; self->state = new_state;
int8_t quarter_incr = transitions[idx]; int8_t sub_incr = transitions[idx];
if (quarter_incr == BAD) {
// Missed a transition. We don't know which way we're going, so do nothing.
return;
}
self->quarter_count += quarter_incr; self->sub_count += sub_incr;
if (self->quarter_count >= 4) { if (self->sub_count >= self->divisor) {
self->position += 1; self->position += 1;
self->quarter_count = 0; self->sub_count = 0;
} else if (self->quarter_count <= -4) { } else if (self->sub_count <= -self->divisor) {
self->position -= 1; self->position -= 1;
self->quarter_count = 0; self->sub_count = 0;
} }
} }
@ -83,4 +78,12 @@ mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementa
void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self, mp_int_t position) { void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self, mp_int_t position) {
self->position = position; self->position = position;
} }
mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self) {
return self->divisor;
}
void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self, mp_int_t divisor) {
self->divisor = divisor;
}
#endif #endif