diff options
-rw-r--r-- | ports/esp32/Makefile | 2 | ||||
-rw-r--r-- | ports/esp32/machine_rtc.c | 162 | ||||
-rw-r--r-- | ports/esp32/machine_rtc.h | 42 | ||||
-rw-r--r-- | ports/esp32/modmachine.c | 135 | ||||
-rw-r--r-- | ports/esp32/modmachine.h | 7 | ||||
-rw-r--r-- | ports/esp32/sdkconfig.h | 2 |
6 files changed, 349 insertions, 1 deletions
diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 6bf212964..3c70729fe 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -152,6 +152,7 @@ SRC_C = \ machine_hw_spi.c \ machine_wdt.c \ mpthreadport.c \ + machine_rtc.c \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -251,6 +252,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ dport_access.o \ wifi_init.o \ wifi_internal.o \ + sleep_modes.o \ ) ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c new file mode 100644 index 000000000..a70134422 --- /dev/null +++ b/ports/esp32/machine_rtc.c @@ -0,0 +1,162 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com> + * Copyright (c) 2017 "Tom Manning" <tom@manningetal.com> + * + * 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 <stdio.h> +#include <string.h> + +#include <time.h> +#include <sys/time.h> +#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" + +typedef struct _machine_rtc_obj_t { + mp_obj_base_t base; +} machine_rtc_obj_t; + +#define MEM_MAGIC 0x75507921 +/* There is 8K of rtc_slow_memory, but some is used by the system software + If the USER_MAXLEN is set to high, the following compile error will happen: + region `rtc_slow_seg' overflowed by N bytes + The current system software allows almost 4096 to be used. + To avoid running into issues if the system software uses more, 2048 was picked as a max length +*/ +#define MEM_USER_MAXLEN 2048 +RTC_DATA_ATTR uint32_t rtc_user_mem_magic; +RTC_DATA_ATTR uint32_t rtc_user_mem_len; +RTC_DATA_ATTR uint8_t rtc_user_mem_data[MEM_USER_MAXLEN]; + +// singleton RTC object +STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}}; + +machine_rtc_config_t machine_rtc_config = { + .ext1_pins = 0, + .ext0_pin = -1 + }; + +STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&machine_rtc_obj; +} + +STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // Get time + + struct timeval tv; + + gettimeofday(&tv, NULL); + timeutils_struct_time_t tm; + + timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tv.tv_usec) + }; + + return mp_obj_new_tuple(8, tuple); + } else { + // Set time + + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 8, &items); + + struct timeval tv = {0}; + tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6])); + settimeofday(&tv, NULL); + + return mp_const_none; + } +} +STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { + return machine_rtc_datetime_helper(n_args, args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime); + +STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) { + mp_obj_t args[2] = {self_in, date}; + machine_rtc_datetime_helper(2, args); + + if (rtc_user_mem_magic != MEM_MAGIC) { + rtc_user_mem_magic = MEM_MAGIC; + rtc_user_mem_len = 0; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init); + +STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // read RTC memory + uint32_t len = rtc_user_mem_len; + uint8_t rtcram[MEM_USER_MAXLEN]; + memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len); + return mp_obj_new_bytes(rtcram, len); + } else { + // write RTC memory + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + if (bufinfo.len > MEM_USER_MAXLEN) { + mp_raise_ValueError("buffer too long"); + } + memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len); + rtc_user_mem_len = bufinfo.len; + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory); + +STATIC const mp_map_elem_t machine_rtc_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&machine_rtc_datetime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&machine_rtc_datetime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&machine_rtc_memory_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); + +const mp_obj_type_t machine_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .make_new = machine_rtc_make_new, + .locals_dict = (mp_obj_t)&machine_rtc_locals_dict, +}; diff --git a/ports/esp32/machine_rtc.h b/ports/esp32/machine_rtc.h new file mode 100644 index 000000000..c2016ca79 --- /dev/null +++ b/ports/esp32/machine_rtc.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com> + * Copyright (c) 2017 "Tom Manning" <tom@manningetal.com> + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_ESP32_MACHINE_RTC_H +#define MICROPY_INCLUDED_ESP32_MACHINE_RTC_H + +#include "modmachine.h" + +typedef struct { + uint64_t ext1_pins; // set bit == pin# + int8_t ext0_pin; // just the pin#, -1 == None + bool wake_on_touch : 1; + bool ext0_level : 1; + wake_type_t ext0_wake_types; + bool ext1_level : 1; +} machine_rtc_config_t; + +#endif diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 32c9c5ad5..72211a2c5 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -33,7 +33,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "rom/ets_sys.h" +#include "rom/rtc.h" #include "esp_system.h" +#include "driver/touch_pad.h" #include "py/obj.h" #include "py/runtime.h" @@ -43,9 +45,20 @@ #include "extmod/machine_i2c.h" #include "extmod/machine_spi.h" #include "modmachine.h" +#include "machine_rtc.h" #if MICROPY_PY_MACHINE +extern machine_rtc_config_t machine_rtc_config; + +typedef enum { + MP_PWRON_RESET = 1, + MP_HARD_RESET, + MP_WDT_RESET, + MP_DEEPSLEEP_RESET, + MP_SOFT_RESET +} reset_reason_t; + STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { // get @@ -64,6 +77,104 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); +STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + enum {ARG_sleep_ms}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_sleep_ms, MP_ARG_INT, { .u_int = 0 } }, + }; + + 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); + + + mp_int_t expiry = args[ARG_sleep_ms].u_int; + + if (expiry != 0) { + esp_sleep_enable_timer_wakeup(expiry * 1000); + } + + if (machine_rtc_config.ext0_pin != -1 && (machine_rtc_config.ext0_wake_types & wake_type)) { + esp_sleep_enable_ext0_wakeup(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0); + } + + if (machine_rtc_config.ext1_pins != 0) { + esp_sleep_enable_ext1_wakeup( + machine_rtc_config.ext1_pins, + machine_rtc_config.ext1_level ? ESP_EXT1_WAKEUP_ANY_HIGH : ESP_EXT1_WAKEUP_ALL_LOW); + } + + if (machine_rtc_config.wake_on_touch) { + if (esp_sleep_enable_touchpad_wakeup() != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "esp_sleep_enable_touchpad_wakeup() failed")); + } + } + + switch(wake_type) { + case MACHINE_WAKE_SLEEP: + esp_light_sleep_start(); + break; + case MACHINE_WAKE_DEEPSLEEP: + esp_deep_sleep_start(); + break; + } + return mp_const_none; +} + +STATIC mp_obj_t machine_sleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "light sleep not available for this version of ESP-IDF")); + return machine_sleep_helper(MACHINE_WAKE_SLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sleep_obj, 0, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return machine_sleep_helper(MACHINE_WAKE_DEEPSLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_deepsleep_obj, 0, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + switch(rtc_get_reset_reason(0)) { + case POWERON_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_PWRON_RESET); + break; + case SW_RESET: + case SW_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_SOFT_RESET); + break; + case OWDT_RESET: + case TG0WDT_SYS_RESET: + case TG1WDT_SYS_RESET: + case RTCWDT_SYS_RESET: + case RTCWDT_BROWN_OUT_RESET: + case RTCWDT_CPU_RESET: + case RTCWDT_RTC_RESET: + case TGWDT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_WDT_RESET); + break; + + case DEEPSLEEP_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_DEEPSLEEP_RESET); + break; + + case EXT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_HARD_RESET); + break; + + case NO_MEAN: + case SDIO_RESET: + case INTRUSION_RESET: + default: + return MP_OBJ_NEW_SMALL_INT(0); + break; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause); + +STATIC mp_obj_t machine_wake_reason(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return MP_OBJ_NEW_SMALL_INT(esp_sleep_get_wakeup_cause()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_wake_reason_obj, 0, machine_wake_reason); + STATIC mp_obj_t machine_reset(void) { esp_restart(); return mp_const_none; @@ -106,6 +217,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, @@ -115,6 +228,10 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) }, + + // wake abilities + { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, @@ -122,8 +239,26 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, + + // Reset reasons + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(MP_HARD_RESET) }, + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(MP_WDT_RESET) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(MP_DEEPSLEEP_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(MP_SOFT_RESET) }, + + // Wake reasons + { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) }, + { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT0_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT1_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT1) }, + { MP_ROM_QSTR(MP_QSTR_TIMER_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TIMER) }, + { MP_ROM_QSTR(MP_QSTR_TOUCHPAD_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TOUCHPAD) }, + { MP_ROM_QSTR(MP_QSTR_ULP_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_ULP) }, }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index 58229007d..c8513a471 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -3,6 +3,12 @@ #include "py/obj.h" +typedef enum { + //MACHINE_WAKE_IDLE=0x01, + MACHINE_WAKE_SLEEP=0x02, + MACHINE_WAKE_DEEPSLEEP=0x04 +} wake_type_t; + extern const mp_obj_type_t machine_timer_type; extern const mp_obj_type_t machine_wdt_type; extern const mp_obj_type_t machine_pin_type; @@ -12,6 +18,7 @@ extern const mp_obj_type_t machine_dac_type; extern const mp_obj_type_t machine_pwm_type; extern const mp_obj_type_t machine_hw_spi_type; extern const mp_obj_type_t machine_uart_type; +extern const mp_obj_type_t machine_rtc_type; void machine_pins_init(void); void machine_pins_deinit(void); diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index 7fcbb7c01..3f5c7402a 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -23,7 +23,7 @@ #define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240 #define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1 #define CONFIG_ESP32_DEBUG_OCDAWARE 1 -#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 0 +#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000 #define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1 #define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1 #define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1 |