soc: esp32: add light sleep sample code

Add light sleep sample code.

Signed-off-by: Glauber Maroto Ferreira <glauber.ferreira@espressif.com>
This commit is contained in:
Glauber Maroto Ferreira 2022-08-31 21:37:03 -03:00 committed by Carles Cufí
commit 2ad13a50a7
4 changed files with 174 additions and 0 deletions

View file

@ -0,0 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(esp32_light_sleep)
target_sources(app PRIVATE src/main.c)

View file

@ -0,0 +1,70 @@
.. _esp32-light-sleep-sample:
ESP32 Light Sleep demo
######################
Overview
********
This example illustrates usage of light sleep mode. Unlike deep sleep mode,
light sleep preserves the state of the memory, CPU, and peripherals. Execution
of code on both CPUs is stopped when esp_light_sleep_start() function is called.
When the chip exits light sleep mode, execution continues at the point where it
was stopped, and esp_light_sleep_start() function returns.
The example enables the following wakeup sources:
* ``Timer``: wake up the chip in 2 seconds.
* ``EXT0``: wake up the chip if a button attached to GPIO0 is pressed (i.e. if
GPIO0 goes low).
Requirements
************
This example can be used with any ESP32 development board. Most boards have a
button attached to GPIO0, often labelled BOOT. If the board does not have such
button, an external button can be connected, along with a 10k pull-up resistor,
and a 100nF capacitor to ground for debouncing.
Building, Flashing and Running
******************************
.. zephyr-app-commands::
:zephyr-app: samples/boards/esp32/light_sleep
:board: esp32
:goals: build flash
:compact:
Sample Output
=================
ESP32 core output
-----------------
In the scenario below, the button attached to GPIO0 was pressed and held for
about 500 ms, after the second wakeup from light sleep. The program has
indicated the wakeup reason after each sleep iteration.
.. code-block:: console
*** Booting Zephyr OS build zephyr-v3.1.0-3667-gb42e2b225ecf ***
Entering light sleep
Returned from light sleep, reason: timer, t=3344 ms, slept for 2001 ms
Entering light sleep
Returned from light sleep, reason: timer, t=5354 ms, slept for 2000 ms
Entering light sleep
Returned from light sleep, reason: pin, t=5885 ms, slept for 521 ms
Waiting for GPIO0 to go high...
Entering light sleep
Returned from light sleep, reason: timer, t=8765 ms, slept for 2000 ms
Entering light sleep
Returned from light sleep, reason: timer, t=10776 ms, slept for 2001 ms
Entering light sleep
Troubleshooting
***************
If pressing the button attached to GPIO0 does not affect program behavior,
check DTR/RTS configuration in the serial monitor. This is not necessary for
IDF monitor, but for other tools it might be necessary to set DTR and RTS line
state to "disabled" or "de-asserted".

View file

@ -0,0 +1,3 @@
CONFIG_PM=y
# Required to disable default behavior of deep sleep on timeout
CONFIG_PM_DEVICE=y

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/pm/pm.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/policy.h>
#include <zephyr/drivers/gpio.h>
#include "esp_sleep.h"
/* Most development boards have "boot" button attached to GPIO0.
* You can also change this to another pin.
*/
#define SW0_NODE DT_ALIAS(sw0)
#if !DT_NODE_HAS_STATUS(SW0_NODE, okay)
#error "unsupported board: sw0 devicetree alias is not defined"
#endif
/* Add an extra delay when sleeping to make sure that light sleep
* is chosen.
*/
#define LIGHT_SLP_EXTRA_DELAY (50UL)
static const struct gpio_dt_spec button =
GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
void main(void)
{
if (!device_is_ready(button.port)) {
printk("Error: button device %s is not ready\n", button.port->name);
return;
}
const int wakeup_level = (button.dt_flags & GPIO_ACTIVE_LOW) ? 0 : 1;
esp_gpio_wakeup_enable(button.pin,
wakeup_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL);
while (true) {
/* Wake up in 2 seconds, or when button is pressed */
esp_sleep_enable_timer_wakeup(2000000);
esp_sleep_enable_gpio_wakeup();
/* Wait until GPIO goes high */
if (gpio_pin_get_dt(&button) == wakeup_level) {
printk("Waiting for GPIO%d to go high...\n", button.pin);
do {
k_busy_wait(10000);
} while (gpio_pin_get_dt(&button) == wakeup_level);
}
printk("Entering light sleep\n");
/* To make sure the complete line is printed before entering sleep mode,
* need to wait until UART TX FIFO is empty
*/
k_busy_wait(10000);
/* Get timestamp before entering sleep */
int64_t t_before_ms = k_uptime_get();
/* Sleep triggers the idle thread, which makes the pm subsystem select some
* pre-defined power state. Light sleep is used here because there is enough
* time to consider it, energy-wise, worthy.
*/
k_sleep(K_USEC(DT_PROP(DT_NODELABEL(light_sleep), min_residency_us) +
LIGHT_SLP_EXTRA_DELAY));
/* Execution continues here after wakeup */
/* Get timestamp after waking up from sleep */
int64_t t_after_ms = k_uptime_get();
/* Determine wake up reason */
const char *wakeup_reason;
switch (esp_sleep_get_wakeup_cause()) {
case ESP_SLEEP_WAKEUP_TIMER:
wakeup_reason = "timer";
break;
case ESP_SLEEP_WAKEUP_GPIO:
wakeup_reason = "pin";
break;
default:
wakeup_reason = "other";
break;
}
printk("Returned from light sleep, reason: %s, t=%lld ms, slept for %lld ms\n",
wakeup_reason, t_after_ms, (t_after_ms - t_before_ms));
}
}