From abec47a1cd4c26d073f717c8086ba21f64ff1aa3 Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Thu, 15 Feb 2018 07:59:28 -0800 Subject: [PATCH] esp32/modesp32: Add new module "esp32" to support extra wake features. The machine.Pin class is also updated to support these wake-on-pin features. --- ports/esp32/Makefile | 1 + ports/esp32/machine_pin.c | 57 ++++++++++++--- ports/esp32/modesp32.c | 140 +++++++++++++++++++++++++++++++++++++ ports/esp32/modesp32.h | 29 ++++++++ ports/esp32/mpconfigport.h | 2 + 5 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 ports/esp32/modesp32.c create mode 100644 ports/esp32/modesp32.h diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 3c70729fe3..02aebc1a63 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -147,6 +147,7 @@ SRC_C = \ network_lan.c \ modsocket.c \ modesp.c \ + modesp32.c \ moduhashlib.c \ espneopixel.c \ machine_hw_spi.c \ diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 493dff3f50..89ff9d8b77 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -35,6 +35,10 @@ #include "py/mphal.h" #include "modmachine.h" #include "extmod/virtpin.h" +#include "machine_rtc.h" +#include "modesp32.h" + +extern machine_rtc_config_t machine_rtc_config; typedef struct _machine_pin_obj_t { mp_obj_base_t base; @@ -219,10 +223,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_ // pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING) STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_handler, ARG_trigger, ARG_hard }; + enum { ARG_handler, ARG_trigger, ARG_wake }; static const mp_arg_t allowed_args[] = { { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} }, + { MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -232,14 +237,48 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_ // configure irq mp_obj_t handler = args[ARG_handler].u_obj; uint32_t trigger = args[ARG_trigger].u_int; - if (handler == mp_const_none) { - handler = MP_OBJ_NULL; - trigger = 0; + mp_obj_t wake_obj = args[ARG_wake].u_obj; + + if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) { + mp_int_t wake; + if (mp_obj_get_int_maybe(wake_obj, &wake)) { + if (wake < 2 || wake > 7) { + mp_raise_ValueError("bad wake value"); + } + } else { + mp_raise_ValueError("bad wake value"); + } + + if (machine_rtc_config.wake_on_touch) { // not compatible + mp_raise_ValueError("no resources"); + } + + if (!RTC_IS_VALID_EXT_PIN(self->id)) { + mp_raise_ValueError("invalid pin for wake"); + } + + if (machine_rtc_config.ext0_pin == -1) { + machine_rtc_config.ext0_pin = self->id; + } else if (machine_rtc_config.ext0_pin != self->id) { + mp_raise_ValueError("no resources"); + } + + machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1; + machine_rtc_config.ext0_wake_types = wake; + } else { + if (machine_rtc_config.ext0_pin == self->id) { + machine_rtc_config.ext0_pin = -1; + } + + if (handler == mp_const_none) { + handler = MP_OBJ_NULL; + trigger = 0; + } + gpio_isr_handler_remove(self->id); + MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; + gpio_set_intr_type(self->id, trigger); + gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); } - gpio_isr_handler_remove(self->id); - MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; - gpio_set_intr_type(self->id, trigger); - gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); } // return the irq object @@ -261,6 +300,8 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) }, { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) }, { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) }, }; STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c new file mode 100644 index 0000000000..db78248f82 --- /dev/null +++ b/ports/esp32/modesp32.c @@ -0,0 +1,140 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * 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. + */ + +#include +#include + +#include +#include +#include "driver/gpio.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timeutils.h" +#include "modmachine.h" +#include "machine_rtc.h" +#include "modesp32.h" + +extern machine_rtc_config_t machine_rtc_config; + +STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) { + + if (machine_rtc_config.ext0_pin != -1) { + mp_raise_ValueError("no resources"); + } + //nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "touchpad wakeup not available for this version of ESP-IDF")); + + machine_rtc_config.wake_on_touch = mp_obj_is_true(wake); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_wake_on_touch_obj, esp32_wake_on_touch); + +STATIC mp_obj_t esp32_wake_on_ext0(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + if (machine_rtc_config.wake_on_touch) { + mp_raise_ValueError("no resources"); + } + enum {ARG_pin, ARG_level}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = mp_obj_new_int(machine_rtc_config.ext0_pin)} }, + { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext0_level} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_pin].u_obj == mp_const_none) { + machine_rtc_config.ext0_pin = -1; // "None" + } else { + gpio_num_t pin_id = machine_pin_get_id(args[ARG_pin].u_obj); + if (pin_id != machine_rtc_config.ext0_pin) { + if (!RTC_IS_VALID_EXT_PIN(pin_id)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin")); + } + machine_rtc_config.ext0_pin = pin_id; + } + } + + machine_rtc_config.ext0_level = args[ARG_level].u_bool; + machine_rtc_config.ext0_wake_types = MACHINE_WAKE_SLEEP | MACHINE_WAKE_DEEPSLEEP; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext0_obj, 0, esp32_wake_on_ext0); + +STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_pins, ARG_level}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext1_level} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint64_t ext1_pins = machine_rtc_config.ext1_pins; + + + // Check that all pins are allowed + if (args[ARG_pins].u_obj != mp_const_none) { + mp_uint_t len = 0; + mp_obj_t *elem; + mp_obj_get_array(args[ARG_pins].u_obj, &len, &elem); + ext1_pins = 0; + + for (int i = 0; i < len; i++) { + + gpio_num_t pin_id = machine_pin_get_id(elem[i]); + if (!RTC_IS_VALID_EXT_PIN(pin_id)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin")); + break; + } + ext1_pins |= (1ll << pin_id); + } + } + + machine_rtc_config.ext1_level = args[ARG_level].u_bool; + machine_rtc_config.ext1_pins = ext1_pins; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1); + +STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_touch), (mp_obj_t)&esp32_wake_on_touch_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext0), (mp_obj_t)&esp32_wake_on_ext0_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext1), (mp_obj_t)&esp32_wake_on_ext1_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ALL_LOW), mp_const_false }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), mp_const_true }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table); + +const mp_obj_module_t esp32_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp32_module_globals, +}; diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h new file mode 100644 index 0000000000..83532e052f --- /dev/null +++ b/ports/esp32/modesp32.h @@ -0,0 +1,29 @@ +#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H +#define MICROPY_INCLUDED_ESP32_MODESP32_H + +#define RTC_VALID_EXT_PINS \ +( \ + (1ll << 0) | \ + (1ll << 2) | \ + (1ll << 4) | \ + (1ll << 12) | \ + (1ll << 13) | \ + (1ll << 14) | \ + (1ll << 15) | \ + (1ll << 25) | \ + (1ll << 26) | \ + (1ll << 27) | \ + (1ll << 32) | \ + (1ll << 33) | \ + (1ll << 34) | \ + (1ll << 35) | \ + (1ll << 36) | \ + (1ll << 37) | \ + (1ll << 38) | \ + (1ll << 39) \ +) + +#define RTC_LAST_EXT_PIN 39 +#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) + +#endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 69d17fd818..e5fc2b4c5d 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -162,6 +162,7 @@ // extra built in modules to add to the list of known ones extern const struct _mp_obj_module_t esp_module; +extern const struct _mp_obj_module_t esp32_module; extern const struct _mp_obj_module_t utime_module; extern const struct _mp_obj_module_t uos_module; extern const struct _mp_obj_module_t mp_module_usocket; @@ -171,6 +172,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \