Using Same GPIO for Deep Sleep Wake-up (EXT0) and State Check in Wake Stub on ESP32-S3

Ahmetsafi
Posts: 10
Joined: Wed Aug 07, 2024 12:01 pm

Using Same GPIO for Deep Sleep Wake-up (EXT0) and State Check in Wake Stub on ESP32-S3

Postby Ahmetsafi » Wed Sep 11, 2024 1:47 pm

I'm working on a project using an ESP32-S3, where I want to achieve the following:

- Wake up the ESP32 from deep sleep using a button press on a GPIO pin (using EXT0 wake-up).
- Check the state of the same GPIO in the wake stub function to determine if the button is being held for 4 seconds.


here is my code:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "esp_sleep.h"
  4. #include "esp_attr.h"
  5. #include "rom/rtc.h"
  6. #include "freertos/FreeRTOS.h"
  7. #include "freertos/task.h"
  8. #include "soc/rtc_cntl_reg.h"
  9. #include "soc/rtc_io_reg.h"
  10. #include "driver/rtc_io.h"
  11. #include "esp_wake_stub.h"
  12. #include "esp_system.h"
  13. #include "soc/rtc.h"
  14.  
  15. #define BLE_BUTTON 5  
  16.  
  17. static size_t RTC_DATA_ATTR s_wake_count = 0;
  18. static int RTC_DATA_ATTR s_button_state = 0;
  19. static int RTC_DATA_ATTR s_in5 = 0;
  20.  
  21. static void RTC_IRAM_ATTR wake_stub(void) {
  22.     esp_default_wake_deep_sleep();
  23.     uint32_t gpio_val;
  24.  
  25.     ESP_RTC_LOGI("wake stub function called");
  26.  
  27.     // Configure GPIO for input
  28.     SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_MUX_SEL);
  29.     SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_FUN_IE);
  30.     SET_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_5));
  31.  
  32.     // Read initial button state
  33.     gpio_val = REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S;
  34.     int button_pressed = (gpio_val >> BLE_BUTTON) & 0x1;
  35.  
  36.     ESP_RTC_LOGI("button pressed: %d", button_pressed);
  37.  
  38.     if (button_pressed == 0) {
  39.         // Get the current time in microseconds
  40.         int count = 0;
  41.  
  42.         // Wait for 4 seconds (4,000,000 microseconds)
  43.         while (count < 4000000) {
  44.             button_pressed = (REG_READ(RTC_GPIO_IN_REG) >> BLE_BUTTON) & 0x1;
  45.             count++;
  46.             if (button_pressed == 1) {
  47.                 ESP_RTC_LOGI("Button held for 4 seconds, waking up");
  48.                 return;
  49.             }
  50.         }
  51.     }
  52.     ESP_RTC_LOGI("wake stub: going to deep sleep");
  53.  
  54.     // Set stub entry, then going to deep sleep again.
  55.     esp_wake_stub_sleep(&wake_stub);
  56. }
  57.  
  58. void example_deep_sleep_register_ext0_wakeup(void) {
  59.     printf("Enabling EXT0 wakeup on pin GPIO%d\n", BLE_BUTTON);
  60.     esp_sleep_enable_ext0_wakeup(BLE_BUTTON, 0);  // Wake on button press (low level)
  61.    
  62.     // Initialize and configure RTC GPIO for BLE_BUTTON
  63.     rtc_gpio_init(BLE_BUTTON);
  64.     rtc_gpio_set_direction(BLE_BUTTON, RTC_GPIO_MODE_INPUT_ONLY);
  65.     rtc_gpio_pullup_en(BLE_BUTTON);  // Enable pull-up resistor
  66.     rtc_gpio_pulldown_dis(BLE_BUTTON);  // Disable pull-down resistor
  67.     rtc_gpio_hold_en(BLE_BUTTON);  // Hold the GPIO configuration in deep sleep
  68. }
  69.  
  70. void app_main(void) {
  71.     if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
  72.         printf("Wake up from deep sleep\n");
  73.     } else {
  74.         printf("Not a deep sleep wakeup\n");
  75.     }
  76.    
  77.     // Register EXT0 GPIO as a wakeup source
  78.     example_deep_sleep_register_ext0_wakeup();
  79.  
  80.     // Register the wake stub
  81.     esp_set_deep_sleep_wake_stub(&wake_stub);
  82.  
  83.     // Enter deep sleep
  84.  
  85.     printf("Entering deep sleep\n");
  86.     printf("Entering deep sleep\n");
  87.     printf("Entering deep sleep\n");
  88.     printf("Entering deep sleep\n");
  89.     printf("Entering deep sleep\n");
  90.     printf("Entering deep sleep\n");
  91.     printf("Entering deep sleep\n");
  92.     printf("Entering deep sleep\n");
  93.     printf("Entering deep sleep\n");
  94.     printf("Entering deep sleep\n");
  95.  
  96.     esp_deep_sleep_start();
  97. }

