1 /*
2 * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/kernel.h>
7 #include <zephyr/pm/pm.h>
8 #include <zephyr/pm/device.h>
9 #include <zephyr/pm/policy.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <esp_sleep.h>
12 #include <driver/gpio.h>
13
14 /* Most development boards have "boot" button attached to GPIO0.
15 * You can also change this to another pin.
16 */
17 #define SW0_NODE DT_ALIAS(sw0)
18
19 #if !DT_NODE_HAS_STATUS_OKAY(SW0_NODE)
20 #error "unsupported board: sw0 devicetree alias is not defined"
21 #endif
22
23 /* Add an extra delay when sleeping to make sure that light sleep
24 * is chosen.
25 */
26 #define LIGHT_SLP_EXTRA_DELAY (50UL)
27
28 static const struct gpio_dt_spec button =
29 GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
30
main(void)31 int main(void)
32 {
33 if (!gpio_is_ready_dt(&button)) {
34 printk("Error: button device %s is not ready\n", button.port->name);
35 return 0;
36 }
37
38 const int wakeup_level = (button.dt_flags & GPIO_ACTIVE_LOW) ? 0 : 1;
39
40 esp_gpio_wakeup_enable(button.pin,
41 wakeup_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL);
42
43 while (true) {
44 /* Wake up in 2 seconds, or when button is pressed */
45 esp_sleep_enable_timer_wakeup(2000000);
46 esp_sleep_enable_gpio_wakeup();
47
48 /* Wait until GPIO goes high */
49 if (gpio_pin_get_dt(&button) == wakeup_level) {
50 printk("Waiting for GPIO%d to go high...\n", button.pin);
51 do {
52 k_busy_wait(10000);
53 } while (gpio_pin_get_dt(&button) == wakeup_level);
54 }
55
56 printk("Entering light sleep\n");
57 /* To make sure the complete line is printed before entering sleep mode,
58 * need to wait until UART TX FIFO is empty
59 */
60 k_busy_wait(10000);
61
62 /* Get timestamp before entering sleep */
63 int64_t t_before_ms = k_uptime_get();
64
65 /* Sleep triggers the idle thread, which makes the pm subsystem select some
66 * pre-defined power state. Light sleep is used here because there is enough
67 * time to consider it, energy-wise, worthy.
68 */
69 k_sleep(K_USEC(DT_PROP(DT_NODELABEL(light_sleep), min_residency_us) +
70 LIGHT_SLP_EXTRA_DELAY));
71 /* Execution continues here after wakeup */
72
73 /* Get timestamp after waking up from sleep */
74 int64_t t_after_ms = k_uptime_get();
75
76 /* Determine wake up reason */
77 const char *wakeup_reason;
78
79 switch (esp_sleep_get_wakeup_cause()) {
80 case ESP_SLEEP_WAKEUP_TIMER:
81 wakeup_reason = "timer";
82 break;
83 case ESP_SLEEP_WAKEUP_GPIO:
84 wakeup_reason = "pin";
85 break;
86 default:
87 wakeup_reason = "other";
88 break;
89 }
90
91 printk("Returned from light sleep, reason: %s, t=%lld ms, slept for %lld ms\n",
92 wakeup_reason, t_after_ms, (t_after_ms - t_before_ms));
93 }
94
95 return 0;
96 }
97