ESP32S3 - how to read GPIO input from a wake stub

andrewelder
Posts: 3
Joined: Fri Apr 01, 2022 9:40 pm

ESP32S3 - how to read GPIO input from a wake stub

Postby andrewelder » Fri Apr 01, 2022 9:48 pm

I'm testing on a ESP32S3-DevKitM-1. I can make GPIO outputs work from within my wake stub, but not GPIO inputs. Complete code is included below. What an I missing?

I have verified that the main application does read the same input GPIOs correctly.
  1. /*
  2.  * This sample illustrates writing and reading GPIO from a wake stub.
  3.  *
  4.  * The desired sequence is to
  5.  * 1) set GPIO_9 high
  6.  * 2) Read GPIO_10 and GPIO_11
  7.  * 3) set GPIO_9 low
  8.  *
  9.  * At this time the GPIO_10 and GPIO_11 read operations are not
  10.  * working correctly from the wake stub, but they do work correctly when
  11.  * the main application performs the same read.
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include "esp_sleep.h"
  17. #include "esp_attr.h"
  18. #include "rom/rtc.h"
  19. #include "rom/ets_sys.h"
  20. #include "freertos/FreeRTOS.h"
  21. #include "freertos/task.h"
  22. #include "soc/rtc_cntl_reg.h"
  23. #include "soc/rtc_io_reg.h"
  24. #include "soc/uart_reg.h"
  25. #include "soc/timer_group_reg.h"
  26. #include "driver/rtc_io.h"
  27.  
  28. // Pulse counter value, stored in RTC_SLOW_MEM
  29. static size_t RTC_DATA_ATTR s_wake_count;
  30. static int RTC_DATA_ATTR s_in10 = 0;
  31. static int RTC_DATA_ATTR s_in11 = 0;
  32.  
  33. // Function which runs after exit from deep sleep
  34. static void RTC_IRAM_ATTR wake_stub();
  35.  
  36. void app_main(void)
  37. {
  38.     int l_in10 = 0;
  39.     int l_in11 = 0;
  40.  
  41.     if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
  42.         printf("Wake up from deep sleep: count = %d\n", s_wake_count);
  43.     } else {
  44.         s_wake_count = 0;
  45.         printf("Not a deep sleep wake up\n");
  46.     }
  47.  
  48.     // check GPIO 10 & 11 from application
  49.     rtc_gpio_init(GPIO_NUM_10);
  50.     rtc_gpio_set_direction(GPIO_NUM_10, RTC_GPIO_MODE_INPUT_ONLY);
  51.     rtc_gpio_pulldown_dis(GPIO_NUM_10);
  52.     rtc_gpio_pullup_dis(GPIO_NUM_10);
  53.     rtc_gpio_hold_en(GPIO_NUM_10);
  54.  
  55.     rtc_gpio_init(GPIO_NUM_11);
  56.     rtc_gpio_set_direction(GPIO_NUM_11, RTC_GPIO_MODE_INPUT_ONLY);
  57.     rtc_gpio_pulldown_dis(GPIO_NUM_11);
  58.     rtc_gpio_pullup_dis(GPIO_NUM_11);
  59.     rtc_gpio_hold_en(GPIO_NUM_11);
  60.  
  61.     l_in10 = rtc_gpio_get_level(GPIO_NUM_10);
  62.     l_in11 = rtc_gpio_get_level(GPIO_NUM_11);
  63.  
  64.     printf("Wake stub readings: 10 = %d, 11 = %d\n", s_in10, s_in11);
  65.     printf("App readings:       10 = %d, 11 = %d\n", l_in10, l_in11);
  66.  
  67.     printf("Going to deep sleep in 2 second for 5 seconds\n");
  68.     ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(5 * 1000000));
  69.     vTaskDelay(2000/portTICK_PERIOD_MS);
  70.  
  71.     // Set the wake stub function
  72.     esp_set_deep_sleep_wake_stub(&wake_stub);
  73.  
  74.     // Enter deep sleep
  75.     esp_deep_sleep_start();
  76. }
  77.  
  78. static void RTC_IRAM_ATTR wake_stub()
  79. {
  80.     uint32_t gpio_val;
  81.  
  82.     // Increment the wake counter
  83.     s_wake_count++;
  84.  
  85.     // Output - set RTC mux
  86.     SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_MUX_SEL);
  87.  
  88.     // Output - clear the HOLD bit
  89.     CLEAR_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_9));
  90.  
  91.     // Output - enable GPIO output
  92.     REG_WRITE(RTC_GPIO_ENABLE_W1TS_REG, BIT(RTC_GPIO_ENABLE_W1TS_S + GPIO_NUM_9));
  93.  
  94.     // Ouput - set the GPIO output high
  95.     REG_WRITE(RTC_GPIO_OUT_W1TS_REG, BIT(RTC_GPIO_OUT_DATA_W1TS_S + GPIO_NUM_9));
  96.  
  97.     // Input - set RTC mux
  98.     SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD10_REG, RTC_IO_TOUCH_PAD10_MUX_SEL);
  99.     SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD11_REG, RTC_IO_TOUCH_PAD11_MUX_SEL);
  100.  
  101.     // Input - enable
  102.     SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD10_REG, RTC_IO_TOUCH_PAD10_FUN_IE);
  103.     SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD11_REG, RTC_IO_TOUCH_PAD11_FUN_IE);
  104.  
  105.     // Input - set the hold bit
  106.     SET_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_10));    
  107.     SET_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_11));
  108.  
  109.     // Input - read the GPIO input register
  110.     gpio_val = REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S;
  111.     s_in10 = (gpio_val >> GPIO_NUM_10) & 0x1;
  112.     s_in11 = (gpio_val >> GPIO_NUM_11) & 0x1;
  113.  
  114.     // Ouput - set the GPIO output low again
  115.     REG_WRITE(RTC_GPIO_OUT_W1TC_REG, BIT(RTC_GPIO_OUT_DATA_W1TC_S + GPIO_NUM_9));
  116.  
  117.     // On revision 0 of ESP32, this function must be called:
  118.     esp_default_wake_deep_sleep();
  119.  
  120.     // Return from the wake stub function to continue
  121.     // booting the firmware.
  122.     return;
  123.     // never reaches here.
  124. }
  125.  

iParcelBox
Posts: 31
Joined: Sun Oct 27, 2019 3:12 pm

Re: ESP32S3 - how to read GPIO input from a wake stub

Postby iParcelBox » Sun Apr 10, 2022 8:08 am

I’m trying to do the same using an ESP32-Wrover. I’m not even able to set a GPIO pin gig during the wake stub.

owenjames
Posts: 12
Joined: Fri Sep 02, 2022 6:24 pm

Re: ESP32S3 - how to read GPIO input from a wake stub

Postby owenjames » Fri Sep 02, 2022 6:36 pm

I'm having similar trouble on an esp32-3c evaluation board. I cannot get any IO pins to work (input or output) from the sleep stub. I need to do some 12c comms after being woken by an 12c peripheral. The attached test code should drive the output pin when waking from deep sleep but the oscilloscope shows only the pulse that is generated in main. Any idea what I'm missing?

  1.  
  2. /**
  3.  * Brief:
  4.  * Test RTC deep sleep GPIO operation
  5.  */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include "freertos/task.h"
  11. #include "freertos/queue.h"
  12. #include "driver/gpio.h"
  13. #include "esp_sleep.h"
  14. #include "esp_log.h"
  15. #include "driver/rtc_io.h"
  16.  
  17.  
  18. static const char* TAG = "test";
  19.  
  20. #define GPIO_OUTPUT_IO_0    11
  21. #define GPIO_OUTPUT_PIN_SEL  (1ULL<<GPIO_OUTPUT_IO_0)
  22. #define GPIO_INPUT_IO_0     13
  23. #define GPIO_INPUT_PIN_SEL  (1ULL<<GPIO_INPUT_IO_0)
  24. #define ESP_INTR_FLAG_DEFAULT 0
  25.  
  26. RTC_DATA_ATTR int wake_count;
  27.  
  28. void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
  29.     wake_count = 0;
  30.     esp_default_wake_deep_sleep();
  31.     wake_count++;
  32.     // Output - set RTC mux
  33.     SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD11_REG, RTC_IO_TOUCH_PAD11_MUX_SEL);
  34.     wake_count++;
  35.     REG_SET_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, BIT(GPIO_OUTPUT_IO_0));
  36.     wake_count++;
  37.     REG_SET_FIELD(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC, BIT(GPIO_OUTPUT_IO_0));
  38.     wake_count++;
  39. }
  40.  
  41. void goto_sleep()
  42. {
  43.     // Configure wakeup
  44.     esp_err_t err = esp_sleep_enable_ext1_wakeup((1UL << GPIO_INPUT_IO_0), ESP_EXT1_WAKEUP_ANY_HIGH);
  45.     if (err != ESP_OK) {
  46.         ESP_LOGE(TAG, "esp_sleep_enable_ext1_wakeup err %d", err);
  47.     }
  48.     rtc_gpio_isolate(GPIO_INPUT_IO_0);
  49.  
  50.     // Configure RTC GPIO output
  51.     if (rtc_gpio_is_valid_gpio(GPIO_OUTPUT_IO_0)) {
  52.         esp_err_t err = rtc_gpio_init(GPIO_OUTPUT_IO_0);
  53.         if (err == ESP_OK) {
  54.             err = rtc_gpio_set_direction_in_sleep(GPIO_OUTPUT_IO_0, RTC_GPIO_MODE_OUTPUT_ONLY);
  55.         }
  56.         if (err == ESP_OK) {
  57.             err = rtc_gpio_set_level(GPIO_OUTPUT_IO_0, 0);
  58.         }
  59.         if (err != ESP_OK) {
  60.             ESP_LOGE(TAG, "rtc gpio err %d", err);
  61.         }
  62.     } else {
  63.         ESP_LOGE(TAG, "GPIO pin %d is not a valid RTC pin", GPIO_OUTPUT_IO_0);
  64.     }
  65.  
  66.     // Goodbye!
  67.     esp_deep_sleep_start();
  68. }
  69.  
  70. void app_main(void)
  71. {
  72.     {
  73.     gpio_config_t io_conf = {};
  74.     io_conf.intr_type = GPIO_INTR_DISABLE;
  75.     io_conf.mode = GPIO_MODE_OUTPUT;
  76.     io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
  77.     io_conf.pull_down_en = 0;
  78.     io_conf.pull_up_en = 0;
  79.     gpio_config(&io_conf);
  80.     }
  81.  
  82.     {
  83.     gpio_config_t io_conf = {};
  84.     io_conf.intr_type = GPIO_INTR_DISABLE;
  85.     io_conf.mode = GPIO_MODE_INPUT;
  86.     io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
  87.     io_conf.pull_down_en = 1;
  88.     io_conf.pull_up_en = 0;
  89.     gpio_config(&io_conf);
  90.     }
  91.  
  92.     gpio_set_level(GPIO_OUTPUT_IO_0, 1);
  93.     vTaskDelay(1);
  94.     gpio_set_level(GPIO_OUTPUT_IO_0, 0);
  95.     ESP_LOGI(TAG, "wake_count: %d", wake_count);
  96.  
  97.     vTaskDelay(1000/portTICK_RATE_MS);
  98.     ESP_LOGI(TAG, "Going to sleep");
  99.     goto_sleep();
  100. }

Corrado.bosco
Posts: 2
Joined: Thu Oct 17, 2024 10:19 pm

Re: ESP32S3 - how to read GPIO input from a wake stub

Postby Corrado.bosco » Thu Oct 17, 2024 10:22 pm

I am facing the same problem.
Did you find the solution on how to read a GPIO in the stub?
thanks

Corrado.bosco
Posts: 2
Joined: Thu Oct 17, 2024 10:19 pm

Re: ESP32S3 - how to read GPIO input from a wake stub

Postby Corrado.bosco » Thu Oct 17, 2024 10:43 pm

Found the solution on github
add:
SET_PERI_REG_MASK(SENS_SAR_PERI_CLK_GATE_CONF_REG, SENS_IOMUX_CLK_EN_M);

(you'll also need #include "soc/sens_reg.h" at the top of the file)

Who is online

Users browsing this forum: Majestic-12 [Bot] and 367 guests