This is output:
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3818,len:0x1758
load:0x403c9700,len:0x4
load:0x403c9704,len:0xc00
load:0x403cc700,len:0x2e0c
entry 0x403c9908
I (27) boot: ESP-IDF v5.1.4-dirty 2nd stage bootloader
I (27) boot: compile time Sep 11 2024 10:23:34
I (27) boot: Multicore bootloader
I (30) boot: chip revision: v0.2
I (34) boot.esp32s3: Boot SPI Speed : 80MHz
I (39) boot.esp32s3: SPI Mode : DIO
I (44) boot.esp32s3: SPI Flash Size : 2MB
I (48) boot: Enabling RNG early entropy source...
I (54) boot: Partition Table:
I (57) boot: ## Label Usage Type ST Offset Length
I (65) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (72) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (80) boot: 2 factory factory app 00 00 00010000 00100000
I (87) boot: End of partition table
I (91) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0a270h ( 41584) map
I (107) esp_image: segment 1: paddr=0001a298 vaddr=3fc92500 size=027b4h ( 10164) load
I (110) esp_image: segment 2: paddr=0001ca54 vaddr=40374000 size=035c4h ( 13764) load
I (120) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1901ch (102428) map
I (144) esp_image: segment 4: paddr=00039044 vaddr=403775c4 size=0af20h ( 44832) load
I (154) esp_image: segment 5: paddr=00043f6c vaddr=50000000 size=000a8h ( 168) load
I (154) esp_image: segment 6: paddr=0004401c vaddr=600fe000 size=001cch ( 460) load
I (166) boot: Loaded app from partition at offset 0x10000
I (166) boot: Disabling RNG early entropy source...
I (182) cpu_start: Multicore app
I (183) cpu_start: Pro cpu up.
I (183) cpu_start: Starting app cpu, entry point is 0x40375438
0x40375438: call_start_cpu1 at /home/ahmet/esp/v5.1.4/esp-idf/components/esp_system/port/cpu_start.c:159

