Support for GPIO wakeup in node.dsleep() (#3115)

This commit is contained in:
tomsci 2020-08-22 09:32:45 +01:00 committed by GitHub
parent 8db97c0f52
commit fa2348f36b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 27 deletions

View File

@ -1,5 +1,6 @@
#include "module.h"
#include "lauxlib.h"
#include "common.h"
#include "legc.h"
#include "lundump.h"
#include "platform.h"
@ -7,6 +8,8 @@
#include "vfs.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "soc/efuse_reg.h"
#include "ldebug.h"
#include "esp_vfs.h"
@ -46,11 +49,103 @@ static int node_restart (lua_State *L)
}
// Lua: node.dsleep (microseconds)
// Lua: node.dsleep (microseconds|{opts})
static int node_dsleep (lua_State *L)
{
uint64_t us = luaL_optinteger (L, 1, 0);
esp_deep_sleep (us);
lua_settop(L, 1);
bool enable_timer_wakeup = false;
int64_t usecs = 0;
int type = lua_type(L, 1);
if (type == LUA_TNUMBER) {
enable_timer_wakeup = true;
usecs = lua_tointeger(L, 1);
} else if (type == LUA_TTABLE) {
// time options: us, secs
lua_getfield(L, 1, "us");
lua_getfield(L, 1, "secs");
enable_timer_wakeup = !lua_isnil(L, 2) || !lua_isnil(L, 3);
lua_pop(L, 2);
if (enable_timer_wakeup) {
usecs = opt_checkint(L, "us", 0);
usecs += (int64_t)opt_checkint(L, "secs", 0) * 1000000;
}
// GPIO wakeup options: gpio = num|{num, num, ...}
uint64_t pin_mask = 0;
lua_getfield(L, -1, "gpio");
type = lua_type(L, -1);
if (type == LUA_TNUMBER) {
pin_mask |= 1ULL << lua_tointeger(L, -1);
} else if (type == LUA_TTABLE) {
for (int i = 1; ; i++) {
lua_rawgeti(L, -1, i);
int pin = lua_tointeger(L, -1);
lua_pop(L, 1);
if (!pin) {
break;
}
pin_mask |= 1ULL << pin;
}
}
lua_pop(L, 1); // gpio
// Check pin validity here to get better error messages
for (int pin = 0; pin < GPIO_PIN_COUNT; pin++) {
if (pin_mask & (1ULL << pin)) {
if (!rtc_gpio_is_valid_gpio(pin)) {
return luaL_error(L, "Pin %d is not an RTC GPIO and cannot be used for wakeup", pin);
}
}
}
int level = opt_checkint_range(L, "level", 1, 0, 1);
bool pull = opt_checkbool(L, "pull", false);
bool touch = opt_checkbool(L, "touch", false);
if (opt_get(L, "isolate", LUA_TTABLE)) {
for (int i = 1; ; i++) {
lua_rawgeti(L, -1, i);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
break;
}
int pin = lua_tointeger(L, -1);
lua_pop(L, 1);
int err = rtc_gpio_isolate(pin);
if (err) {
return luaL_error(L, "Error %d returned from rtc_gpio_isolate(%d)", err, pin);
}
}
lua_pop(L, 1); // isolate table
}
if (pull) {
// Keeping the peripheral domain powered keeps the pullups/downs working
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
}
if (pin_mask) {
esp_sleep_ext1_wakeup_mode_t mode = (level == 1) ?
ESP_EXT1_WAKEUP_ANY_HIGH : ESP_EXT1_WAKEUP_ALL_LOW;
int err = esp_sleep_enable_ext1_wakeup(pin_mask, mode);
if (err) {
return luaL_error(L, "Error %d returned from esp_sleep_enable_ext1_wakeup", err);
}
}
if (touch) {
esp_sleep_enable_touchpad_wakeup();
}
} else {
luaL_argerror(L, 1, "Expected integer or table");
}
if (enable_timer_wakeup) {
esp_sleep_enable_timer_wakeup(usecs);
}
esp_deep_sleep_start();
// Note, above call does not actually return
return 0;
}

View File

