From 6d025a239e1c6d6ff786655c48e6927d923bb4f1 Mon Sep 17 00:00:00 2001 From: Dominic Davis-Foster Date: Mon, 28 Mar 2022 08:55:04 +0100 Subject: [PATCH] Add espressif rotaryio divisor support. --- .../common-hal/rotaryio/IncrementalEncoder.c | 53 ++++++++++++++++--- .../common-hal/rotaryio/IncrementalEncoder.h | 1 + ports/espressif/peripherals/pcnt.c | 13 ++++- ports/espressif/peripherals/pcnt.h | 1 + shared-bindings/rotaryio/IncrementalEncoder.c | 2 +- 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c index 676e99289d..db50e8db93 100644 --- a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c @@ -29,7 +29,6 @@ #include "common-hal/microcontroller/Pin.h" #include "py/runtime.h" -#include "supervisor/shared/translate.h" void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self, const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) { @@ -37,7 +36,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode claim_pin(pin_b); // Prepare configuration for the PCNT unit - const pcnt_config_t pcnt_config = { + pcnt_config_t pcnt_config = { // Set PCNT input signal and control GPIOs .pulse_gpio_num = pin_a->number, .ctrl_gpio_num = pin_b->number, @@ -51,11 +50,46 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode }; // Initialize PCNT unit - const int8_t unit = peripherals_pcnt_init(pcnt_config); + const int8_t unit = peripherals_pcnt_get_unit(pcnt_config); if (unit == -1) { mp_raise_RuntimeError(translate("All PCNT units in use")); } + pcnt_unit_config(&pcnt_config); + + if ((self->divisor == 2) || (self->divisor == 1)) { + // Setup channel 1 for divisor=2 or divisor=1 + pcnt_config.pulse_gpio_num = pin_b->number; // What was control is now signal + pcnt_config.ctrl_gpio_num = pin_a->number; // What was signal is now control + pcnt_config.channel = PCNT_CHANNEL_1; + // What to do on the positive / negative edge of pulse input? + pcnt_config.pos_mode = PCNT_COUNT_DEC; // Count up on the positive edge + pcnt_config.neg_mode = PCNT_COUNT_INC; // Keep the counter value on the negative edge + // What to do when control input is low or high? + pcnt_config.lctrl_mode = PCNT_MODE_KEEP; // Keep the primary counter mode if low + pcnt_config.hctrl_mode = PCNT_MODE_REVERSE; // Reverse counting direction if high + } else { + // Ensure channel 1 is disabled for divisor=4 + pcnt_config.pulse_gpio_num = pin_b->number; // What was control is now signal + pcnt_config.ctrl_gpio_num = pin_a->number; // What was signal is now control + pcnt_config.channel = PCNT_CHANNEL_1; + // What to do on the positive / negative edge of pulse input? + pcnt_config.pos_mode = PCNT_COUNT_DIS; // Disabled + pcnt_config.neg_mode = PCNT_COUNT_DIS; // Disabled + // What to do when control input is low or high? + pcnt_config.lctrl_mode = PCNT_MODE_DISABLE; // Disabled + pcnt_config.hctrl_mode = PCNT_MODE_DISABLE; // Disabled + } + + pcnt_unit_config(&pcnt_config); + + // Initialize PCNT's counter + pcnt_counter_pause(pcnt_config.unit); + pcnt_counter_clear(pcnt_config.unit); + + // Everything is set up, now go to counting + pcnt_counter_resume(pcnt_config.unit); + self->pin_a = pin_a->number; self->pin_b = pin_b->number; self->unit = (pcnt_unit_t)unit; @@ -77,7 +111,12 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t *self) { int16_t count; pcnt_get_counter_value(self->unit, &count); - return (count / 2) + self->position; + + if ((self->divisor == 4) || (self->divisor == 2)) { + return (count / 2) + self->position; + } else { + return (count) + self->position; + } } void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self, @@ -87,11 +126,9 @@ void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalenc } mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self) { - return 4; + return self->divisor; } 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")); - } + self->divisor = divisor; } diff --git a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.h b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.h index 4982c39103..c43cd62bf6 100644 --- a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.h +++ b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.h @@ -35,6 +35,7 @@ typedef struct { uint8_t pin_a, pin_b; mp_int_t position; pcnt_unit_t unit; + int8_t divisor; // Number of quadrature edges required per count } rotaryio_incrementalencoder_obj_t; #endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_ROTARYIO_INCREMENTALENCODER_H diff --git a/ports/espressif/peripherals/pcnt.c b/ports/espressif/peripherals/pcnt.c index e4578a2791..d1b85fbb13 100644 --- a/ports/espressif/peripherals/pcnt.c +++ b/ports/espressif/peripherals/pcnt.c @@ -37,7 +37,7 @@ void peripherals_pcnt_reset(void) { } } -int peripherals_pcnt_init(pcnt_config_t pcnt_config) { +int peripherals_pcnt_get_unit(pcnt_config_t pcnt_config) { // Look for available pcnt unit for (uint8_t i = 0; i <= 3; i++) { if (pcnt_unit_state[i] == PCNT_UNIT_INACTIVE) { @@ -49,6 +49,17 @@ int peripherals_pcnt_init(pcnt_config_t pcnt_config) { } } + return pcnt_config.unit; +} + +int peripherals_pcnt_init(pcnt_config_t pcnt_config) { + // Look for available pcnt unit + + const int8_t unit = peripherals_pcnt_get_unit(pcnt_config); + if (unit == -1) { + return -1; + } + // Initialize PCNT unit pcnt_unit_config(&pcnt_config); diff --git a/ports/espressif/peripherals/pcnt.h b/ports/espressif/peripherals/pcnt.h index b2bae7b371..c73c41a232 100644 --- a/ports/espressif/peripherals/pcnt.h +++ b/ports/espressif/peripherals/pcnt.h @@ -31,6 +31,7 @@ #include "soc/pcnt_struct.h" extern int peripherals_pcnt_init(pcnt_config_t pcnt_config); +extern int peripherals_pcnt_get_unit(pcnt_config_t pcnt_config); extern void peripherals_pcnt_deinit(pcnt_unit_t *unit); extern void peripherals_pcnt_reset(void); diff --git a/shared-bindings/rotaryio/IncrementalEncoder.c b/shared-bindings/rotaryio/IncrementalEncoder.c index ef218ba024..12202a2649 100644 --- a/shared-bindings/rotaryio/IncrementalEncoder.c +++ b/shared-bindings/rotaryio/IncrementalEncoder.c @@ -77,9 +77,9 @@ STATIC mp_obj_t rotaryio_incrementalencoder_make_new(const mp_obj_type_t *type, rotaryio_incrementalencoder_obj_t *self = m_new_obj(rotaryio_incrementalencoder_obj_t); self->base.type = &rotaryio_incrementalencoder_type; + common_hal_rotaryio_incrementalencoder_set_divisor(self, args[ARG_divisor].u_int); 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); }