Skip to content

Commit 32d7cf6

Browse files
committed
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')
1 parent 2a51f72 commit 32d7cf6

3 files changed

Lines changed: 101 additions & 0 deletions

File tree

esp8266/modmachine.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,20 @@
3333
#include "extmod/machine_i2c.h"
3434
#include "utils.h"
3535
#include "modpyb.h"
36+
#include "modpybrtc.h"
3637

3738
#include "os_type.h"
3839
#include "osapi.h"
3940
#include "etshal.h"
41+
#include "ets_alt_task.h"
4042
#include "user_interface.h"
4143

4244
#if MICROPY_PY_MACHINE
4345

46+
//#define MACHINE_WAKE_IDLE (0x01)
47+
//#define MACHINE_WAKE_SLEEP (0x02)
48+
#define MACHINE_WAKE_DEEPSLEEP (0x04)
49+
4450
STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) {
4551
if (n_args == 0) {
4652
// get
@@ -75,6 +81,40 @@ STATIC mp_obj_t machine_unique_id(void) {
7581
}
7682
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
7783

84+
STATIC mp_obj_t machine_deepsleep(void) {
85+
// default to sleep forever
86+
uint32_t sleep_us = 0;
87+
88+
// see if RTC.ALARM0 should wake the device
89+
if (pyb_rtc_alarm0_wake & MACHINE_WAKE_DEEPSLEEP) {
90+
uint64_t t = pyb_rtc_get_us_since_2000();
91+
if (pyb_rtc_alarm0_expiry <= t) {
92+
sleep_us = 1; // alarm already expired so wake immediately
93+
} else {
94+
uint64_t delta = pyb_rtc_alarm0_expiry - t;
95+
if (delta <= 0xffffffff) {
96+
// sleep for the desired time
97+
sleep_us = delta;
98+
} else {
99+
// overflow, just set to maximum sleep time
100+
sleep_us = 0xffffffff;
101+
}
102+
}
103+
}
104+
105+
// put the device in a deep-sleep state
106+
system_deep_sleep_set_option(0); // default power down mode; TODO check this
107+
system_deep_sleep(sleep_us);
108+
109+
for (;;) {
110+
// we must not return
111+
ets_loop_iter();
112+
}
113+
114+
return mp_const_none;
115+
}
116+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
117+
78118
typedef struct _esp_timer_obj_t {
79119
mp_obj_base_t base;
80120
os_timer_t timer;
@@ -160,14 +200,24 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
160200
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
161201
{ MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
162202
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
203+
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
163204

205+
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
164206
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) },
165207
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
166208
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
167209
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
168210
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
169211
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
170212
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) },
213+
214+
// wake abilities
215+
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
216+
217+
// reset causes
218+
{ MP_ROM_QSTR(MP_QSTR_PWR_ON_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
219+
{ MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
220+
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) },
171221
};
172222

173223
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);

esp8266/modpybrtc.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ typedef struct _pyb_rtc_obj_t {
4949
// singleton RTC object
5050
STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
5151

52+
// ALARM0 state
53+
uint32_t pyb_rtc_alarm0_wake; // see MACHINE_WAKE_xxx constants
54+
uint64_t pyb_rtc_alarm0_expiry; // in microseconds
55+
5256
void mp_hal_rtc_init(void) {
5357
uint32_t magic;
5458

@@ -61,6 +65,10 @@ void mp_hal_rtc_init(void) {
6165
system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
6266
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
6367
}
68+
69+
// reset ALARM0 state
70+
pyb_rtc_alarm0_wake = 0;
71+
pyb_rtc_alarm0_expiry = 0;
6472
}
6573

6674
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) {
177185
}
178186
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 2, pyb_rtc_memory);
179187

188+
STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time_in) {
189+
(void)self_in; // unused
190+
191+
// check we want alarm0
192+
if (mp_obj_get_int(alarm_id) != 0) {
193+
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid alarm"));
194+
}
195+
196+
// set expiry time (in microseconds)
197+
pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + mp_obj_get_int(time_in) * 1000;
198+
199+
return mp_const_none;
200+
201+
}
202+
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_rtc_alarm_obj, pyb_rtc_alarm);
203+
204+
STATIC mp_obj_t pyb_rtc_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
205+
enum { ARG_trigger, ARG_wake };
206+
static const mp_arg_t allowed_args[] = {
207+
{ MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
208+
{ MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
209+
};
210+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
211+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
212+
213+
// check we want alarm0
214+
if (args[ARG_trigger].u_int != 0) {
215+
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid alarm"));
216+
}
217+
218+
// set the wake value
219+
pyb_rtc_alarm0_wake = args[ARG_wake].u_int;
220+
221+
return mp_const_none;
222+
}
223+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
224+
180225
STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
181226
{ MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&pyb_rtc_datetime_obj },
182227
{ MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&pyb_rtc_memory_obj },
228+
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj },
229+
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj },
230+
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(0) },
183231
};
184232
STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
185233

esp8266/modpybrtc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
extern uint32_t pyb_rtc_alarm0_wake;
28+
extern uint64_t pyb_rtc_alarm0_expiry;
29+
2730
void pyb_rtc_set_us_since_2000(uint64_t nowus);
2831

2932
uint64_t pyb_rtc_get_us_since_2000();

0 commit comments

Comments
 (0)