Commit 32d7cf6e authored by Damien George's avatar Damien George
Browse files

esp8266: Implement basic deep-sleep capabilities.

Use the machine.deepsleep() function to enter the sleep mode.  Use the
RTC to configure the alarm to wake the device.

Basic use is the following:

    import machine

    # configure RTC's ALARM0 to wake device from deep sleep
    rtc = machine.RTC()
    rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)

    # do other things
    # ...

    # set ALARM0's alarm to wake after 10 seconds
    rtc.alarm(rtc.ALARM0, 10000)

    # enter deep-sleep state (system is reset upon waking)
    machine.deepsleep()

To detect if the system woke from a deep sleep use:

    if machine.reset_cause() == machine.DEEPSLEEP_RESET:
        print('woke from deep sleep')
parent 2a51f72e
...@@ -33,14 +33,20 @@ ...@@ -33,14 +33,20 @@
#include "extmod/machine_i2c.h" #include "extmod/machine_i2c.h"
#include "utils.h" #include "utils.h"
#include "modpyb.h" #include "modpyb.h"
#include "modpybrtc.h"
#include "os_type.h" #include "os_type.h"
#include "osapi.h" #include "osapi.h"
#include "etshal.h" #include "etshal.h"
#include "ets_alt_task.h"
#include "user_interface.h" #include "user_interface.h"
#if MICROPY_PY_MACHINE #if MICROPY_PY_MACHINE
//#define MACHINE_WAKE_IDLE (0x01)
//#define MACHINE_WAKE_SLEEP (0x02)
#define MACHINE_WAKE_DEEPSLEEP (0x04)
STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) { STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) { if (n_args == 0) {
// get // get
...@@ -75,6 +81,40 @@ STATIC mp_obj_t machine_unique_id(void) { ...@@ -75,6 +81,40 @@ STATIC mp_obj_t machine_unique_id(void) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
STATIC mp_obj_t machine_deepsleep(void) {
// default to sleep forever
uint32_t sleep_us = 0;
// see if RTC.ALARM0 should wake the device
if (pyb_rtc_alarm0_wake & MACHINE_WAKE_DEEPSLEEP) {
uint64_t t = pyb_rtc_get_us_since_2000();
if (pyb_rtc_alarm0_expiry <= t) {
sleep_us = 1; // alarm already expired so wake immediately
} else {
uint64_t delta = pyb_rtc_alarm0_expiry - t;
if (delta <= 0xffffffff) {
// sleep for the desired time
sleep_us = delta;
} else {
// overflow, just set to maximum sleep time
sleep_us = 0xffffffff;
}
}
}
// put the device in a deep-sleep state
system_deep_sleep_set_option(0); // default power down mode; TODO check this
system_deep_sleep(sleep_us);
for (;;) {
// we must not return
ets_loop_iter();
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
typedef struct _esp_timer_obj_t { typedef struct _esp_timer_obj_t {
mp_obj_base_t base; mp_obj_base_t base;
os_timer_t timer; os_timer_t timer;
...@@ -160,7 +200,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { ...@@ -160,7 +200,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
...@@ -168,6 +210,14 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { ...@@ -168,6 +210,14 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) },
// wake abilities
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
// reset causes
{ MP_ROM_QSTR(MP_QSTR_PWR_ON_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
{ MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) },
}; };
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
......
...@@ -49,6 +49,10 @@ typedef struct _pyb_rtc_obj_t { ...@@ -49,6 +49,10 @@ typedef struct _pyb_rtc_obj_t {
// singleton RTC object // singleton RTC object
STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}}; STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
// ALARM0 state
uint32_t pyb_rtc_alarm0_wake; // see MACHINE_WAKE_xxx constants
uint64_t pyb_rtc_alarm0_expiry; // in microseconds
void mp_hal_rtc_init(void) { void mp_hal_rtc_init(void) {
uint32_t magic; uint32_t magic;
...@@ -61,6 +65,10 @@ void mp_hal_rtc_init(void) { ...@@ -61,6 +65,10 @@ void mp_hal_rtc_init(void) {
system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal)); system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
} }
// reset ALARM0 state
pyb_rtc_alarm0_wake = 0;
pyb_rtc_alarm0_expiry = 0;
} }
STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
...@@ -177,9 +185,49 @@ STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { ...@@ -177,9 +185,49 @@ STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 2, pyb_rtc_memory); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 2, pyb_rtc_memory);
STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time_in) {
(void)self_in; // unused
// check we want alarm0
if (mp_obj_get_int(alarm_id) != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid alarm"));
}
// set expiry time (in microseconds)
pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + mp_obj_get_int(time_in) * 1000;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_rtc_alarm_obj, pyb_rtc_alarm);
STATIC mp_obj_t pyb_rtc_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_trigger, ARG_wake };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// check we want alarm0
if (args[ARG_trigger].u_int != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid alarm"));
}
// set the wake value
pyb_rtc_alarm0_wake = args[ARG_wake].u_int;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = { STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&pyb_rtc_datetime_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&pyb_rtc_datetime_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&pyb_rtc_memory_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&pyb_rtc_memory_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(0) },
}; };
STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
extern uint32_t pyb_rtc_alarm0_wake;
extern uint64_t pyb_rtc_alarm0_expiry;
void pyb_rtc_set_us_since_2000(uint64_t nowus); void pyb_rtc_set_us_since_2000(uint64_t nowus);
uint64_t pyb_rtc_get_us_since_2000(); uint64_t pyb_rtc_get_us_since_2000();
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment