diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index a1c23f55b2..22bc4261e4 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -2976,6 +2976,10 @@ msgstr "" msgid "division by zero" msgstr "" +#: ports/espressif/common-hal/rotaryio/IncrementalEncoder.c +msgid "divisor must be 4" +msgstr "" + #: py/objdeque.c msgid "empty" msgstr "" diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c index 2a30142ab3..dc9cf65334 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c @@ -67,7 +67,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode set_eic_channel_data(self->eic_channel_b, (void *)self); self->position = 0; - self->quarter_count = 0; + self->sub_count = 0; shared_module_softencoder_state_init(self, ((uint8_t)gpio_get_pin_level(self->pin_a) << 1) | diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h index 2560997a97..f9223ddc7c 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h @@ -38,7 +38,8 @@ typedef struct { uint8_t eic_channel_a; uint8_t eic_channel_b; uint8_t state; // - 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; } rotaryio_incrementalencoder_obj_t; diff --git a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c index 59fa54880a..b36c79b4f6 100644 --- a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c @@ -84,3 +84,13 @@ void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalenc self->position = new_position; 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")); + } +} diff --git a/ports/nrf/common-hal/rotaryio/IncrementalEncoder.h b/ports/nrf/common-hal/rotaryio/IncrementalEncoder.h index 3693131056..86fbe5475f 100644 --- a/ports/nrf/common-hal/rotaryio/IncrementalEncoder.h +++ b/ports/nrf/common-hal/rotaryio/IncrementalEncoder.h @@ -36,7 +36,8 @@ typedef struct { uint8_t pin_a; uint8_t pin_b; uint8_t state; // - 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; } rotaryio_incrementalencoder_obj_t; diff --git a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c index 00cf54b221..649c9421e0 100644 --- a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c @@ -73,7 +73,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode } self->position = 0; - self->quarter_count = 0; + self->sub_count = 0; common_hal_rp2pio_statemachine_construct(&self->state_machine, encoder, MP_ARRAY_SIZE(encoder), diff --git a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.h b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.h index 6745d95a1c..812ba09821 100644 --- a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.h +++ b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.h @@ -35,7 +35,8 @@ typedef struct { mp_obj_base_t base; rp2pio_statemachine_obj_t state_machine; uint8_t state; // - 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? mp_int_t position; } rotaryio_incrementalencoder_obj_t; diff --git a/shared-bindings/rotaryio/IncrementalEncoder.c b/shared-bindings/rotaryio/IncrementalEncoder.c index 9590df5c42..ef218ba024 100644 --- a/shared-bindings/rotaryio/IncrementalEncoder.c +++ b/shared-bindings/rotaryio/IncrementalEncoder.c @@ -37,13 +37,14 @@ //| class IncrementalEncoder: //| """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 //| state of an incremental rotary encoder (also known as a quadrature encoder.) Position is //| relative to the position when the object is contructed. //| //| :param ~microcontroller.Pin pin_a: First 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:: //| @@ -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) { - enum { ARG_pin_a, ARG_pin_b }; + enum { ARG_pin_a, ARG_pin_b, ARG_divisor }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pin_a, 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_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_set_divisor(self, args[ARG_divisor].u_int); 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__); +//| 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 //| """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) { 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___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_divisor), MP_ROM_PTR(&rotaryio_incrementalencoder_divisor_obj) }, }; STATIC MP_DEFINE_CONST_DICT(rotaryio_incrementalencoder_locals_dict, rotaryio_incrementalencoder_locals_dict_table); diff --git a/shared-bindings/rotaryio/IncrementalEncoder.h b/shared-bindings/rotaryio/IncrementalEncoder.h index 51bf7bd9f6..45551c3e41 100644 --- a/shared-bindings/rotaryio/IncrementalEncoder.h +++ b/shared-bindings/rotaryio/IncrementalEncoder.h @@ -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 void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self, 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 diff --git a/shared-module/rotaryio/IncrementalEncoder.c b/shared-module/rotaryio/IncrementalEncoder.c index 330895606e..89dea01cfe 100644 --- a/shared-module/rotaryio/IncrementalEncoder.c +++ b/shared-module/rotaryio/IncrementalEncoder.c @@ -30,26 +30,25 @@ void shared_module_softencoder_state_init(rotaryio_incrementalencoder_obj_t *self, uint8_t quiescent_state) { self->state = quiescent_state; - self->quarter_count = 0; + self->sub_count = 0; common_hal_rotaryio_incrementalencoder_set_position(self, 0); } void shared_module_softencoder_state_update(rotaryio_incrementalencoder_obj_t *self, uint8_t new_state) { - #define BAD 7 static const int8_t transitions[16] = { 0, // 00 -> 00 no movement -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 - BAD, // 00 -> 11 non-Gray-code transition + 0, // 00 -> 11 non-Gray-code transition +1, // 01 -> 00 2/4 or 4/4 cw 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, // 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 +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 -> 10 1/4 or 3/4 ccw 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; self->state = new_state; - int8_t quarter_incr = transitions[idx]; - if (quarter_incr == BAD) { - // Missed a transition. We don't know which way we're going, so do nothing. - return; - } + int8_t sub_incr = transitions[idx]; - 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->quarter_count = 0; - } else if (self->quarter_count <= -4) { + self->sub_count = 0; + } else if (self->sub_count <= -self->divisor) { 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) { 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