atomic14 / esp32-s3-pinouts

ESP32-S3 Pinout Quick Guide
Creative Commons Attribution Share Alike 4.0 International
176 stars 15 forks source link

Next level... How about starting a list of registers that are different on the ESP32-S3 vs ESP32 #3

Open peteDDD opened 7 months ago

peteDDD commented 7 months ago

I have been in the throes of converting an application from ESP32 to ESP32-S3 boards. This app uses a lot of direct register commands particularly in the wake_stub. It has been stumble and research, over and over, to figure out the differences in the registers between the processors. Have you found any reference which covers these differences? If not, perhaps we could start a community-sourced reference for this. I'll start with a few contributions here.

Flushing UART

// Wait for UART to end transmitting.
#define uS_PER_CHARACTER 95 // 95uS per character at 115200 baud

    // the following line works with ESP32 but not ESP32-S3
    // while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT))

    // the following line works for ESP32-S3
    while (REG_GET_FIELD(UART_FSM_STATUS_REG(0), UART_ST_UTX_OUT))
    {
      REG_WRITE(TIMG_WDTFEED_REG(0), 1); // feed the watchdog
      ets_delay_us(uS_PER_CHARACTER); // 95 uS per character at 115200 baud
    }

Including the right rom/rtc.h

I found that working in Visual Studio Code with Platformio that the wrong rom/rtc.h was being used for the ESP32-S3 (it was using the C version). Here is a fix for that.

#ifdef CONFIG_IDF_TARGET_ESP32 // https://github.com/espressif/esp-idf/blob/master/components/esp_hw_support/sleep_wake_stub.c#L92
#include "esp32/rom/rtc.h"     // needed for rtc_get_reset_reason, DEEPSLEEP_RESET, RTC_ENTRY_ADDR_REG
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C6
#include "esp32c6/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#endif
cgreening commented 7 months ago

It doesn't seem to be called out in the datasheets - maybe there's something somewhere in the espressif docs?

This would be a great bit of information to add. Shall we create a new page for it?

peteDDD commented 7 months ago

I searched and so far have not found a reference. (I find the S3 technical reference very unfulfilling in terms of useful suggestions... but very filling in terms of volume).

Such a reference would be useful and I think community sourcing it might be the way to build it quickly and more completely.

peteDDD commented 7 months ago

Getting wake cause while in wake stub


#include "esp_sleep.h"
#include "rom/rtc.h" 

RTC_IRAM_ATTR esp_sleep_wakeup_cause_t stub_esp_sleep_get_wakeup_cause()
{
    // ESP32
    // uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE);

    // ESP-32-S3
    uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_SLP_WAKEUP_CAUSE_REG, RTC_CNTL_WAKEUP_CAUSE);
    if (wakeup_cause & RTC_EXT0_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_EXT0;
    }
    else if (wakeup_cause & RTC_EXT1_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_EXT1;
    }
    else if (wakeup_cause & RTC_TIMER_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_TIMER;
    }
    else if (wakeup_cause & RTC_TOUCH_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_TOUCHPAD;
    }
    else if (wakeup_cause & RTC_ULP_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_ULP;
    }
    else
    {
        return ESP_SLEEP_WAKEUP_UNDEFINED;
    }
}
peteDDD commented 7 months ago

Here is one I can't (yet... after two days of trying) figure out. This is a program that wakes from EXT0 low into at wake stub and counts the number of times that happens. If higher than a threshold, it wakes all the way up. If not, it goes back to sleep from within the wake stub. What I am seeing is that the EXT0 wake, after the going to sleep from the wake stub does not wake into the wake stub. This leads me to believe that the problem is with this line:

        // Set the pointer of the wake stub function.
        REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)&wake_stub);  

So what the program demonstrates is waking correcting into the wake stub when it goes to sleep from the setup() and not waking into the wake_stub when it goes to sleep from the wake stub.

Any insights?

Here is the whole program:

#include <Arduino.h>

#include <stdio.h>
#include <string.h>
#include "esp_sleep.h"
// #include "esp_attr.h"
#include "rom/rtc.h" // needed for rtc_get_reset_reason, DEEPSLEEP_RESET, RTC_ENTRY_ADDR_REG
// #include "esp32/rom/rtc.h"
// #include "esp32/rom/gpio.h"
// #include "soc\rtc_io_reg.h"
// #include "soc/rtc_periph.h"
#include "driver\rtc_io.h" // needed for rtc_gpio_pullup_en
// #include "soc/rtc_cntl_reg.h"
// #include "soc/timer_group_reg.h"
// #include "rom/ets_sys.h"

// #include "esp32/rom/ets_sys.h"
// #include "soc/gpio_periph.h"
// #include "soc/sens_reg.h"
// #include "soc/sens_struct.h"
// #include "driver/adc.h"
// #include "soc/uart_reg.h"
// #include "esp_system.h"
#include "soc/rtc.h" // needed for RTC_EXT0_TRIG_EN, RTC_EXT1_TRIG_EN, RTC_TIMER_TRIG_EN, RTC_TOUCH_TRIG_EN, RTC_ULP_TRIG_EN

// #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"        // needed for UART_STATUS_REG
#include "soc/timer_group_reg.h" // needed for TIMG_WDTFEED_REG

#define wakeup_time_sec 60
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define RAIN_COUNT_PULSE_DEBOUNCE_US 5
#define uS_PER_CHARACTER 95 // 95 uSec per character at 115200 baud

#define EXT0_PULSE_TO_WAKEUP 4

// Pin used for pulse counting
#define PULSE_CNT_GPIO_NUM 0
#define PULSE_CNT_GPIO_NAME GPIO_NUM_0
#define PULSE_CNT_RTC_GPIO_NUM 0

#define PULSE_CNT_IS_LOW() \
    ((REG_GET_FIELD(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT) & BIT(PULSE_CNT_RTC_GPIO_NUM)) == 0)

// Pulse counter value, stored in RTC_SLOW_MEM
static size_t RTC_DATA_ATTR rain_count;
static size_t RTC_DATA_ATTR s_max_pulse_count;

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

// void app_main(void)
void setup(void)
{
    if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET)
    {
        printf("SETUP: Wake up from deep sleep\n");
        printf("rain_count=%d\n", rain_count);
    }
    else
    {
        printf("SETUP: Not a deep sleep wake up\n");
    }
    s_max_pulse_count = EXT0_PULSE_TO_WAKEUP;
    printf("SETUP: Going to deep sleep in 1 second\n");
    printf("SETUP: Will wake up after %d pulses\n", s_max_pulse_count);
    printf("  or %d seconds\n\n\n", wakeup_time_sec);
    vTaskDelay(1000 / portTICK_PERIOD_MS);

    rtc_gpio_init(PULSE_CNT_GPIO_NAME);
    // rtc_gpio_set_direction(RAIN_CNT_GPIO_NUM, RTC_GPIO_MODE_INPUT_ONLY);
    rtc_gpio_set_direction_in_sleep(PULSE_CNT_GPIO_NAME, RTC_GPIO_MODE_INPUT_ONLY);
    rtc_gpio_pulldown_dis(PULSE_CNT_GPIO_NAME);
    rtc_gpio_pullup_en(PULSE_CNT_GPIO_NAME);

    // Wake up on low logic level
    esp_sleep_enable_ext0_wakeup(PULSE_CNT_GPIO_NAME, 0); // 1 = High, 0 = Low

    // add timer wake
    esp_sleep_enable_timer_wakeup(wakeup_time_sec * uS_TO_S_FACTOR);

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

    // Enter deep sleep
    esp_deep_sleep_start();
}

// https://github.com/espressif/esp-idf/blob/a20d02b7f196c407bc9f39b781e31a0a4f665968/components/esp32/sleep_modes.c
RTC_IRAM_ATTR esp_sleep_wakeup_cause_t stub_esp_sleep_get_wakeup_cause()
{
    // ESP32
    // uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE);

    // ESP-32-S3
    uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_SLP_WAKEUP_CAUSE_REG, RTC_CNTL_WAKEUP_CAUSE);
    if (wakeup_cause & RTC_EXT0_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_EXT0;
    }
    else if (wakeup_cause & RTC_EXT1_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_EXT1;
    }
    else if (wakeup_cause & RTC_TIMER_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_TIMER;
    }
    else if (wakeup_cause & RTC_TOUCH_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_TOUCHPAD;
    }
    else if (wakeup_cause & RTC_ULP_TRIG_EN)
    {
        return ESP_SLEEP_WAKEUP_ULP;
    }
    else
    {
        return ESP_SLEEP_WAKEUP_UNDEFINED;
    }
}

//! WAKE STUB
static const char RTC_RODATA_ATTR wake_fmt_str[] = "count=%d\n";
static const char RTC_RODATA_ATTR sleep_fmt_str[] = "sleeping from WAKE STUB\n\n\n";

static const char RTC_RODATA_ATTR wakeup_cause_EXT0_str[] = "WAKE_STUB: Wakeup Cause EXT0\n";
static const char RTC_RODATA_ATTR wakeup_cause_TIMER_str[] = "WAKE_STUB: Wakeup Cause TIMER\n";

static void RTC_IRAM_ATTR wake_stub()
{
    esp_default_wake_deep_sleep();
    // Determine why we woke up
    switch (stub_esp_sleep_get_wakeup_cause())
    {
    // If we woke up from the power button, and we're not critical voltage just boot up
    case ESP_SLEEP_WAKEUP_EXT0:
        ets_printf(wakeup_cause_EXT0_str);

        // Increment the pulse counter
        rain_count++;
        // and print the pulse counter value:
        ets_printf(wake_fmt_str, rain_count);

        // Wait for pin level to be high.
        // If we go to sleep when the pin is still low, the chip
        // will wake up again immediately. Hardware doesn't have
        // edge trigger support for deep sleep wakeup.
        do
        {
            // while (PULSE_CNT_IS_LOW())
            while (GPIO_INPUT_GET(PULSE_CNT_GPIO_NUM) == 0)
            {
                // feed the watchdog
                REG_WRITE(TIMG_WDTFEED_REG(0), 1);
            }
            // debounce
            ets_delay_us(RAIN_COUNT_PULSE_DEBOUNCE_US);
        } while (PULSE_CNT_IS_LOW());

        if (rain_count >= s_max_pulse_count)
        {
            // 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;
        }
        // Pulse count is <s_max_pulse_count, go back to sleep
        // and wait for more pulses.

        // Print status
        ets_printf(sleep_fmt_str);
        // Wait for UART to end transmitting.
        while (REG_GET_FIELD(UART_FSM_STATUS_REG(0), UART_ST_UTX_OUT))
        {
            // feed the watchdog
            REG_WRITE(TIMG_WDTFEED_REG(0), 1);
            ets_delay_us(uS_PER_CHARACTER); // 95 uS per character at 115200 baud
        }

        //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
        //&& THE FOLLOWING LINE DOES NOT SEEM TO WORK WITH THE ESP32-S3
        // Set the pointer of the wake stub function.
        REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)&wake_stub);  
        //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

        // Go to sleep.
        CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
        SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
        // A few CPU cycles may be necessary for the sleep to start...
        while (true)
        {
            ;
        }
        // never reaches here.
        break; // case ESP_SLEEP_WAKEUP_EXT0:

    case ESP_SLEEP_WAKEUP_TIMER:
        ets_printf(wakeup_cause_TIMER_str);
        // 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;

        break; // case ESP_SLEEP_WAKEUP_TIMER:
    }
}

void loop(void)
{
}
peteDDD commented 7 months ago

I have also posted a request for help regarding setting wake stub from within a wake stub on th eESP32-S3 here https://esp32.com/viewtopic.php?f=2&t=37002&p=123908#p123908