@ -88,42 +88,41 @@ dofile("hello.lc")
## node.dsleep()
Enters deep sleep mode, wakes up when timed out.
Enters deep sleep mode. When the processor wakes back up depends on the supplied `options`. Unlike light sleep, waking from deep sleep restarts the processor, therefore this API never returns. Wake up can be triggered by a time period, or when a GPIO (or GPIOs) change level, or when a touchpad event occurs. If multiple different wakeup sources are specified, the processor will wake when any of them occur. Use [`node.bootreason()`](#nodebootreason) to determine what caused the wakeup.
The maximum sleep time is 4294967295us, ~71 minutes. This is an SDK limitation.
Firmware from before 05 Jan 2016 have a maximum sleeptime of ~35 minutes.
Only RTC GPIO pins can be used to trigger wake from deep sleep, and they should be configured as inputs prior to calling this API. On the ESP32, the RTC pins are GPIOs 0, 2, 4, 12-15, 25-27, and 32-39. An error will be raised if any of the specified pins are not RTC-capable. If multiple pins are specified and `level=1` (which is the default), the wakeup will occur if *any* of the pins are high. If `level=0` then the wakeup will only occur if *all* the specified pins are low.
!!! note "Note:"
This function can only be used in the condition that esp8266 PIN32(RST) and PIN8(XPD_DCDC aka GPIO16) are connected together. Using sleep(0) will set no wake up timer, connect a GPIO to pin RST, the chip will wake up by a falling-edge on pin RST.
For compatibility, a number parameter `usecs` can be supplied instead of an `options` table, which is equivalent to `node.dsleep({us = usecs})`.
#### Syntax
`node.dsleep(us, option)`
`node.dsleep(usecs)` or `node.dsleep(options)`
#### Parameters
- `us` number (integer) or `nil`, sleep time in micro second. If `us == 0`, it will sleep forever. If `us == nil`, will not set sleep time.
- `option` number (integer) or `nil`. If `nil`, it will use last alive setting as default option.
- 0, init data byte 108 is valuable
- \> 0, init data byte 108 is valueless
- 0, RF_CAL or not after deep-sleep wake up, depends on init data byte 108
- 1, RF_CAL after deep-sleep wake up, there will belarge current
- 2, no RF_CAL after deep-sleep wake up, there will only be small current
- 4, disable RF after deep-sleep wake up, just like modem sleep, there will be the smallest current
- `options`, a table containing some of:
- `secs`, a number of seconds to sleep. This permits longer sleep periods compared to using the `us` parameter.
- `us`, a number of microseconds to sleep. If both `secs` and `us` are provided, the values are combined.
- `gpio`, a single GPIO number or a list of GPIOs. These pins must all be RTC-capable otherwise an error is raised.
- `level`. Whether to trigger when *any* of the GPIOs are high (`level=1`, which is the default if not specified), or when *all* the GPIOs are low (`level=0`).
- `isolate`. A list of GPIOs to isolate. Isolating a GPIO disables input, output, pullup, pulldown, and enables hold feature for an RTC IO. Use this function if an RTC IO needs to be disconnected from internal circuits in deep sleep, to minimize leakage current.
- `pull`, boolean, whether to keep powering previously-configured internal pullup/pulldown resistors. Default is `false` if not specified.
- `touch`, boolean, whether to trigger wakeup from any previously-configured touchpads. Default is `false` if not specified.
If an empty options table is specified, ie no wakeup sources, then the chip will sleep forever with no way to wake it (except for power cycling or triggering the reset pin/button).
#### Returns
`nil`
Does not return.
#### Example
```lua
--do nothing
node.dsleep()
--sleep μs
node.dsleep(1000000)
--set sleep option, then sleep μs
node.dsleep(1000000, 4)
--set sleep option only
node.dsleep(nil,4)
-- sleep 10 seconds then reboot
node.dsleep({ secs = 10 })
-- sleep until 10 seconds have elapsed or either of GPIO 13 or 15 becomes high
node.dsleep({ secs = 10, gpio = { 13, 15 } })
-- Sleep forever until GPIO 13 is low, and keep its pullup powered
node.dsleep({ gpio = 13, level = 0, pull = true })
```
## node.flashid()