From 9d2bd359d6f3992d5bca4258ef68c14e0eb097fb Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Mon, 16 Nov 2020 15:49:29 +0200 Subject: [PATCH 1/8] ESP32: Add EspError exception --- ports/esp32/cmodules/esp_err/esp_err.c | 154 ++++++++++++++++++++ ports/esp32/cmodules/esp_err/esp_error.h | 4 + ports/esp32/cmodules/esp_err/micropython.mk | 8 + 3 files changed, 166 insertions(+) create mode 100644 ports/esp32/cmodules/esp_err/esp_err.c create mode 100644 ports/esp32/cmodules/esp_err/esp_error.h create mode 100644 ports/esp32/cmodules/esp_err/micropython.mk diff --git a/ports/esp32/cmodules/esp_err/esp_err.c b/ports/esp32/cmodules/esp_err/esp_err.c new file mode 100644 index 0000000000000..67f627b569365 --- /dev/null +++ b/ports/esp32/cmodules/esp_err/esp_err.c @@ -0,0 +1,154 @@ +/* + * This file was generated by micropython-extmod-generator https://github.com/prusnak/micropython-extmod-generator + * from Python stab file esp_err.py + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Ihor Nehrutsa + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* +Wrapped around +https://github.com/espressif/esp-idf/blob/master/components/esp_common/include/esp_err.h +*/ + +#define MODULE_ESP_ERR_ENABLED (1) // you may relocate this line to the mpconfigport.h +#if MODULE_ESP_ERR_ENABLED + +// Include required definitions first +#include "py/obj.h" +//#include "py/objstr.h" +//#include "py/objtuple.h" +//#include "py/runtime.h" +//#include "py/builtin.h" + +#include "py/objexcept.h" + +//#include "esp_error.h" + +/* +// Example how to raise ESP exception from C code +esp_err_t err = pcnt_event_disable(self->unit, evt_type); +if (err != ESP_OK) + raise_esp_error(err); +*/ + +// Defining classes +// class EspError(Exception): +typedef struct _mp_obj_esp_err_EspError_t { + mp_obj_base_t base; +} mp_obj_esp_err_EspError_t; + +/*STATIC */const mp_obj_type_t mp_type_EspError; +/* +// Defining EspError methods +// def EspError.__init__(self, error_code: int=0, error_msg: str='') +STATIC mp_obj_t esp_err_EspError_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 2, false); + self->base.type = &mp_type_EspError; + + mp_obj_esp_err_EspError_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t error_code = mp_obj_get_int(args[1]); + const char* error_msg = mp_obj_str_get_str(args[2]); + + //TODO: Your code here + return MP_OBJ_FROM_PTR(self); +} +*/ +/* +STATIC mp_obj_t esp_err_EspError_print(const mp_print_t *print, mp_obj_t self_obj, mp_print_kind_t kind) { + esp_err_EspError_obj_t *self = MP_OBJ_TO_PTR(self_obj); + mp_printf(print, "EspError()"); + + //TODO: Your code here +} +*/ + +// EspError stuff +// Register class methods +STATIC const mp_rom_map_elem_t esp_err_EspError_locals_dict_table[] = { + //{ MP_ROM_QSTR(MP_QSTR_ESP_ERR_FLASH_BASE), MP_ROM_INT(ESP_ERR_FLASH_BASE) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_INVALID_ARG), MP_ROM_INT(ESP_ERR_INVALID_ARG) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_INVALID_CRC), MP_ROM_INT(ESP_ERR_INVALID_CRC) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_INVALID_MAC), MP_ROM_INT(ESP_ERR_INVALID_MAC) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_INVALID_RESPONSE), MP_ROM_INT(ESP_ERR_INVALID_RESPONSE) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_INVALID_SIZE), MP_ROM_INT(ESP_ERR_INVALID_SIZE) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_INVALID_STATE), MP_ROM_INT(ESP_ERR_INVALID_STATE) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_INVALID_VERSION), MP_ROM_INT(ESP_ERR_INVALID_VERSION) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_MESH_BASE), MP_ROM_INT(ESP_ERR_MESH_BASE) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_NOT_FOUND), MP_ROM_INT(ESP_ERR_NOT_FOUND) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_NOT_SUPPORTED), MP_ROM_INT(ESP_ERR_NOT_SUPPORTED) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_NO_MEM), MP_ROM_INT(ESP_ERR_NO_MEM) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_TIMEOUT), MP_ROM_INT(ESP_ERR_TIMEOUT) }, + { MP_ROM_QSTR(MP_QSTR_ESP_ERR_WIFI_BASE), MP_ROM_INT(ESP_ERR_WIFI_BASE) }, + { MP_ROM_QSTR(MP_QSTR_ESP_FAIL), MP_ROM_INT(ESP_FAIL) }, + { MP_ROM_QSTR(MP_QSTR_ESP_OK), MP_ROM_INT(ESP_OK) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp_err_EspError_locals_dict, esp_err_EspError_locals_dict_table); + +// Create the class-object itself +#if 1 +const mp_obj_type_t mp_type_EspError = { + { &mp_type_type }, + .name = MP_QSTR_EspError, + + //.make_new = esp_err_EspError_make_new, + //.print = esp_err_EspError_print, + .locals_dict = (mp_obj_dict_t*)&esp_err_EspError_locals_dict, + + .print = mp_obj_exception_print, + .make_new = mp_obj_exception_make_new, + .attr = mp_obj_exception_attr, + .parent = &mp_type_Exception, +}; +#else +#error The same ?, but raise Guru Meditation Error +MP_DEFINE_EXCEPTION(EspError, Exception) +#endif + +// module stuff +// Set up the module properties +STATIC const mp_rom_map_elem_t esp_err_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp_err) }, + { MP_ROM_QSTR(MP_QSTR_EspError), MP_ROM_PTR(&mp_type_EspError) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp_err_globals, esp_err_globals_table); + +// Define the module object +const mp_obj_module_t esp_err_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp_err_globals, +}; +// Register the module +MP_REGISTER_MODULE(MP_QSTR_esp_err, esp_err_cmodule, MODULE_ESP_ERR_ENABLED); + +/* +// To call from C modules use like: + mp_raise_msg_varg(&mp_type_EspError, MP_ERROR_TEXT("An error message %d"), val); +*/ +/* +// Function to call from C modules +NORETURN void mp_raise_EspError(mp_rom_error_text_t msg) { + mp_raise_msg(&mp_type_EspError, msg); +} +*/ + +#endif // MODULE_ESP_ERR_ENABLED diff --git a/ports/esp32/cmodules/esp_err/esp_error.h b/ports/esp32/cmodules/esp_err/esp_error.h new file mode 100644 index 0000000000000..d4d99c66a2c4c --- /dev/null +++ b/ports/esp32/cmodules/esp_err/esp_error.h @@ -0,0 +1,4 @@ +const mp_obj_type_t esp_err_EspError_type; + +#define raise_esp_error(err) mp_raise_msg_varg(&esp_err_EspError_type, MP_ERROR_TEXT("%d(0x%X) - "#err), err, err); + \ No newline at end of file diff --git a/ports/esp32/cmodules/esp_err/micropython.mk b/ports/esp32/cmodules/esp_err/micropython.mk new file mode 100644 index 0000000000000..0e39448b6bee7 --- /dev/null +++ b/ports/esp32/cmodules/esp_err/micropython.mk @@ -0,0 +1,8 @@ +MOD_DIR := $(USERMOD_DIR) + +# Add all C files to SRC_USERMOD. +SRC_USERMOD += $(MOD_DIR)/esp_err.c + +# We can add our module folder to include paths if needed +# This is not actually needed in this example. +CFLAGS_USERMOD += -I$(MOD_DIR) From a71ec8dbe24ebcfbe8b31e5bc699e5b453976c8d Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Mon, 16 Nov 2020 15:50:58 +0200 Subject: [PATCH 2/8] ESP32: Add Pulse counter and Quadrature encoder --- ports/esp32/cmodules/pcnt/micropython.mk | 8 + ports/esp32/cmodules/pcnt/pcnt.c | 1363 ++++++++++++++++++++++ ports/esp32/cmodules/pcnt/pcnt_.h | 43 + 3 files changed, 1414 insertions(+) create mode 100644 ports/esp32/cmodules/pcnt/micropython.mk create mode 100644 ports/esp32/cmodules/pcnt/pcnt.c create mode 100644 ports/esp32/cmodules/pcnt/pcnt_.h diff --git a/ports/esp32/cmodules/pcnt/micropython.mk b/ports/esp32/cmodules/pcnt/micropython.mk new file mode 100644 index 0000000000000..6f86435a2fdff --- /dev/null +++ b/ports/esp32/cmodules/pcnt/micropython.mk @@ -0,0 +1,8 @@ +MOD_DIR := $(USERMOD_DIR) + +# Add all C files to SRC_USERMOD. +SRC_USERMOD += $(MOD_DIR)/pcnt.c + +# We can add our module folder to include paths if needed +# This is not actually needed in this example. +CFLAGS_USERMOD += -I$(MOD_DIR) diff --git a/ports/esp32/cmodules/pcnt/pcnt.c b/ports/esp32/cmodules/pcnt/pcnt.c new file mode 100644 index 0000000000000..65dacc1b817c4 --- /dev/null +++ b/ports/esp32/cmodules/pcnt/pcnt.c @@ -0,0 +1,1363 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * This file was generated by micropython-extmod-generator https://github.com/prusnak/micropython-extmod-generator + * from Python stab file pcnt.py + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Ihor Nehrutsa + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* +ESP32 Pulse Counter +https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html +Wrapped around +https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/pcnt.h +https://github.com/espressif/esp-idf/blob/master/components/hal/include/hal/pcnt_types.h +https://github.com/espressif/esp-idf/blob/master/components/driver/pcnt.c +See also +https://github.com/espressif/esp-idf/tree/master/examples/peripherals/pcnt/pulse_count_event +*/ + +#define MODULE_PCNT_ENABLED (1) // you may relocate this line to the mpconfigport.h +#if MODULE_PCNT_ENABLED + +#include "py/obj.h" +#include "py/runtime.h" +#include "driver/pcnt.h" + +#include "../esp_err/esp_error.h" +#include "pcnt_.h" + +//--------------------------------------- +static int machine_pin_get_gpio(mp_obj_t pin_in) +{ + if (MP_OBJ_IS_INT(pin_in)) { + int wanted_pin = mp_obj_get_int(pin_in); + if (!GPIO_IS_VALID_GPIO(wanted_pin)) { + mp_raise_ValueError(MP_ERROR_TEXT("ESP PCNT invalid pin number")); + } + return wanted_pin; + } + return machine_pin_get_id(pin_in); +} +//--------------------------------------- + +/* +// Example exception for C code +err = pcnt_counter_pause(self->unit); +if (err != ESP_OK) + raise_esp_error(err); +*/ +// mp_printf(MP_PYTHON_PRINTER, MP_ERROR_TEXT("_pin_pull_type=%u "), self->useInternalWeakPullResistors); +// mp_printf(MP_PYTHON_PRINTER, "_pin_pull_type=%u \n", self->useInternalWeakPullResistors); + + +// Defining classes +//==================================================================================== +// class Edge(object): +// enumaration +typedef struct _mp_obj_Edge_t { + mp_obj_base_t base; +} mp_obj_Edge_t; + +// Edge constants +STATIC const mp_rom_map_elem_t pcnt_Edge_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_RAISE), MP_ROM_INT(RAISE) }, + { MP_ROM_QSTR(MP_QSTR_FALL), MP_ROM_INT(FALL) }, + { MP_ROM_QSTR(MP_QSTR_BOTH), MP_ROM_INT(BOTH) }, +}; +STATIC MP_DEFINE_CONST_DICT(pcnt_Edge_locals_dict, pcnt_Edge_locals_dict_table); + +STATIC const mp_obj_type_t pcnt_Edge_type = { + { &mp_type_type }, + .name = MP_QSTR_Edge, + .locals_dict = (void*)&pcnt_Edge_locals_dict, +}; + +//==================================================================================== +// class PinPull(object): +// enumaration +typedef struct _mp_obj_PinPull_t { + mp_obj_base_t base; +} mp_obj_PinPull_t; + +// PinPull constants +// PinPull stuff +STATIC const mp_rom_map_elem_t pcnt_PinPull_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_NONE), MP_ROM_INT(NONE) }, + { MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_INT(DOWN) }, + { MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_INT(UP) }, +}; +STATIC MP_DEFINE_CONST_DICT(pcnt_PinPull_locals_dict, pcnt_PinPull_locals_dict_table); + +STATIC const mp_obj_type_t pcnt_PinPull_type = { + { &mp_type_type }, + .name = MP_QSTR_PinPull, + .locals_dict = (void*)&pcnt_PinPull_locals_dict, +}; + +//==================================================================================== +// class EncoderType(object): +// enumaration +typedef struct _mp_obj_EncoderType_t { + mp_obj_base_t base; +} mp_obj_EncoderType_t; + +// EncoderType constants +// EncoderType stuff +STATIC const mp_rom_map_elem_t quad_EncoderType_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_FULL), MP_ROM_INT(FULL) }, + { MP_ROM_QSTR(MP_QSTR_HALF), MP_ROM_INT(HALF) }, + { MP_ROM_QSTR(MP_QSTR_SINGLE), MP_ROM_INT(SINGLE) }, +}; +STATIC MP_DEFINE_CONST_DICT(quad_EncoderType_locals_dict, quad_EncoderType_locals_dict_table); + +STATIC const mp_obj_type_t quad_EncoderType_type = { + { &mp_type_type }, + .name = MP_QSTR_EncoderType, + .locals_dict = (void*)&quad_EncoderType_locals_dict, +}; + +static pcnt_isr_handle_t pcnt_isr_handle = NULL; +static /*const */pcnt_PCNT_obj_t *pcnts[PCNT_UNIT_MAX] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +//*********************************** +/* Decode what PCNT's unit originated an interrupt + * and pass this information together with the event type + * the main program using a queue. + */ +static void IRAM_ATTR pcnt_intr_handler(void *arg) { + pcnt_PCNT_obj_t *self; + uint32_t intr_status = PCNT.int_st.val; + + int i; + for (i = 0; i < PCNT_UNIT_MAX; i++) { + if (intr_status & (1 << i)) { + self = pcnts[i]; + // Save the PCNT event type that caused an interrupt to pass it to the main program + + int64_t status=0; + if (PCNT.status_unit[i].h_lim_lat) { + status = self->r_enc_config.counter_h_lim; + } else if (PCNT.status_unit[i].l_lim_lat) { + status = self->r_enc_config.counter_l_lim; + } + //pcnt_counter_clear(self->unit); + PCNT.int_clr.val |= 1 << i; // clear the interrupt + self->count = status + self->count; + + break; + } + } +} + +//------------------------------------------------------------------------------------------------------------- +static void attach_pcnt(pcnt_PCNT_obj_t *self, gpio_num_t a, gpio_num_t b, enum edgeKind e) +{ + if (self->attached) { + mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Already attached, FAIL!")); + return; + } + + int index = 0; + for (; index < PCNT_UNIT_MAX; index++) { + if (pcnts[index] == NULL) { + break; + } + } + if (index == PCNT_UNIT_MAX) { + mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Too many encoders, FAIL!")); + return; + } + + // Set data now that pin attach checks are done + self->unit = (pcnt_unit_t) index; + self->aPinNumber = a; // (gpio_num_t) a; + self->bPinNumber = b; // (gpio_num_t) b; + + //Set up the IO state of hte pin + gpio_pad_select_gpio(self->aPinNumber); + gpio_pad_select_gpio(self->bPinNumber); + gpio_set_direction(self->aPinNumber, GPIO_MODE_INPUT); + gpio_set_direction(self->bPinNumber, GPIO_MODE_INPUT); + if(self->useInternalWeakPullResistors==DOWN) { + gpio_pulldown_en(self->aPinNumber); + gpio_pulldown_en(self->bPinNumber); + } else if(self->useInternalWeakPullResistors==UP) { + gpio_pullup_en(self->aPinNumber); + gpio_pullup_en(self->bPinNumber); + } + + // Prepare configuration for the PCNT unit + self->r_enc_config.pulse_gpio_num = self->aPinNumber; // Pulses + self->r_enc_config.ctrl_gpio_num = self->bPinNumber; // Direction + + self->r_enc_config.unit = self->unit; + self->r_enc_config.channel = PCNT_CHANNEL_0; + + // What to do on the positive / negative edge of pulse input? + if (e != FALL) + self->r_enc_config.pos_mode = PCNT_COUNT_INC; // Count up on the positive edge + else + self->r_enc_config.pos_mode = PCNT_COUNT_DIS; // Keep the counter value on the positive edge + if (e != RAISE) + self->r_enc_config.neg_mode = PCNT_COUNT_INC; // Count up on the negative edge + else + self->r_enc_config.neg_mode = PCNT_COUNT_DIS; // Keep the counter value on the negative edge + + // What to do when control input is low or high? + self->r_enc_config.lctrl_mode = PCNT_MODE_REVERSE, // Reverse counting direction if low + self->r_enc_config.hctrl_mode = PCNT_MODE_KEEP, // Keep the primary counter mode if high + + // Set the maximum and minimum limit values to watch + self->r_enc_config.counter_h_lim = _INT16_MAX; + self->r_enc_config.counter_l_lim = _INT16_MIN ; + + esp_err_t err; + err = pcnt_unit_config(&self->r_enc_config); + if (err != ESP_OK) + raise_esp_error(err); + + // Filter out bounces and noise + err = pcnt_set_filter_value(self->unit, 1023); // Filter Runt Pulses + if (err != ESP_OK) + raise_esp_error(err); + err = pcnt_filter_enable(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + // Enable events on maximum and minimum limit values + err = pcnt_event_enable(self->unit, PCNT_EVT_H_LIM); + if (err != ESP_OK) + raise_esp_error(err); + err = pcnt_event_enable(self->unit, PCNT_EVT_L_LIM); + if (err != ESP_OK) + raise_esp_error(err); + + err = pcnt_counter_pause(self->unit); // Initial PCNT init + if (err != ESP_OK) + raise_esp_error(err); + // Register ISR handler and enable interrupts for PCNT unit + if(pcnt_isr_handle==NULL){ + err = pcnt_isr_register(pcnt_intr_handler, (void *) NULL, (int)0, (pcnt_isr_handle_t *)&pcnt_isr_handle); + if (err != ESP_OK) + raise_esp_error(err); + if (pcnt_isr_handle==NULL) { + mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Encoder wrap interrupt failed")); + } + } + err = pcnt_intr_enable(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + err = pcnt_counter_clear(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + self->count = 0; + err = pcnt_counter_resume(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + pcnts[index] = self; + self->attached = true; +} + +// class PCNT(object): +STATIC const mp_obj_type_t pcnt_PCNT_type; + +// Defining PCNT methods +// def PCNT.__init__(aPinNumber: int, bPinNumber: int=PCNT_PIN_NOT_USED, pin_pull_type: PinPull=DOWN) +STATIC mp_obj_t pcnt_PCNT_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 4, true); + + enum edgeKind edge = mp_obj_get_int(args[0]); + gpio_num_t pin_a = machine_pin_get_gpio(args[1]); + gpio_num_t pin_b = PCNT_PIN_NOT_USED; + if (n_args + n_kw >= 3) + pin_b = machine_pin_get_gpio(args[2]); +/* + if (unit < 0 || unit > PCNT_UNIT_MAX) + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ESP PCNT bad timer number %d", unit)); +*/ + // create PCNT object for the given unit + pcnt_PCNT_obj_t *self = m_new_obj(pcnt_PCNT_obj_t); + self->base.type = &pcnt_PCNT_type; + + self->attached = false; + self->aPinNumber = PCNT_PIN_NOT_USED; + self->bPinNumber = PCNT_PIN_NOT_USED; + + self->useInternalWeakPullResistors = DOWN; + if (n_args + n_kw >= 4) + self->useInternalWeakPullResistors = mp_obj_get_int(args[3]); + self->unit = (pcnt_unit_t) -1; + + attach_pcnt(self, pin_a, pin_b, edge); + + // ??? not sure what this is for or if it's needed + //mp_map_t kw_args; + //mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t pcnt_PCNT_del(mp_obj_t self_obj) +{ + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_set_pin(self->unit, PCNT_CHANNEL_0, PCNT_PIN_NOT_USED, PCNT_PIN_NOT_USED); + if (err != ESP_OK) + raise_esp_error(err); + err = pcnt_set_pin(self->unit, PCNT_CHANNEL_1, PCNT_PIN_NOT_USED, PCNT_PIN_NOT_USED); + if (err != ESP_OK) + raise_esp_error(err); + gpio_pullup_dis(self->aPinNumber); + gpio_pullup_dis(self->bPinNumber); + gpio_pulldown_dis(self->aPinNumber); + gpio_pulldown_dis(self->bPinNumber); + + pcnts[self->unit] = NULL; + + m_del_obj(pcnt_PCNT_obj_t, self); // ??? + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_del_obj, pcnt_PCNT_del); + +STATIC void pcnt_PCNT_print(const mp_print_t *print, mp_obj_t self_obj, mp_print_kind_t kind) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + mp_printf(print, "PCNT(unit=%u, Pin(%u)", self->unit, self->aPinNumber); + if (self->bPinNumber != PCNT_PIN_NOT_USED) + mp_printf(print, ", Pin(%u)", self->bPinNumber); + mp_printf(print, ", pin_pull_type=%u)", self->useInternalWeakPullResistors); +} + +// def PCNT.counter_clear(self) +/* +Clear and reset PCNT counter value to zero + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +/* +STATIC mp_obj_t pcnt_PCNT_counter_clear(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_counter_clear(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + self->count = 0; + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_counter_clear_obj, pcnt_PCNT_counter_clear); +*/ + +// def PCNT.counter_pause(self) +/* +Pause PCNT counter of PCNT unit + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +/* +STATIC mp_obj_t pcnt_PCNT_counter_pause(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_counter_pause(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_counter_pause_obj, pcnt_PCNT_counter_pause); +*/ + +// def PCNT.counter_resume(self) +/* +Resume counting for PCNT counter + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +/* +STATIC mp_obj_t pcnt_PCNT_counter_resume(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_counter_resume(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_counter_resume_obj, pcnt_PCNT_counter_resume); +*/ + +// def PCNT.event_disable(self, evt_type: int) +/* +Disable PCNT event of PCNT unit + + @param evt_type Watch point event type. + All enabled events share the same interrupt (one interrupt per pulse counter unit). + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_event_disable(mp_obj_t self_obj, mp_obj_t evt_type_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + mp_int_t evt_type = mp_obj_get_int(evt_type_obj); + + esp_err_t err = pcnt_event_disable(self->unit, evt_type); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pcnt_PCNT_event_disable_obj, pcnt_PCNT_event_disable); + +// def PCNT.event_enable(self, evt_type: int) +/* +Enable PCNT event of PCNT unit + + @param evt_type Watch point event type. + All enabled events share the same interrupt (one interrupt per pulse counter unit). + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_event_enable(mp_obj_t self_obj, mp_obj_t evt_type_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + mp_int_t evt_type = mp_obj_get_int(evt_type_obj); + + esp_err_t err = pcnt_event_enable(self->unit, evt_type); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pcnt_PCNT_event_enable_obj, pcnt_PCNT_event_enable); + +// def PCNT.filter_disable(self) +/* +Disable PCNT input filter + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_filter_disable(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_filter_disable(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_filter_disable_obj, pcnt_PCNT_filter_disable); + +// def PCNT.filter_enable(self) +/* +Enable PCNT input filter + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_filter_enable(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_filter_enable(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_filter_enable_obj, pcnt_PCNT_filter_enable); + +// def PCNT.get_counter_value(self) -> int +/* +Get pulse counter value + + @return Counter value + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_get_counter_value(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + int16_t count; + pcnt_get_counter_value(self->unit, &count); // without error test + + return MP_OBJ_NEW_SMALL_INT(count); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_get_counter_value_obj, pcnt_PCNT_get_counter_value); + +// def PCNT.get_event_value(self, evt_type: int) -> int +/* +Get PCNT event value of PCNT unit + + @param evt_type Watch point event type. + All enabled events share the same interrupt (one interrupt per pulse counter unit). + + @return Value for PCNT event + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_get_event_value(mp_obj_t self_obj, mp_obj_t evt_type_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + mp_int_t evt_type = mp_obj_get_int(evt_type_obj); + + int16_t count; + esp_err_t err = pcnt_get_event_value(self->unit, evt_type, &count); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_OBJ_NEW_SMALL_INT(count); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pcnt_PCNT_get_event_value_obj, pcnt_PCNT_get_event_value); + +// def PCNT.get_filter_value(self) -> int +/* +Get PCNT filter value + + @return Filter value. + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_get_filter_value(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + uint16_t count; + esp_err_t err = pcnt_get_filter_value(self->unit, &count); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_OBJ_NEW_SMALL_INT(count); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_get_filter_value_obj, pcnt_PCNT_get_filter_value); + +// def PCNT.intr_disable(self) +/* +Disable PCNT interrupt for PCNT unit + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_intr_disable(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_intr_disable(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_intr_disable_obj, pcnt_PCNT_intr_disable); + +// def PCNT.intr_enable(self) +/* +Enable PCNT interrupt for PCNT unit + @note + Each Pulse counter unit has five watch point events that share the same interrupt. + Configure events with pcnt_event_enable() and pcnt_event_disable() + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_intr_enable(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_intr_enable(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_intr_enable_obj, pcnt_PCNT_intr_enable); + +// def PCNT.isr_handler_add(self, isr_handler: int, _args: int) +/* +Add ISR handler for specified unit. + + Call this function after using pcnt_isr_service_install() to + install the PCNT driver's ISR handler service. + + The ISR handlers do not need to be declared with IRAM_ATTR, + unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the + ISR in pcnt_isr_service_install(). + + This ISR handler will be called from an ISR. So there is a stack + size limit (configurable as "ISR stack size" in menuconfig). This + limit is smaller compared to a global PCNT interrupt handler due + to the additional level of indirection. + + @param isr_handler Interrupt handler function. + @param args Parameter for handler function + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_isr_handler_add(mp_obj_t self_obj, mp_obj_t isr_handler_obj, mp_obj_t _args_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + void *isr_handler = MP_OBJ_TO_PTR(isr_handler_obj); + void *_args = MP_OBJ_TO_PTR(_args_obj); + + esp_err_t err = pcnt_isr_handler_add(self->unit, isr_handler, _args); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pcnt_PCNT_isr_handler_add_obj, pcnt_PCNT_isr_handler_add); + +// def PCNT.isr_handler_remove(self) +/* +Delete ISR handler for specified unit. + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_isr_handler_remove(mp_obj_t self_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_isr_handler_remove(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_isr_handler_remove_obj, pcnt_PCNT_isr_handler_remove); + +// def PCNT.isr_register(self, fn: int, arg: int, intr_alloc_flags: int, handle: int) +/* +Register PCNT interrupt handler, the handler is an ISR. + The handler will be attached to the same CPU core that this function is running on. + Please do not use pcnt_isr_service_install if this function was called. + + @param fn Interrupt handler function. + @param arg Parameter for handler function + @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) + ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will + be returned here. Calling pcnt_isr_unregister to unregister this ISR service if needed, + but only if the handle is not NULL. + + @note + Can raise EspException: + - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags. + - ESP_ERR_INVALID_ARG Function pointer error. +*/ +STATIC mp_obj_t pcnt_PCNT_isr_register(size_t n_args, const mp_obj_t *args) { + //pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(args[0]); + void *fn = MP_OBJ_TO_PTR(args[1]); + void *arg = MP_OBJ_TO_PTR(args[2]); + mp_int_t intr_alloc_flags = mp_obj_get_int(args[3]); + pcnt_isr_handle_t *handle = MP_OBJ_TO_PTR(args[4]); + + esp_err_t err = pcnt_isr_register(fn, arg, intr_alloc_flags, handle); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pcnt_PCNT_isr_register_obj, 5, 5, pcnt_PCNT_isr_register); + +// def PCNT.isr_service_install(self, intr_alloc_flags: int) +/* +Install PCNT ISR service. + @note + We can manage different interrupt service for each unit. + This function will use the default ISR handle service, Calling pcnt_isr_service_uninstall to + uninstall the default service if needed. Please do not use pcnt_isr_register if this function was called. + + @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) + ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_NO_MEM No memory to install this service + - ESP_ERR_INVALID_STATE ISR service already installed +*/ +STATIC mp_obj_t pcnt_PCNT_isr_service_install(mp_obj_t self_obj, mp_obj_t intr_alloc_flags_obj) { + //pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + mp_int_t intr_alloc_flags = mp_obj_get_int(intr_alloc_flags_obj); + + esp_err_t err = pcnt_isr_service_install(intr_alloc_flags); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pcnt_PCNT_isr_service_install_obj, pcnt_PCNT_isr_service_install); + +// def PCNT.isr_unregister(self, handle: int) +/* +Unregister PCNT interrupt handler (registered by pcnt_isr_register), the handler is an ISR. +The handler will be attached to the same CPU core that this function is running on. +If the interrupt service is registered by pcnt_isr_service_install, please call pcnt_isr_service_uninstall instead + + @param handle handle to unregister the ISR service. + + @note + Can raise EspException: + - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags. + - ESP_ERR_INVALID_ARG Function pointer error. +*/ +/* +// It does not present in pcnt.h !!! +STATIC mp_obj_t pcnt_PCNT_isr_unregister(mp_obj_t self_obj, mp_obj_t handle_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + mp_int_t handle = mp_obj_get_int(handle_obj); + + esp_err_t err = pcnt_isr_unregister(handle); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pcnt_PCNT_isr_unregister_obj, pcnt_PCNT_isr_unregister); +*/ + +// def PCNT.pcnt_isr_service_uninstall(self) +/* +Uninstall PCNT ISR service, freeing related resources. +*/ +STATIC mp_obj_t pcnt_PCNT_pcnt_isr_service_uninstall(mp_obj_t self_obj) { + //pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + pcnt_isr_service_uninstall(); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_pcnt_isr_service_uninstall_obj, pcnt_PCNT_pcnt_isr_service_uninstall); + +// def PCNT.set_event_value(self, evt_type: int, value: int) +/* +Set PCNT event value of PCNT unit + + @param evt_type Watch point event type. + All enabled events share the same interrupt (one interrupt per pulse counter unit). + + @param value Counter value for PCNT event + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_set_event_value(mp_obj_t self_obj, mp_obj_t evt_type_obj, mp_obj_t value_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + mp_int_t evt_type = mp_obj_get_int(evt_type_obj); + mp_int_t value = mp_obj_get_int(value_obj); + + esp_err_t err = pcnt_set_event_value(self->unit, evt_type, value); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pcnt_PCNT_set_event_value_obj, pcnt_PCNT_set_event_value); + +// def PCNT.set_filter_value(self, filter_val: int) +/* +Set PCNT filter value + + @param filter_val PCNT signal filter value, counter in APB_CLK cycles. + Any pulses lasting shorter than this will be ignored when the filter is enabled. + @note + filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023. + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_set_filter_value(mp_obj_t self_obj, mp_obj_t filter_val_obj) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + mp_int_t value = mp_obj_get_int(filter_val_obj); + + if ((value < 0) || (value > 1023)) + //mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Correct 10-bits filter value is [0..1023]")); + mp_raise_msg(&esp_err_EspError_type, MP_ERROR_TEXT("Correct 10-bits filter value is [0..1023]")); + + esp_err_t err = pcnt_set_filter_value(self->unit, value); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pcnt_PCNT_set_filter_value_obj, pcnt_PCNT_set_filter_value); + +// def PCNT.set_mode(self, channel: int, pos_mode: int, neg_mode: int, hctrl_mode: int, lctrl_mode: int) +/* +Set PCNT counter mode + + @param channel PCNT channel number + @param pos_mode Counter mode when detecting positive edge + @param neg_mode Counter mode when detecting negative edge + @param hctrl_mode Counter mode when control signal is high level + @param lctrl_mode Counter mode when control signal is low level + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_set_mode(size_t n_args, const mp_obj_t *args) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t channel = mp_obj_get_int(args[1]); + mp_int_t pos_mode = mp_obj_get_int(args[2]); + mp_int_t neg_mode = mp_obj_get_int(args[3]); + mp_int_t hctrl_mode = mp_obj_get_int(args[4]); + mp_int_t lctrl_mode = mp_obj_get_int(args[5]); + + esp_err_t err = pcnt_set_mode(self->unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pcnt_PCNT_set_mode_obj, 6, 6, pcnt_PCNT_set_mode); + +// def PCNT.set_pin(self, channel: int, pulse_io: int, ctrl_io: int) +/* +Configure PCNT pulse signal input pin and control input pin + + @param channel PCNT channel number + @param pulse_io Pulse signal input GPIO + @param ctrl_io Control signal input GPIO + +Set the signal input to PCNT_PIN_NOT_USED if unused. + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver has not been initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_set_pin(size_t n_args, const mp_obj_t *args) { + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t channel = mp_obj_get_int(args[1]); + mp_int_t pulse_io = mp_obj_get_int(args[2]); + mp_int_t ctrl_io = mp_obj_get_int(args[3]); + + esp_err_t err = pcnt_set_pin(self->unit, channel, pulse_io, ctrl_io); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pcnt_PCNT_set_pin_obj, 4, 4, pcnt_PCNT_set_pin); + +// def PCNT.unit_config(self, pcnt_config: int) +/* +Configure Pulse Counter unit + @note + This function will disable three events: PCNT_EVT_L_LIM, PCNT_EVT_H_LIM, PCNT_EVT_ZERO. + + @param pcnt_config Pointer of Pulse Counter unit configure parameter + + @note + Can raise EspException: + - ESP_ERR_INVALID_STATE pcnt driver already initialized + - ESP_ERR_INVALID_ARG Parameter error +*/ +STATIC mp_obj_t pcnt_PCNT_unit_config(mp_obj_t self_obj, mp_obj_t pcnt_config_obj) { + //pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + pcnt_config_t *pcnt_config = MP_OBJ_TO_PTR(pcnt_config_obj); + + esp_err_t err = pcnt_unit_config(pcnt_config); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pcnt_PCNT_unit_config_obj, pcnt_PCNT_unit_config); + +//==================================================================================== +STATIC mp_obj_t pcnt_PCNT_set_count(mp_obj_t self_obj, mp_obj_t value_obj) +{ + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + int64_t value = mp_obj_get_int(value_obj); + + int16_t count; + esp_err_t err = pcnt_get_counter_value(self->unit, &count); + if (err != ESP_OK) + raise_esp_error(err); + self->count = value - count; + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pcnt_PCNT_set_count_obj, pcnt_PCNT_set_count); + +//----------------------------------------------------------------- +STATIC mp_obj_t pcnt_PCNT_count(mp_obj_t self_obj) +{ + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + int16_t count; + pcnt_get_counter_value(self->unit, &count); // without error test + + return mp_obj_new_int_from_ll(self->count + count); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_count_obj, pcnt_PCNT_count); + +//----------------------------------------------------------------- +STATIC mp_obj_t pcnt_PCNT_count_and_clear(mp_obj_t self_obj) +{ + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + int16_t count; + esp_err_t err; + err = pcnt_get_counter_value(self->unit, &count); + if (err != ESP_OK) + raise_esp_error(err); + err = pcnt_counter_clear(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + int64_t _count = self->count + count; + self->count = 0; + return mp_obj_new_int_from_ll(_count); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_count_and_clear_obj, pcnt_PCNT_count_and_clear); + +//----------------------------------------------------------------- +STATIC mp_obj_t pcnt_PCNT_clear(mp_obj_t self_obj) +{ + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_counter_clear(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + self->count = 0; + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_clear_obj, pcnt_PCNT_clear); + +//----------------------------------------------------------------- +STATIC mp_obj_t pcnt_PCNT_pause(mp_obj_t self_obj) +{ + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_counter_pause(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_pause_obj, pcnt_PCNT_pause); + +//----------------------------------------------------------------- +STATIC mp_obj_t pcnt_PCNT_resume(mp_obj_t self_obj) +{ + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + esp_err_t err = pcnt_counter_resume(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pcnt_PCNT_resume_obj, pcnt_PCNT_resume); + +//==================================================================================== +// PCNT stuff +// Register class methods +STATIC const mp_rom_map_elem_t pcnt_PCNT_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_unit_config), MP_ROM_PTR(&pcnt_PCNT_unit_config_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&pcnt_PCNT_del_obj) }, + + { MP_ROM_QSTR(MP_QSTR_intr_disable), MP_ROM_PTR(&pcnt_PCNT_intr_disable_obj) }, + { MP_ROM_QSTR(MP_QSTR_intr_enable), MP_ROM_PTR(&pcnt_PCNT_intr_enable_obj) }, + { MP_ROM_QSTR(MP_QSTR_isr_handler_add), MP_ROM_PTR(&pcnt_PCNT_isr_handler_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_isr_handler_remove), MP_ROM_PTR(&pcnt_PCNT_isr_handler_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_isr_register), MP_ROM_PTR(&pcnt_PCNT_isr_register_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_isr_unregister), MP_ROM_PTR(&pcnt_PCNT_isr_unregister_obj) }, + { MP_ROM_QSTR(MP_QSTR_isr_service_install), MP_ROM_PTR(&pcnt_PCNT_isr_service_install_obj) }, + { MP_ROM_QSTR(MP_QSTR_pcnt_isr_service_uninstall), MP_ROM_PTR(&pcnt_PCNT_pcnt_isr_service_uninstall_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_mode), MP_ROM_PTR(&pcnt_PCNT_set_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_pin), MP_ROM_PTR(&pcnt_PCNT_set_pin_obj) }, + + { MP_ROM_QSTR(MP_QSTR_event_disable), MP_ROM_PTR(&pcnt_PCNT_event_disable_obj) }, + { MP_ROM_QSTR(MP_QSTR_event_enable), MP_ROM_PTR(&pcnt_PCNT_event_enable_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_event_value), MP_ROM_PTR(&pcnt_PCNT_get_event_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_event_value), MP_ROM_PTR(&pcnt_PCNT_set_event_value_obj) }, + + { MP_ROM_QSTR(MP_QSTR_filter_disable), MP_ROM_PTR(&pcnt_PCNT_filter_disable_obj) }, + { MP_ROM_QSTR(MP_QSTR_filter_enable), MP_ROM_PTR(&pcnt_PCNT_filter_enable_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_filter_value), MP_ROM_PTR(&pcnt_PCNT_get_filter_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_filter_value), MP_ROM_PTR(&pcnt_PCNT_set_filter_value_obj) }, + + { MP_ROM_QSTR(MP_QSTR_get_counter_value), MP_ROM_PTR(&pcnt_PCNT_get_counter_value_obj) }, + /* + { MP_ROM_QSTR(MP_QSTR_counter_clear), MP_ROM_PTR(&pcnt_PCNT_counter_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_counter_pause), MP_ROM_PTR(&pcnt_PCNT_counter_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_counter_resume), MP_ROM_PTR(&pcnt_PCNT_counter_resume_obj) }, + */ + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&pcnt_PCNT_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_count_and_clear), MP_ROM_PTR(&pcnt_PCNT_count_and_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&pcnt_PCNT_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&pcnt_PCNT_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&pcnt_PCNT_resume_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_count), MP_ROM_PTR(&pcnt_PCNT_set_count_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(pcnt_PCNT_locals_dict, pcnt_PCNT_locals_dict_table); + +// Create the class-object itself +STATIC const mp_obj_type_t pcnt_PCNT_type = { + { &mp_type_type }, + .name = MP_QSTR_PCNT, + .make_new = pcnt_PCNT_make_new, + .print = pcnt_PCNT_print, + .locals_dict = (mp_obj_dict_t*)&pcnt_PCNT_locals_dict, +}; + +//==================================================================================== +// Defining classes +// class QUAD(object): +STATIC const mp_obj_type_t quad_QUAD_type; + +//------------------------------------------------------------------------------------------------------------- +static void attach_quad(pcnt_PCNT_obj_t *self, gpio_num_t a, gpio_num_t b, enum encType et) +{ + if (self->attached) { + mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Already attached, FAIL!")); + return; + } + + int index = 0; + for (; index < PCNT_UNIT_MAX; index++) { + if (pcnts[index] == NULL) { + break; + } + } + if (index == PCNT_UNIT_MAX) { + mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Too many encoders, FAIL!")); + return; + } + + // Set data now that pin attach checks are done + self->unit = (pcnt_unit_t) index; + self->aPinNumber = a; // (gpio_num_t) a; + self->bPinNumber = b; // (gpio_num_t) b; + + //Set up the IO state of hte pin + gpio_pad_select_gpio(self->aPinNumber); + gpio_pad_select_gpio(self->bPinNumber); + gpio_set_direction(self->aPinNumber, GPIO_MODE_INPUT); + gpio_set_direction(self->bPinNumber, GPIO_MODE_INPUT); + if(self->useInternalWeakPullResistors==DOWN) { + gpio_pulldown_en(self->aPinNumber); + gpio_pulldown_en(self->bPinNumber); + } else if(self->useInternalWeakPullResistors==UP) { + gpio_pullup_en(self->aPinNumber); + gpio_pullup_en(self->bPinNumber); + } + // Set up encoder PCNT configuration + self->r_enc_config.pulse_gpio_num = self->aPinNumber; //Rotary Encoder Chan A + self->r_enc_config.ctrl_gpio_num = self->bPinNumber; //Rotary Encoder Chan B + + self->r_enc_config.unit = self->unit; + self->r_enc_config.channel = PCNT_CHANNEL_0; + + self->r_enc_config.pos_mode = (et != SINGLE) ? PCNT_COUNT_DEC : PCNT_COUNT_DIS; //Count Only On Rising-Edges + self->r_enc_config.neg_mode = PCNT_COUNT_INC; // Discard Falling-Edge + + self->r_enc_config.lctrl_mode = PCNT_MODE_KEEP; // Rising A on HIGH B = CW Step + self->r_enc_config.hctrl_mode = PCNT_MODE_REVERSE; // Rising A on LOW B = CCW Step + + // Set the maximum and minimum limit values to watch + self->r_enc_config.counter_h_lim = _INT16_MAX; + self->r_enc_config.counter_l_lim = _INT16_MIN ; + + esp_err_t err; + err = pcnt_unit_config(&self->r_enc_config); + if (err != ESP_OK) + raise_esp_error(err); + + self->r_enc_config.channel = PCNT_CHANNEL_1; // channel 1 + self->r_enc_config.pulse_gpio_num = self->bPinNumber; //make prior control into signal + self->r_enc_config.ctrl_gpio_num = self->aPinNumber; //and prior signal into control + if (et == FULL) { // set up second channel for full quad + //self->r_enc_config.pulse_gpio_num = self->bPinNumber; //make prior control into signal + //self->r_enc_config.ctrl_gpio_num = self->aPinNumber; //and prior signal into control + + //self->r_enc_config.unit = self->unit; + //self->r_enc_config.channel = PCNT_CHANNEL_1; // channel 1 + + self->r_enc_config.pos_mode = PCNT_COUNT_DEC; //Count Only On Rising-Edges + self->r_enc_config.neg_mode = PCNT_COUNT_INC; // Discard Falling-Edge + + self->r_enc_config.lctrl_mode = PCNT_MODE_REVERSE; // prior high mode is now low + self->r_enc_config.hctrl_mode = PCNT_MODE_KEEP; // prior low mode is now high + + //self->r_enc_config.counter_h_lim = _INT16_MAX; + //self->r_enc_config.counter_l_lim = _INT16_MIN ; + } else { // make sure channel 1 is not set when not full quad + //self->r_enc_config.pulse_gpio_num = self->bPinNumber; //make prior control into signal + //self->r_enc_config.ctrl_gpio_num = self->aPinNumber; //and prior signal into control + + //self->r_enc_config.unit = self->unit; + //self->r_enc_config.channel = PCNT_CHANNEL_1; // channel 1 + + self->r_enc_config.pos_mode = PCNT_COUNT_DIS; //disabling channel 1 + self->r_enc_config.neg_mode = PCNT_COUNT_DIS; // disabling channel 1 + + self->r_enc_config.lctrl_mode = PCNT_MODE_DISABLE; // disabling channel 1 + self->r_enc_config.hctrl_mode = PCNT_MODE_DISABLE; // disabling channel 1 + + //self->r_enc_config.counter_h_lim = _INT16_MAX; + //self->r_enc_config.counter_l_lim = _INT16_MIN ; + } + err = pcnt_unit_config(&self->r_enc_config); + if (err != ESP_OK) + raise_esp_error(err); +/* + if (et == FULL) { + // set up second channel for full quad + self->r_enc_config.pulse_gpio_num = self->bPinNumber; //make prior control into signal + self->r_enc_config.ctrl_gpio_num = self->aPinNumber; //and prior signal into control + + self->r_enc_config.unit = self->unit; + self->r_enc_config.channel = PCNT_CHANNEL_1; // channel 1 + + self->r_enc_config.pos_mode = PCNT_COUNT_DEC; //Count Only On Rising-Edges + self->r_enc_config.neg_mode = PCNT_COUNT_INC; // Discard Falling-Edge + + self->r_enc_config.lctrl_mode = PCNT_MODE_REVERSE; // prior high mode is now low + self->r_enc_config.hctrl_mode = PCNT_MODE_KEEP; // prior low mode is now high + + self->r_enc_config.counter_h_lim = _INT16_MAX; + self->r_enc_config.counter_l_lim = _INT16_MIN ; + + err = pcnt_unit_config(&self->r_enc_config); + if (err != ESP_OK) + raise_esp_error(err); + } else { // make sure channel 1 is not set when not full quad + self->r_enc_config.pulse_gpio_num = self->bPinNumber; //make prior control into signal + self->r_enc_config.ctrl_gpio_num = self->aPinNumber; //and prior signal into control + + self->r_enc_config.unit = self->unit; + self->r_enc_config.channel = PCNT_CHANNEL_1; // channel 1 + + self->r_enc_config.pos_mode = PCNT_COUNT_DIS; //disabling channel 1 + self->r_enc_config.neg_mode = PCNT_COUNT_DIS; // disabling channel 1 + + self->r_enc_config.lctrl_mode = PCNT_MODE_DISABLE; // disabling channel 1 + self->r_enc_config.hctrl_mode = PCNT_MODE_DISABLE; // disabling channel 1 + + self->r_enc_config.counter_h_lim = _INT16_MAX; + self->r_enc_config.counter_l_lim = _INT16_MIN ; + + err = pcnt_unit_config(&self->r_enc_config); + if (err != ESP_OK) + raise_esp_error(err); + } +*/ + // Filter out bounces and noise + err = pcnt_set_filter_value(self->unit, 1023); // Filter Runt Pulses + if (err != ESP_OK) + raise_esp_error(err); + err = pcnt_filter_enable(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + /* Enable events on maximum and minimum limit values */ + err = pcnt_event_enable(self->unit, PCNT_EVT_H_LIM); + if (err != ESP_OK) + raise_esp_error(err); + err = pcnt_event_enable(self->unit, PCNT_EVT_L_LIM); + if (err != ESP_OK) + raise_esp_error(err); + + err = pcnt_counter_pause(self->unit); // Initial PCNT init + if (err != ESP_OK) + raise_esp_error(err); + /* Register ISR handler and enable interrupts for PCNT unit */ + if(pcnt_isr_handle==NULL){ + err = pcnt_isr_register(pcnt_intr_handler, (void *) NULL, (int)0, (pcnt_isr_handle_t *)&pcnt_isr_handle); + if ((err != ESP_OK) || (pcnt_isr_handle==NULL)) { + mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Encoder wrap interrupt failed")); + } + } + err = pcnt_intr_enable(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + err = pcnt_counter_clear(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + self->count = 0; + err = pcnt_counter_resume(self->unit); + if (err != ESP_OK) + raise_esp_error(err); + + pcnts[index] = self; + self->attached = true; +} + +//------------------------------------------------------------------------------------------------------------- +// Defining QUAD methods +// def QUAD.__init__(encoder_type: EncoderType, aPinNumber: int, bPinNumber: int=PCNT_PIN_NOT_USED, pin_pull_type: PinPull=DOWN) +STATIC mp_obj_t quad_QUAD_make_new(const mp_obj_type_t *t_ype, size_t n_args, size_t n_kw, const mp_obj_t *args) +{ + mp_arg_check_num(n_args, n_kw, 2, 4, true); + + int encoder_type = mp_obj_get_int(args[0]); + gpio_num_t pin_a = machine_pin_get_gpio(args[1]); + gpio_num_t pin_b = PCNT_PIN_NOT_USED; + if (n_args + n_kw >= 3) + pin_b = machine_pin_get_gpio(args[2]); +/* + if (unit < 0 || unit > PCNT_UNIT_MAX) + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ESP PCNT bad timer number %d", unit)); +*/ + // create QUAD object for the given unit + pcnt_PCNT_obj_t *self = m_new_obj(pcnt_PCNT_obj_t); + self->base.type = &quad_QUAD_type; + + self->attached = false; + self->aPinNumber = PCNT_PIN_NOT_USED; + self->bPinNumber = PCNT_PIN_NOT_USED; + + self->useInternalWeakPullResistors = DOWN; + if (n_args + n_kw >= 4) + self->useInternalWeakPullResistors = mp_obj_get_int(args[3]); + self->unit = (pcnt_unit_t) -1; + + attach_quad(self, pin_a, pin_b, encoder_type); + + // not sure what this is for or if it's needed + //mp_map_t kw_args; + //mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + + return MP_OBJ_FROM_PTR(self); +} + +//------------------------------------------------------------------------------------------ +STATIC void quad_QUAD_print(const mp_print_t *print, mp_obj_t self_obj, mp_print_kind_t kind) +{ + pcnt_PCNT_obj_t *self = MP_OBJ_TO_PTR(self_obj); + + mp_printf(print, "QUAD(unit=%u, Pin(%u)", self->unit, self->aPinNumber); + if (self->bPinNumber != PCNT_PIN_NOT_USED) + mp_printf(print, ", Pin(%u)", self->bPinNumber); + mp_printf(print, ", pin_pull_type=%u)", self->useInternalWeakPullResistors); +} + +// Create the class-object itself +STATIC const mp_obj_type_t quad_QUAD_type = { + { &mp_type_type }, + .name = MP_QSTR_QUAD, + .print = quad_QUAD_print, + //.print = pcnt_PCNT_print, + .make_new = quad_QUAD_make_new, + //.locals_dict = (mp_obj_dict_t*)&quad_QUAD_locals_dict, + .locals_dict = (mp_obj_dict_t*)&pcnt_PCNT_locals_dict, + //.parent = &pcnt_PCNT_type, +}; + +//==================================================================================== +// module stuff +// Set up the module properties +STATIC const mp_rom_map_elem_t pcnt_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pcnt) }, + { MP_ROM_QSTR(MP_QSTR_PCNT), MP_ROM_PTR(&pcnt_PCNT_type) }, + { MP_ROM_QSTR(MP_QSTR_QUAD), MP_ROM_PTR(&quad_QUAD_type) }, + /* + { MP_ROM_QSTR(MP_QSTR_PCNT_CHANNEL_0), MP_ROM_INT(PCNT_CHANNEL_0) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_CHANNEL_1), MP_ROM_INT(PCNT_CHANNEL_1) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_CHANNEL_MAX), MP_ROM_INT(PCNT_CHANNEL_MAX) }, + */ + { MP_ROM_QSTR(MP_QSTR_PCNT_COUNT_DEC), MP_ROM_INT(PCNT_COUNT_DEC) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_COUNT_DIS), MP_ROM_INT(PCNT_COUNT_DIS) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_COUNT_INC), MP_ROM_INT(PCNT_COUNT_INC) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_COUNT_MAX), MP_ROM_INT(PCNT_COUNT_MAX) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_EVT_H_LIM), MP_ROM_INT(PCNT_EVT_H_LIM) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_EVT_L_LIM), MP_ROM_INT(PCNT_EVT_L_LIM) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_EVT_THRES_0), MP_ROM_INT(PCNT_EVT_THRES_0) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_PCNT_EVT_THRES_1), MP_ROM_INT(PCNT_EVT_THRES_1) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_EVT_ZERO), MP_ROM_INT(PCNT_EVT_ZERO) }, + + { MP_ROM_QSTR(MP_QSTR_PCNT_MODE_DISABLE), MP_ROM_INT(PCNT_MODE_DISABLE) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_MODE_KEEP), MP_ROM_INT(PCNT_MODE_KEEP) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_MODE_MAX), MP_ROM_INT(PCNT_MODE_MAX) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_MODE_REVERSE), MP_ROM_INT(PCNT_MODE_REVERSE) }, + + { MP_ROM_QSTR(MP_QSTR_PCNT_PIN_NOT_USED), MP_ROM_INT(PCNT_PIN_NOT_USED) }, + /* + { MP_ROM_QSTR(MP_QSTR_PCNT_PORT_0), MP_ROM_INT(PCNT_PORT_0) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_PORT_MAX), MP_ROM_INT(PCNT_PORT_MAX) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_0), MP_ROM_INT(PCNT_UNIT_0) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_1), MP_ROM_INT(PCNT_UNIT_1) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_2), MP_ROM_INT(PCNT_UNIT_2) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_3), MP_ROM_INT(PCNT_UNIT_3) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_4), MP_ROM_INT(PCNT_UNIT_4) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_5), MP_ROM_INT(PCNT_UNIT_5) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_6), MP_ROM_INT(PCNT_UNIT_6) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_7), MP_ROM_INT(PCNT_UNIT_7) }, + { MP_ROM_QSTR(MP_QSTR_PCNT_UNIT_MAX), MP_ROM_INT(PCNT_UNIT_MAX) }, + */ + { MP_ROM_QSTR(MP_QSTR_PinPull), MP_ROM_PTR(&pcnt_PinPull_type) }, + { MP_ROM_QSTR(MP_QSTR_Edge), MP_ROM_PTR(&pcnt_Edge_type) }, + { MP_ROM_QSTR(MP_QSTR_EncoderType), MP_ROM_PTR(&quad_EncoderType_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(pcnt_globals, pcnt_globals_table); + +// Define the module object +const mp_obj_module_t pcnt_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&pcnt_globals, +}; +// Register the module +MP_REGISTER_MODULE(MP_QSTR_pcnt, pcnt_cmodule, MODULE_PCNT_ENABLED); + +#endif // MODULE_PCNT_ENABLED diff --git a/ports/esp32/cmodules/pcnt/pcnt_.h b/ports/esp32/cmodules/pcnt/pcnt_.h new file mode 100644 index 0000000000000..e3a73eb71588c --- /dev/null +++ b/ports/esp32/cmodules/pcnt/pcnt_.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include "driver/pcnt.h" + +#define _INT16_MAX (32766) +#define _INT16_MIN (-32766) + +enum puType { + NONE, + DOWN, + UP +}; + +enum edgeKind { + RAISE, + FALL, + BOTH +}; + +enum encType { + SINGLE, + HALF, + FULL +}; + +typedef struct _pcnt_PCNT_obj_t { + mp_obj_base_t base; + gpio_num_t aPinNumber; + gpio_num_t bPinNumber; + enum puType useInternalWeakPullResistors; + + pcnt_config_t r_enc_config; + bool attached; + pcnt_unit_t unit; + volatile int64_t count; + + //bool fullQuad; // for QUAD() only +} pcnt_PCNT_obj_t; + +extern int machine_pin_get_id(mp_obj_t pin_in); + +#pragma once From e82d438822e01a12007e25d3155408677cc3d7e6 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Mon, 16 Nov 2020 07:17:07 -0800 Subject: [PATCH 3/8] Tested ESP-WROOM-32 --- ports/esp32/cmodules/pcnt/pcnt.c | 6 +++--- ports/esp32/mpconfigport.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ports/esp32/cmodules/pcnt/pcnt.c b/ports/esp32/cmodules/pcnt/pcnt.c index 65dacc1b817c4..31603773a2bf2 100644 --- a/ports/esp32/cmodules/pcnt/pcnt.c +++ b/ports/esp32/cmodules/pcnt/pcnt.c @@ -1123,7 +1123,7 @@ static void attach_quad(pcnt_PCNT_obj_t *self, gpio_num_t a, gpio_num_t b, enum err = pcnt_unit_config(&self->r_enc_config); if (err != ESP_OK) raise_esp_error(err); - +/* self->r_enc_config.channel = PCNT_CHANNEL_1; // channel 1 self->r_enc_config.pulse_gpio_num = self->bPinNumber; //make prior control into signal self->r_enc_config.ctrl_gpio_num = self->aPinNumber; //and prior signal into control @@ -1161,7 +1161,7 @@ static void attach_quad(pcnt_PCNT_obj_t *self, gpio_num_t a, gpio_num_t b, enum err = pcnt_unit_config(&self->r_enc_config); if (err != ESP_OK) raise_esp_error(err); -/* +*/ if (et == FULL) { // set up second channel for full quad self->r_enc_config.pulse_gpio_num = self->bPinNumber; //make prior control into signal @@ -1202,7 +1202,7 @@ static void attach_quad(pcnt_PCNT_obj_t *self, gpio_num_t a, gpio_num_t b, enum if (err != ESP_OK) raise_esp_error(err); } -*/ + // Filter out bounces and noise err = pcnt_set_filter_value(self->unit, 1023); // Filter Runt Pulses if (err != ESP_OK) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index f170d70708b79..c6c7bd052aa0f 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -282,3 +282,6 @@ typedef long mp_off_t; #ifndef MICROPY_HW_ENABLE_MDNS_RESPONDER #define MICROPY_HW_ENABLE_MDNS_RESPONDER (1) #endif + +#define MODULE_ESP_ERR_ENABLED (1) +#define MODULE_PCNT_ENABLED (1) From 3f6ce4d905a45ac042d09bd6a4b41da22900b3b1 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Mon, 16 Nov 2020 09:19:23 -0800 Subject: [PATCH 4/8] Fix esp_err type --- ports/esp32/cmodules/esp_err/esp_err.c | 2 +- ports/esp32/cmodules/esp_err/esp_error.h | 5 ++--- ports/esp32/cmodules/pcnt/pcnt.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ports/esp32/cmodules/esp_err/esp_err.c b/ports/esp32/cmodules/esp_err/esp_err.c index 67f627b569365..cab6b29305053 100644 --- a/ports/esp32/cmodules/esp_err/esp_err.c +++ b/ports/esp32/cmodules/esp_err/esp_err.c @@ -57,7 +57,7 @@ typedef struct _mp_obj_esp_err_EspError_t { mp_obj_base_t base; } mp_obj_esp_err_EspError_t; -/*STATIC */const mp_obj_type_t mp_type_EspError; +const mp_obj_type_t mp_type_EspError; /* // Defining EspError methods // def EspError.__init__(self, error_code: int=0, error_msg: str='') diff --git a/ports/esp32/cmodules/esp_err/esp_error.h b/ports/esp32/cmodules/esp_err/esp_error.h index d4d99c66a2c4c..153e283d1168c 100644 --- a/ports/esp32/cmodules/esp_err/esp_error.h +++ b/ports/esp32/cmodules/esp_err/esp_error.h @@ -1,4 +1,3 @@ -const mp_obj_type_t esp_err_EspError_type; +const mp_obj_type_t mp_type_EspError; -#define raise_esp_error(err) mp_raise_msg_varg(&esp_err_EspError_type, MP_ERROR_TEXT("%d(0x%X) - "#err), err, err); - \ No newline at end of file +#define raise_esp_error(err) mp_raise_msg_varg(&mp_type_EspError, MP_ERROR_TEXT("%d(0x%X)"), err, err); diff --git a/ports/esp32/cmodules/pcnt/pcnt.c b/ports/esp32/cmodules/pcnt/pcnt.c index 31603773a2bf2..469aaf56a10b5 100644 --- a/ports/esp32/cmodules/pcnt/pcnt.c +++ b/ports/esp32/cmodules/pcnt/pcnt.c @@ -336,7 +336,7 @@ STATIC mp_obj_t pcnt_PCNT_del(mp_obj_t self_obj) pcnts[self->unit] = NULL; - m_del_obj(pcnt_PCNT_obj_t, self); // ??? + ////m_del_obj(pcnt_PCNT_obj_t, self); // ??? return MP_ROM_NONE; } @@ -826,7 +826,7 @@ STATIC mp_obj_t pcnt_PCNT_set_filter_value(mp_obj_t self_obj, mp_obj_t filter_va if ((value < 0) || (value > 1023)) //mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Correct 10-bits filter value is [0..1023]")); - mp_raise_msg(&esp_err_EspError_type, MP_ERROR_TEXT("Correct 10-bits filter value is [0..1023]")); + mp_raise_msg(&mp_type_EspError, MP_ERROR_TEXT("Correct 10-bits filter value is [0..1023]")); esp_err_t err = pcnt_set_filter_value(self->unit, value); if (err != ESP_OK) From 3444fef7544fdd85d7daa5f327c4a12ad072ff6c Mon Sep 17 00:00:00 2001 From: IhorNehrutsa <70886343+IhorNehrutsa@users.noreply.github.com> Date: Mon, 16 Nov 2020 19:34:03 +0200 Subject: [PATCH 5/8] Create README.md --- ports/esp32/cmodules/esp_err/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 ports/esp32/cmodules/esp_err/README.md diff --git a/ports/esp32/cmodules/esp_err/README.md b/ports/esp32/cmodules/esp_err/README.md new file mode 100644 index 0000000000000..47c94ab241bfe --- /dev/null +++ b/ports/esp32/cmodules/esp_err/README.md @@ -0,0 +1,5 @@ +Error Codes and Helper Functions +https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_err.html + +Wrapped around +https://github.com/espressif/esp-idf/blob/master/components/esp_common/include/esp_err.h From fded57db7abef0e655d349b35fe191390ddafa99 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa <70886343+IhorNehrutsa@users.noreply.github.com> Date: Mon, 16 Nov 2020 19:40:08 +0200 Subject: [PATCH 6/8] Create README.md --- ports/esp32/cmodules/pcnt/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 ports/esp32/cmodules/pcnt/README.md diff --git a/ports/esp32/cmodules/pcnt/README.md b/ports/esp32/cmodules/pcnt/README.md new file mode 100644 index 0000000000000..b348794afde9f --- /dev/null +++ b/ports/esp32/cmodules/pcnt/README.md @@ -0,0 +1,19 @@ +**ESP32 Pulse Counter** +https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html + +Wrapped around +https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/pcnt.h +https://github.com/espressif/esp-idf/blob/master/components/hal/include/hal/pcnt_types.h +https://github.com/espressif/esp-idf/blob/master/components/driver/pcnt.c + +See also +https://github.com/espressif/esp-idf/tree/master/examples/peripherals/pcnt/pulse_count_event + + +**ESP32 Quadrature Encoder based on Pulse Counter(PCNT)** +Based on +https://github.com/madhephaestus/ESP32Encoder +https://github.com/bboser/MicroPython_ESP32_psRAM_LoBo/blob/quad_decoder/MicroPython_BUILD/components/micropython/esp32/machine_dec.c + +See also +https://github.com/espressif/esp-idf/tree/master/examples/peripherals/pcnt/rotary_encoder From 82d5a3d1fef9004810fd4b56ae3485f9578f4a27 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa <70886343+IhorNehrutsa@users.noreply.github.com> Date: Mon, 16 Nov 2020 19:41:22 +0200 Subject: [PATCH 7/8] Update README.md --- ports/esp32/cmodules/esp_err/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/esp32/cmodules/esp_err/README.md b/ports/esp32/cmodules/esp_err/README.md index 47c94ab241bfe..ba2f839528b7c 100644 --- a/ports/esp32/cmodules/esp_err/README.md +++ b/ports/esp32/cmodules/esp_err/README.md @@ -1,3 +1,5 @@ +**EspError Exception** + Error Codes and Helper Functions https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_err.html From 11e9e53b8c33e259344702724ab9a378ab566cd5 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Mon, 16 Nov 2020 10:23:42 -0800 Subject: [PATCH 8/8] Fix EspError: esp_err_to_name() --- ports/esp32/cmodules/esp_err/esp_err.c | 3 +++ ports/esp32/cmodules/esp_err/esp_error.h | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ports/esp32/cmodules/esp_err/esp_err.c b/ports/esp32/cmodules/esp_err/esp_err.c index cab6b29305053..08f7b6114bfd7 100644 --- a/ports/esp32/cmodules/esp_err/esp_err.c +++ b/ports/esp32/cmodules/esp_err/esp_err.c @@ -26,6 +26,9 @@ */ /* +Error Codes and Helper Functions +https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_err.html + Wrapped around https://github.com/espressif/esp-idf/blob/master/components/esp_common/include/esp_err.h */ diff --git a/ports/esp32/cmodules/esp_err/esp_error.h b/ports/esp32/cmodules/esp_err/esp_error.h index 153e283d1168c..565515557f5a9 100644 --- a/ports/esp32/cmodules/esp_err/esp_error.h +++ b/ports/esp32/cmodules/esp_err/esp_error.h @@ -1,3 +1,4 @@ const mp_obj_type_t mp_type_EspError; -#define raise_esp_error(err) mp_raise_msg_varg(&mp_type_EspError, MP_ERROR_TEXT("%d(0x%X)"), err, err); +#define raise_esp_error(err) mp_raise_msg_varg(&mp_type_EspError, MP_ERROR_TEXT("%d(0x%X) - %s"), err, err, esp_err_to_name(err)); +