Skip to content

Commit

Permalink
esp32/Counter: Add IRQ_ROLL_OVER, IRQ_ROLL_UNDER.
Browse files Browse the repository at this point in the history
esp32/Counter: Add IRQ_ROLL_OVER, IRQ_ROLL_UNDER.

Signed-off-by: Ihor Nehrutsa <[email protected]>
  • Loading branch information
IhorNehrutsa committed Feb 1, 2025
1 parent 3fee7bc commit b650e6f
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 23 deletions.
35 changes: 25 additions & 10 deletions docs/esp32/pcnt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ Methods
.. method:: Counter.value([value])

Get, and optionally set, the counter *value* as a signed 64-bit integer.
Attention: Setting the counter brokes the IRQ_MATCH and IRQ_ZERO events.

.. method:: Counter.irq(handler=None, trigger=Counter.IRQ_MATCH1 | Counter.IRQ_ZERO, value=0)
.. method:: Counter.irq(handler=None, trigger=Counter.IRQ_MATCH | Counter.IRQ_ZERO, value=0)

-*handler* specifies a function is called when the respective *trigger* event happens.
The callback function *handler* receives a single argument, which is the Counter object.
Expand All @@ -96,14 +97,16 @@ Methods

-*trigger* events may be:

- Counter.IRQ_MATCH1 triggered when the counter matches the match1 value.
- Counter.IRQ_MATCH triggered when the counter matches the match value.
- Counter.IRQ_ZERO triggered when the counter matches the 0.
- Counter.IRQ_ROLL_OVER triggered when the int16_t counter overloaded.
- Counter.IRQ_ROLL_UNDER triggered when the int16_t counter underloaded.

The default is - trigger=Counter.IRQ_MATCH1 | Counter.IRQ_ZERO.
The default is - trigger=Counter.IRQ_MATCH | Counter.IRQ_ZERO.
The events are triggered when the counter value and match value are identical, but
callbacks have always a latency.

- *value* sets a counter match1 value. When the counter matches these values,
- *value* sets a counter match value. When the counter matches these values,
a callback function can be called. They are 0 by default.

Attention: ``Counter.irq()`` resets counter to 0.
Expand All @@ -112,6 +115,18 @@ Attention: ``Counter.irq()`` resets counter to 0.

Returns the event status flags of the recent handled Counter interrupt as a bitmap.

===== ==== ======================= =============================================================
bit # mask trigger coment
===== ==== ======================= =============================================================
0 1 if zero event: 0 - when counting up, 1 - when counting down
2 4 Counter.IRQ_MATCH match value event when counting up
3 8 Counter.IRQ_MATCH match value event when counting down
4 16 Counter.IRQ_ROLL_UNDER roll under event
5 32 Counter.IRQ_ROLL_OVER roll over event
6 64 Counter.IRQ_ZERO zero event
===== ==== ======================= =============================================================


.. method:: Counter.id()

Returns id number.
Expand All @@ -133,7 +148,7 @@ Constants

Selects the counted edges.

.. data:: Counter.IRQ_MATCH1
.. data:: Counter.IRQ_MATCH
Counter.IRQ_ZERO

Selects callback triggers.
Expand Down Expand Up @@ -180,7 +195,7 @@ See `Quadrature encoder outputs.
Constructor
-----------

.. class:: Encoder(id, phase_a=None, phase_b=None, \*, x124=4, filter_ns=0, match1=0)
.. class:: Encoder(id, phase_a=None, phase_b=None, \*, x124=4, filter_ns=0, match=0)

The Encoder starts to count immediately. Filtering is disabled.

Expand All @@ -203,7 +218,7 @@ Constructor

These keywords are the same as the Counter keywords, see above:
- *filter_ns*
- *match1*
- *match*

Methods
-------
Expand All @@ -218,7 +233,7 @@ in the constructor and internal hardware PCNT initialization.
Constants
---------

.. data:: Encoder.IRQ_MATCH1
.. data:: Encoder.IRQ_MATCH
Encoder.IRQ_ZERO

Selects callback triggers.
Expand All @@ -237,13 +252,13 @@ Constants
n += 1
print('irq_handler2()', self.id(), self.value(), n)

enc = Encoder(0, phase_a=Pin(17, mode=Pin.IN), phase_b=Pin(16, mode=Pin.IN), match1=1000)
enc = Encoder(0, phase_a=Pin(17, mode=Pin.IN), phase_b=Pin(16, mode=Pin.IN), match=1000)

enc.pause()
flt = enc.filter() # return current filter value.
enc.filter(10_000) # filter delay is 10ms
c = enc.value(0) # get current encoder value, set the encoder value to 0
enc.irq(irq_handler1, Encoder.IRQ_MATCH1) # set irq handler
enc.irq(irq_handler1, Encoder.IRQ_MATCH) # set irq handler
enc.resume()

_c = None
Expand Down
77 changes: 64 additions & 13 deletions ports/esp32/machine_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,28 +78,42 @@ static void IRAM_ATTR pcnt_intr_handler(void *arg) {
// self->event_status = PCNT.status_unit[id].val;
pcnt_get_event_status(id, &self->event_status);
if (self->event_status & PCNT_EVT_H_LIM) {
// when counting up
// debug_printf("H");
self->counter += INT16_ROLL;
self->counter_accum += INT16_ROLL;
if (self->handler_roll_over != MP_OBJ_NULL) {
mp_sched_schedule(self->handler_roll_over, MP_OBJ_FROM_PTR(self));
mp_hal_wake_main_task_from_isr();
}
} else if (self->event_status & PCNT_EVT_L_LIM) {
// when counting down
// debug_printf("L");
self->counter -= INT16_ROLL;
self->counter_accum -= INT16_ROLL;
if (self->handler_roll_under != MP_OBJ_NULL) {
mp_sched_schedule(self->handler_roll_under, MP_OBJ_FROM_PTR(self));
mp_hal_wake_main_task_from_isr();
}
}

if (self->event_status & PCNT_EVT_THRES_1) {
// counting up
// when counting up & treshold value > 0
// debug_printf("1");
if (self->counter_accum == self->counter_match) {
mp_sched_schedule(self->handler_match, MP_OBJ_FROM_PTR(self));
mp_hal_wake_main_task_from_isr();
}
}
if (self->event_status & PCNT_EVT_THRES_0) {
// counting down
} else if (self->event_status & PCNT_EVT_THRES_0) {
// when counting down & treshold value < 0
// debug_printf("0");
if (self->counter_accum == self->counter_match + INT16_ROLL) {
mp_sched_schedule(self->handler_match, MP_OBJ_FROM_PTR(self));
mp_hal_wake_main_task_from_isr();
}
}
if (self->event_status & PCNT_EVT_ZERO) {
// when counting up/down
// debug_printf("Z");
if (self->counter == 0) {
mp_sched_schedule(self->handler_zero, MP_OBJ_FROM_PTR(self));
mp_hal_wake_main_task_from_isr();
Expand Down Expand Up @@ -161,6 +175,12 @@ static void set_filter_value(pcnt_unit_t unit, int16_t value) {
}

static void pcnt_disable_events(mp_pcnt_obj_t *self) {
if (self->handler_roll_over != MP_OBJ_NULL) {
self->handler_roll_over = MP_OBJ_NULL;
}
if (self->handler_roll_under != MP_OBJ_NULL) {
self->handler_roll_under = MP_OBJ_NULL;
}
if (self->handler_match != MP_OBJ_NULL) {
check_esp_err(pcnt_event_disable(self->unit, PCNT_EVT_THRES_1));
check_esp_err(pcnt_event_disable(self->unit, PCNT_EVT_THRES_0));
Expand All @@ -183,6 +203,8 @@ static void reset(mp_pcnt_obj_t *self) {
self->counter_match = 0;
self->handler_match = MP_OBJ_NULL;
self->handler_zero = MP_OBJ_NULL;
self->handler_roll_over = MP_OBJ_NULL;
self->handler_roll_under = MP_OBJ_NULL;
self->event_status = 0;

self->filter = 0;
Expand All @@ -192,7 +214,6 @@ static void reset(mp_pcnt_obj_t *self) {
static void pcnt_deinit(mp_pcnt_obj_t *self) {
if (self != NULL) {
check_esp_err(pcnt_counter_pause(self->unit));

check_esp_err(pcnt_intr_disable(self->unit));

check_esp_err(pcnt_event_disable(self->unit, PCNT_EVT_L_LIM));
Expand All @@ -202,6 +223,7 @@ static void pcnt_deinit(mp_pcnt_obj_t *self) {
check_esp_err(pcnt_set_pin(self->unit, PCNT_CHANNEL_0, PCNT_PIN_NOT_USED, PCNT_PIN_NOT_USED));
check_esp_err(pcnt_set_pin(self->unit, PCNT_CHANNEL_1, PCNT_PIN_NOT_USED, PCNT_PIN_NOT_USED));

check_esp_err(pcnt_counter_clear(self->unit));
reset(self);
pcnts[self->unit] = NULL;
}
Expand Down Expand Up @@ -317,7 +339,7 @@ static mp_obj_t machine_PCNT_irq(size_t n_pos_args, const mp_obj_t *pos_args, mp
mp_obj_t handler = args[ARG_handler].u_obj;
mp_uint_t trigger = args[ARG_trigger].u_int;

if (trigger & ~(PCNT_EVT_THRES_1 | PCNT_EVT_ZERO)) {
if (trigger & ~(PCNT_EVT_THRES_1 | PCNT_EVT_ZERO | PCNT_EVT_H_LIM | PCNT_EVT_L_LIM)) {
mp_raise_ValueError(MP_ERROR_TEXT("trigger"));
}

Expand All @@ -333,6 +355,12 @@ static mp_obj_t machine_PCNT_irq(size_t n_pos_args, const mp_obj_t *pos_args, mp
check_esp_err(pcnt_event_disable(self->unit, PCNT_EVT_ZERO));
self->handler_zero = MP_OBJ_NULL;
}
if (trigger & PCNT_EVT_H_LIM) {
self->handler_roll_over = MP_OBJ_NULL;
}
if (trigger & PCNT_EVT_L_LIM) {
self->handler_roll_under = MP_OBJ_NULL;
}
} else {
if (trigger & PCNT_EVT_THRES_1) {
if (args[ARG_value].u_obj != MP_OBJ_NULL) {
Expand Down Expand Up @@ -362,6 +390,12 @@ static mp_obj_t machine_PCNT_irq(size_t n_pos_args, const mp_obj_t *pos_args, mp
check_esp_err(pcnt_event_enable(self->unit, PCNT_EVT_THRES_1));
check_esp_err(pcnt_event_enable(self->unit, PCNT_EVT_THRES_0));
}
if (trigger & PCNT_EVT_H_LIM) {
self->handler_roll_over = handler;
}
if (trigger & PCNT_EVT_L_LIM) {
self->handler_roll_under = handler;
}
if (trigger & PCNT_EVT_ZERO) {
/*
int16_t count;
Expand Down Expand Up @@ -571,19 +605,30 @@ static mp_obj_t machine_Counter_init(size_t n_args, const mp_obj_t *args, mp_map
MP_DEFINE_CONST_FUN_OBJ_KW(machine_Counter_init_obj, 1, machine_Counter_init);

static void common_print_kw(const mp_print_t *print, mp_pcnt_obj_t *self) {
if (self->handler_roll_over != MP_OBJ_NULL) {
mp_printf(print, ", roll_over=%ld", INT16_ROLL);
}
if (self->handler_roll_under != MP_OBJ_NULL) {
mp_printf(print, ", roll_under=%ld", -INT16_ROLL);
}
if (self->handler_match != MP_OBJ_NULL) {
mp_printf(print, ", match1=%ld", self->match);
mp_printf(print, ", match=%ld", self->match);
}
if (self->handler_zero != MP_OBJ_NULL) {
mp_printf(print, ", match=0");
mp_printf(print, ", match0=0");
}
mp_printf(print, ", filter_ns=%d)", filter_to_ns(self->filter));
}

static void machine_Counter_print(const mp_print_t *print, mp_obj_t self_obj, mp_print_kind_t kind) {
mp_pcnt_obj_t *self = MP_OBJ_TO_PTR(self_obj);

mp_printf(print, "Counter(%u, src=Pin(%u)", self->unit, self->aPinNumber);
mp_printf(print, "Counter(%u", self->unit);
if (self->aPinNumber == PCNT_PIN_NOT_USED) {
mp_printf(print, ")");
return;
}
mp_printf(print, "), src=Pin(%u)", self->aPinNumber);
if (self->x124 < 0) {
mp_printf(print, ", _src=Pin(%u)", self->bPinNumber);
} else {
Expand Down Expand Up @@ -611,7 +656,9 @@ static void machine_Counter_print(const mp_print_t *print, mp_obj_t self_obj, mp

#define COMMON_CONSTANTS \
{ MP_ROM_QSTR(MP_QSTR_IRQ_ZERO), MP_ROM_INT(PCNT_EVT_ZERO) }, \
{ MP_ROM_QSTR(MP_QSTR_IRQ_MATCH1), MP_ROM_INT(PCNT_EVT_THRES_1) }
{ MP_ROM_QSTR(MP_QSTR_IRQ_ROLL_OVER), MP_ROM_INT(PCNT_EVT_H_LIM) }, \
{ MP_ROM_QSTR(MP_QSTR_IRQ_ROLL_UNDER), MP_ROM_INT(PCNT_EVT_L_LIM) }, \
{ MP_ROM_QSTR(MP_QSTR_IRQ_MATCH), MP_ROM_INT(PCNT_EVT_THRES_1) }

static const mp_rom_map_elem_t machine_Counter_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_Counter_init_obj) },
Expand Down Expand Up @@ -755,8 +802,12 @@ MP_DEFINE_CONST_FUN_OBJ_KW(machine_Encoder_init_obj, 1, machine_Encoder_init);

static void machine_Encoder_print(const mp_print_t *print, mp_obj_t self_obj, mp_print_kind_t kind) {
mp_pcnt_obj_t *self = MP_OBJ_TO_PTR(self_obj);

mp_printf(print, "Encoder(%u, phase_a=Pin(%u), phase_b=Pin(%u), x124=%d", self->unit, self->aPinNumber, self->bPinNumber, self->x124);
mp_printf(print, "Encoder(%u", self->unit);
if (self->aPinNumber == PCNT_PIN_NOT_USED) {
mp_printf(print, ")");
return;
}
mp_printf(print, ", phase_a=Pin(%u), phase_b=Pin(%u), x124=%d", self->aPinNumber, self->bPinNumber, self->x124);
common_print_kw(print, self);
}

Expand Down
2 changes: 2 additions & 0 deletions ports/esp32/machine_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ typedef struct _mp_pcnt_obj_t {
counter_t counter_match; // (match - counter) - (match - counter) % INT16_ROLL
mp_obj_t handler_match;
mp_obj_t handler_zero;
mp_obj_t handler_roll_over;
mp_obj_t handler_roll_under;
uint32_t event_status;

int filter;
Expand Down

0 comments on commit b650e6f

Please sign in to comment.