Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32S3 - wake stub GPIO needed (IDFGH-7112) #8720

Closed
andrew-elder opened this issue Apr 4, 2022 · 8 comments
Closed

ESP32S3 - wake stub GPIO needed (IDFGH-7112) #8720

andrew-elder opened this issue Apr 4, 2022 · 8 comments
Labels
Resolution: Won't Do This will not be worked on Status: Cancelled Type: Feature Request Feature request for IDF

Comments

@andrew-elder
Copy link

I can't figure out how to read RTC GPIOs from a wake stub an example for ESP32S3 and perhaps other platforms would be helpful.

I have coded the below module for testing purposes and I am unable to get the GPIO read to work from the wake stub.

/*
 * 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.
}

@andrew-elder andrew-elder added the Type: Feature Request Feature request for IDF label Apr 4, 2022
@espressif-bot espressif-bot added the Status: Opened Issue is new label Apr 4, 2022
@github-actions github-actions bot changed the title ESP32S3 - wake stub GPIO needed ESP32S3 - wake stub GPIO needed (IDFGH-7112) Apr 4, 2022
@andrew-elder
Copy link
Author

@igrr - how do I get someone to take a look at this issue?

@ginkgm
Copy link
Collaborator

ginkgm commented Apr 18, 2022

Hi @andrew-elder ,
Have you used logic analyzer to check how the IO works? I'm not 100% sure, but I guess: in your code, because the HOLD of GPIO 10 and 11 is not released, so they will keep the input value hold at the moment HOLD bit is set in the stub (before GPIO9 is set to low) after wakeup and read in the app.

So I suggest:

  1. use logic analyzer to check what's the actually voltage on GPIO 10 and 11, to find out it's the problem of output or input;
  2. try to run without HOLD GPIO 10 and 11. I think it's reasonable to use hold to keep the output after the reset, but for input, there's no reason why we can't read it when we need.

@andrew-elder
Copy link
Author

Hi @ginkgm,
Thank you for taking the time to get back to me.

  1. I don't need to hook up a logic analyzer because inside app_main() I have these lines
    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);

and the App readings show the expected input values. I also have the inputs tied to +3.3 and GND, so it's not that complicated. I see output that looks like:

Wake stub readings: 10 = 0, 11 = 0
App readings:       10 = 0, 11 = 1
  1. I tried without the HOLD on the input. No observable difference. My code change @ line 105 looked like
    // Input - clear the hold bit
    CLEAR_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_10));    
    CLEAR_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, BIT(GPIO_NUM_11));

This is very easy to reproduce with an ESP32-S3-DevKitM-1. Just duplicate the generic-gpio example and replace the gpio_example_main.c code with the code at the top of this issue. Then just jumper GPIO 10 and 11 to different logic levels. Don't forget to connect to the USB serial port UART for actual testing otherwise wake from sleep will not work correctly. idf.py monitor causes a second reset and the wake reason gets over written.

@andrew-elder
Copy link
Author

@ginkgm - any updates/suggestions?

@andrew-elder
Copy link
Author

@ginkgm - it's been a week. Have you been able to duplicate what I reported with the code and steps I have pasted here? CC - @igrr

@igrr
Copy link
Member

igrr commented May 2, 2022

@andrew-elder could you please try adding the following line to your wake stub?

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)

@andrew-elder
Copy link
Author

Thanks a lot @igrr. The addition of

SET_PERI_REG_MASK(SENS_SAR_PERI_CLK_GATE_CONF_REG, SENS_IOMUX_CLK_EN_M);

fixed the issue. I'm going to go ahead and close this one now.

@espressif-bot espressif-bot added Status: In Progress Work is in progress Resolution: Won't Do This will not be worked on Status: Cancelled and removed Status: Opened Issue is new Status: In Progress Work is in progress labels May 5, 2022
@wnienhaus
Copy link

@igrr For me, setting SENS_IOMUX_CLK_EN_M works correctly when done from the main CPU.

However when I try to set it from code running on the ULP-FSM (in normal, not deepsleep mode) it has no effect, i.e. the bit does not get set in the SENS_SAR_PERI_CLK_GATE_CONF_REG register.

Is there something "by design", which is blocking the SENS_SAR_PERI_CLK_GATE_CONF_REG register from being written to by the ULP? Or is there something I am missing? Perhaps some register permission that can be changed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Won't Do This will not be worked on Status: Cancelled Type: Feature Request Feature request for IDF
Projects
None yet
Development

No branches or pull requests

5 participants