I (0) cpu_start: App cpu up.
I (201) cpu_start: Pro cpu start user code
I (201) cpu_start: cpu freq: 160000000 Hz
I (201) cpu_start: Application information:
I (204) cpu_start: Project name: wake_stub_buton_test
I (210) cpu_start: App version: 1
I (214) cpu_start: Compile time: Sep 11 2024 10:23:21
I (221) cpu_start: ELF file SHA256: c04de86e4ebc44a7...
I (226) cpu_start: ESP-IDF: v5.1.4-dirty
I (232) cpu_start: Min chip rev: v0.0
I (237) cpu_start: Max chip rev: v0.99
I (241) cpu_start: Chip rev: v0.2
I (246) heap_init: Initializing. RAM available for dynamic allocation:
I (253) heap_init: At 3FC95540 len 000541D0 (336 KiB): DRAM
I (260) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (266) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (272) heap_init: At 600FE1CC len 00001E1C (7 KiB): RTCRAM
I (280) spi_flash: detected chip: winbond
I (283) spi_flash: flash io: dio
W (287) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (301) sleep: Configure to isolate all GPIO pins in sleep state
I (307) sleep: Enable automatic switching of GPIO sleep configuration
I (315) app_start: Starting scheduler on CPU0
I (319) app_start: Starting scheduler on CPU1
I (319) main_task: Started on CPU0
I (329) main_task: Calling app_main()
Not a deep sleep wakeup
Enabling EXT0 wakeup on pin GPIO5
Entering deep sleep
Entering deep sleep
Entering deep sleep
Entering deep sleep
Entering deep sleep
Entering deep sleep
Entering deep sleep
Entering deep sleep
Entering deep sleep
Entering deep sleep
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT)
pro cpu reset by JTAG
wake stub function called
button pressed: 0
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x7 (TG0WDT_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x600fe0cf
0x600fe0cf: wake_stub at /home/ahmet/esp_projects/wake_stub_buton_test/main/main.c:44

aliarifat794
Posts: 128
Joined: Sun Jun 23, 2024 6:18 pm

Re: Using Same GPIO for Deep Sleep Wake-up (EXT0) and State Check in Wake Stub on ESP32-S3

Postby aliarifat794 » Wed Sep 11, 2024 3:35 pm

Wake stubs are executed very early during the wake-up process, and their execution time is limited. The "watchdog timer" reset (TG0WDT_SYS_RST) is likely triggered because your code in the wake_stub function takes too long. You can edit your code like this:

Code: Select all

#include <stdio.h>
#include "esp_sleep.h"
#include "esp_attr.h"
#include "driver/rtc_io.h"
#include "esp_wake_stub.h"
#include "esp_system.h"

#define BLE_BUTTON GPIO_NUM_5

static size_t RTC_DATA_ATTR s_wake_count = 0;

// Minimal wake stub function
void RTC_IRAM_ATTR wake_stub(void) {
    uint32_t gpio_val;
    
    // Read initial button state
    gpio_val = REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S;
    int button_pressed = (gpio_val >> BLE_BUTTON) & 0x1;

    // Wake up if the button is pressed
    if (button_pressed == 0) {
        // Just wake up, no long loop in the stub
        esp_default_wake_deep_sleep();
    }

    // If not pressed, go back to deep sleep
    esp_wake_stub_sleep(&wake_stub);
}

// Function to handle EXT0 wake-up registration
void example_deep_sleep_register_ext0_wakeup(void) {
    printf("Enabling EXT0 wakeup on pin GPIO%d\n", BLE_BUTTON);
    esp_sleep_enable_ext0_wakeup(BLE_BUTTON, 0);  // Wake on button press (low level)

    // Initialize and configure RTC GPIO for BLE_BUTTON
    rtc_gpio_init(BLE_BUTTON);
    rtc_gpio_set_direction(BLE_BUTTON, RTC_GPIO_MODE_INPUT_ONLY);
    rtc_gpio_pullup_en(BLE_BUTTON);  // Enable pull-up resistor
    rtc_gpio_pulldown_dis(BLE_BUTTON);  // Disable pull-down resistor
    rtc_gpio_hold_en(BLE_BUTTON);  // Hold the GPIO configuration in deep sleep
}

void app_main(void) {
    if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
        printf("Wake up from deep sleep\n");

        // Check if button is still pressed after wake-up
        int button_pressed = gpio_get_level(BLE_BUTTON);
        if (button_pressed == 0) {
            printf("Button is pressed, waiting for 4 seconds hold...\n");

            // Here you can implement the 4-second button hold detection
            vTaskDelay(pdMS_TO_TICKS(4000));
            
            if (gpio_get_level(BLE_BUTTON) == 0) {
                printf("Button held for 4 seconds, performing action...\n");
                // Perform the desired action for long press
            }
        }
    } else {
        printf("Not a deep sleep wakeup\n");
    }

    // Register EXT0 GPIO as a wakeup source
    example_deep_sleep_register_ext0_wakeup();

    // Register the wake stub
    esp_set_deep_sleep_wake_stub(&wake_stub);

    // Enter deep sleep
    printf("Entering deep sleep\n");
    esp_deep_sleep_start();
}

