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.

Code: wake_test.c Select all


/*
* This sample illustrates writing and reading GPIO from a wake stub.
*
* The desired sequence is to
* 1) set GPIO_9 high
* 2) Read GPIO_10 and GPIO_11
* 3) set GPIO_9 low
*
* At this time the GPIO_10 and GPIO_11 read operations are not
* working correctly from the wake stub, but they do work correctly when
* the main application performs the same read.
*/

#include <stdio.h>
#include <string.h>
#include "esp_sleep.h"
#include "esp_attr.h"
#include "rom/rtc.h"
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/uart_reg.h"
#include "soc/timer_group_reg.h"
#include "driver/rtc_io.h"

// Pulse counter value, stored in RTC_SLOW_MEM
static size_t RTC_DATA_ATTR s_wake_count;
static int RTC_DATA_ATTR s_in10 = 0;
static int RTC_DATA_ATTR s_in11 = 0;

// Function which runs after exit from deep sleep
static void RTC_IRAM_ATTR wake_stub();

void app_main(void)
{
int l_in10 = 0;
int l_in11 = 0;

if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
printf("Wake up from deep sleep: count = %d\n", s_wake_count);
} else {
s_wake_count = 0;
printf("Not a deep sleep wake up\n");
}

// check GPIO 10 & 11 from application
rtc_gpio_init(GPIO_NUM_10);
rtc_gpio_set_direction(GPIO_NUM_10, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_dis(GPIO_NUM_10);
rtc_gpio_pullup_dis(GPIO_NUM_10);
rtc_gpio_hold_en(GPIO_NUM_10);

rtc_gpio_init(GPIO_NUM_11);
rtc_gpio_set_direction(GPIO_NUM_11, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_dis(GPIO_NUM_11);
rtc_gpio_pullup_dis(GPIO_NUM_11);
rtc_gpio_hold_en(GPIO_NUM_11);

l_in10 = rtc_gpio_get_level(GPIO_NUM_10);
l_in11 = rtc_gpio_get_level(GPIO_NUM_11);

printf("Wake stub readings: 10 = %d, 11 = %d\n", s_in10, s_in11);
printf("App readings: 10 = %d, 11 = %d\n", l_in10, l_in11);

printf("Going to deep sleep in 2 second for 5 seconds\n");
ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(5 * 1000000));
vTaskDelay(2000/portTICK_PERIOD_MS);

// Set the wake stub function
esp_set_deep_sleep_wake_stub(&wake_stub);

// Enter deep sleep
esp_deep_sleep_start();
}

static void RTC_IRAM_ATTR wake_stub()
{
uint32_t gpio_val;

// Increment the wake counter
s_wake_count++;

// Output - set RTC mux
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_MUX_SEL);

// Output - clear the HOLD bit
CLEAR_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_9));

// Output - enable GPIO output
REG_WRITE(RTC_GPIO_ENABLE_W1TS_REG, BIT(RTC_GPIO_ENABLE_W1TS_S + GPIO_NUM_9));

// Ouput - set the GPIO output high
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, BIT(RTC_GPIO_OUT_DATA_W1TS_S + GPIO_NUM_9));

// Input - set RTC mux
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD10_REG, RTC_IO_TOUCH_PAD10_MUX_SEL);
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD11_REG, RTC_IO_TOUCH_PAD11_MUX_SEL);

// Input - enable
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD10_REG, RTC_IO_TOUCH_PAD10_FUN_IE);
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD11_REG, RTC_IO_TOUCH_PAD11_FUN_IE);

// Input - set the hold bit
SET_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_10));
SET_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_11));

// Input - read the GPIO input register
gpio_val = REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S;
s_in10 = (gpio_val >> GPIO_NUM_10) & 0x1;
s_in11 = (gpio_val >> GPIO_NUM_11) & 0x1;

// Ouput - set the GPIO output low again
REG_WRITE(RTC_GPIO_OUT_W1TC_REG, BIT(RTC_GPIO_OUT_DATA_W1TC_S + GPIO_NUM_9));

// On revision 0 of ESP32, this function must be called:
esp_default_wake_deep_sleep();

// Return from the wake stub function to continue
// booting the firmware.
return;
// never reaches here.
}

iParcelBox
Posts: 47
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: 20
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?

Code: Untitled.c Select all



/**
* Brief:
* Test RTC deep sleep GPIO operation
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "driver/rtc_io.h"


static const char* TAG = "test";

#define GPIO_OUTPUT_IO_0 11
#define GPIO_OUTPUT_PIN_SEL (1ULL<<GPIO_OUTPUT_IO_0)
#define GPIO_INPUT_IO_0 13
#define GPIO_INPUT_PIN_SEL (1ULL<<GPIO_INPUT_IO_0)
#define ESP_INTR_FLAG_DEFAULT 0

RTC_DATA_ATTR int wake_count;

void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
wake_count = 0;
esp_default_wake_deep_sleep();
wake_count++;
// Output - set RTC mux
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD11_REG, RTC_IO_TOUCH_PAD11_MUX_SEL);
wake_count++;
REG_SET_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, BIT(GPIO_OUTPUT_IO_0));
wake_count++;
REG_SET_FIELD(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC, BIT(GPIO_OUTPUT_IO_0));
wake_count++;
}

void goto_sleep()
{
// Configure wakeup
esp_err_t err = esp_sleep_enable_ext1_wakeup((1UL << GPIO_INPUT_IO_0), ESP_EXT1_WAKEUP_ANY_HIGH);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_sleep_enable_ext1_wakeup err %d", err);
}
rtc_gpio_isolate(GPIO_INPUT_IO_0);

// Configure RTC GPIO output
if (rtc_gpio_is_valid_gpio(GPIO_OUTPUT_IO_0)) {
esp_err_t err = rtc_gpio_init(GPIO_OUTPUT_IO_0);
if (err == ESP_OK) {
err = rtc_gpio_set_direction_in_sleep(GPIO_OUTPUT_IO_0, RTC_GPIO_MODE_OUTPUT_ONLY);
}
if (err == ESP_OK) {
err = rtc_gpio_set_level(GPIO_OUTPUT_IO_0, 0);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "rtc gpio err %d", err);
}
} else {
ESP_LOGE(TAG, "GPIO pin %d is not a valid RTC pin", GPIO_OUTPUT_IO_0);
}

// Goodbye!
esp_deep_sleep_start();
}

void app_main(void)
{
{
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
}

{
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
io_conf.pull_down_en = 1;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
}

gpio_set_level(GPIO_OUTPUT_IO_0, 1);
vTaskDelay(1);
gpio_set_level(GPIO_OUTPUT_IO_0, 0);
ESP_LOGI(TAG, "wake_count: %d", wake_count);

vTaskDelay(1000/portTICK_RATE_MS);
ESP_LOGI(TAG, "Going to sleep");
goto_sleep();
}

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: Qwantbot and 2 guests