Ahmetsafi
Posts: 10
Joined: Wed Aug 07, 2024 12:01 pm

Re: Using Same GPIO for Deep Sleep Wake-up (EXT0) and State Check in Wake Stub on ESP32-S3

Postby Ahmetsafi » Thu Sep 12, 2024 6:22 am

aliarifat794 wrote:
Wed Sep 11, 2024 3:35 pm
Wake stubs are executed very early during the wake-up process, and their execution time is limited. The "watchdog timer" reset (TG0WDT_SYS_RST) is likely triggered because your code in the wake_stub function takes too long. You can edit your code like this:

Code: Select all

#include <stdio.h>
#include "esp_sleep.h"
#include "esp_attr.h"
#include "driver/rtc_io.h"
#include "esp_wake_stub.h"
#include "esp_system.h"

#define BLE_BUTTON GPIO_NUM_5

static size_t RTC_DATA_ATTR s_wake_count = 0;

// Minimal wake stub function
void RTC_IRAM_ATTR wake_stub(void) {
    uint32_t gpio_val;
    
    // Read initial button state
    gpio_val = REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S;
    int button_pressed = (gpio_val >> BLE_BUTTON) & 0x1;

    // Wake up if the button is pressed
    if (button_pressed == 0) {
        // Just wake up, no long loop in the stub
        esp_default_wake_deep_sleep();
    }

    // If not pressed, go back to deep sleep
    esp_wake_stub_sleep(&wake_stub);
}

// Function to handle EXT0 wake-up registration
void example_deep_sleep_register_ext0_wakeup(void) {
    printf("Enabling EXT0 wakeup on pin GPIO%d\n", BLE_BUTTON);
    esp_sleep_enable_ext0_wakeup(BLE_BUTTON, 0);  // Wake on button press (low level)

    // Initialize and configure RTC GPIO for BLE_BUTTON
    rtc_gpio_init(BLE_BUTTON);
    rtc_gpio_set_direction(BLE_BUTTON, RTC_GPIO_MODE_INPUT_ONLY);
    rtc_gpio_pullup_en(BLE_BUTTON);  // Enable pull-up resistor
    rtc_gpio_pulldown_dis(BLE_BUTTON);  // Disable pull-down resistor
    rtc_gpio_hold_en(BLE_BUTTON);  // Hold the GPIO configuration in deep sleep
}

void app_main(void) {
    if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
        printf("Wake up from deep sleep\n");

        // Check if button is still pressed after wake-up
        int button_pressed = gpio_get_level(BLE_BUTTON);
        if (button_pressed == 0) {
            printf("Button is pressed, waiting for 4 seconds hold...\n");

            // Here you can implement the 4-second button hold detection
            vTaskDelay(pdMS_TO_TICKS(4000));
            
            if (gpio_get_level(BLE_BUTTON) == 0) {
                printf("Button held for 4 seconds, performing action...\n");
                // Perform the desired action for long press
            }
        }
    } else {
        printf("Not a deep sleep wakeup\n");
    }

    // Register EXT0 GPIO as a wakeup source
    example_deep_sleep_register_ext0_wakeup();

    // Register the wake stub
    esp_set_deep_sleep_wake_stub(&wake_stub);

    // Enter deep sleep
    printf("Entering deep sleep\n");
    esp_deep_sleep_start();
}
Thank you for your reply. I was trying decide activate BLE in wake stub. i guess i can not do this in wake stub module must wake up for check state of button for 4 seconds.

Who is online

Users browsing this forum: No registered users and 110 guests