espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.28k stars 7.35k forks source link

External wake up ext1 problem #9809

Closed CobaProgram closed 2 months ago

CobaProgram commented 3 months ago

Board

ESP32 Dev Module and Doit ESP32 devkit v1

Device Description

Devkit v1

Hardware Configuration

GPIO 34, 36 and 39 connect to push button active high (pulldown resistor 10k)

Version

v3.0.0

IDE Name

Arduino IDE

Operating System

Windows 10

Flash frequency

80 MHz

PSRAM enabled

no

Upload speed

921600

Description

This code does not work after update to version 3.0.0 and always awake

Sketch

/*
Deep Sleep with External Wake Up
=====================================
This code displays how to use deep sleep with
an external trigger as a wake up source and how
to store data in RTC memory to use it over reboots

This code is under Public Domain License.

Hardware Connections
======================
Push Button to GPIO 33 pulled down with a 10K Ohm
resistor

NOTE:
======
Only RTC IO can be used as a source for external wake
source. They are pins: 0,2,4,12-15,25-27,32-39.

Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/
#define BUTTON_PIN_BITMASK 0x400000000  // 2^34 in hex //0x9400000000

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch (wakeup_reason) {
    case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break;
    default: Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);  //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up for an external trigger.
  There are two types for ESP32, ext0 and ext1 .
  ext0 uses RTC_IO to wakeup thus requires RTC peripherals
  to be on while ext1 uses RTC Controller so does not need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  //esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 1);  //1 = High, 0 = Low

  //If you were to use ext1, you would use it like
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK, ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  Serial.println("Going to sleep now");

  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop() {
  //This is not going to be called
}

Debug Message

nothing error but always awake after sleep mode active

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

CobaProgram commented 3 months ago

I found the command ESP_EXT1_WAKEUP_ALL_LOW is the same as ESP_EXT1_WAKEUP_ANY_HIGH in 3.0.0 version

so that's the cause of the problem in 3.0.0 and 3.0.1 but in version 2.x.x there is no problem

Pr77Pr77 commented 2 months ago

I have the same problem. It seems like @CobaProgram is right. ESP_EXT1_WAKEUP_ANY_HIGH behaves like ESP_EXT1_WAKEUP_ALL_LOW should. But how can I get it to wake up on a high pin? I haven't tried to replace ESP_EXT1_WAKEUP_ANY_HIGH with ESP_EXT1_WAKEUP_ALL_LOW, because the behaviours could be exchanged. Does anyone have an idea?

bfeldman-threadb commented 2 months ago

I'm having the same issue on an ESP32-S2. The code for waking up on high pins worked in Core 2.0.x but triggers immediately on Core 3.0.1 when the pins are low.

I looked through the code for both cores (ESP-IDF versions 4.4 and 5.1) and tried manually setting the following registers to no avail:

REG_WRITE(RTC_CNTL_PAD_HOLD_REG,0x4000); REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, 0x4000); SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,1, RTC_CNTL_EXT_WAKEUP1_LV_S); REG_WRITE(IO_MUX_GPIO14_REG, 0b0001101000000000);

Setting those registers alone had no effect. If I put this line before them:

esp_sleep_enable_ext1_wakeup(0x4000, ESP_EXT1_WAKEUP_ANY_HIGH);

The processor would wake up immediately when pin 14 was low. Wakeup reason is shows as EXT1, pin 14.

I did a comparison of all RTC_CNTL registers (and a few others) between Core 2.0.6 and Core 3.0.1 and didn't find any significant differences that I believe would explain the problem. Not sure whether this is fixable with modifying registers alone or the ESP-IDF code needs to be modified.

VojtechBartoska commented 2 months ago

@SuGlider Can you please help with triage of this issue? Thanks a lot

SuGlider commented 2 months ago

This issue seems to be related to a change in IDF code. Not directly Arduino related. The example from IDF Github is now a bit different for EXT1 Wakeup from deepsleep.

IDF 4: esp-idf/examples/system/deep_sleep/main/deep_sleep_example_main.c at release/v4.4 · espressif/esp-idf (github.com)

This is how it was and how the issue describes it:

    const int ext_wakeup_pin_1 = 2;
    const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;
    const int ext_wakeup_pin_2 = 4;
    const uint64_t ext_wakeup_pin_2_mask = 1ULL << ext_wakeup_pin_2;

    printf("Enabling EXT1 wakeup on pins GPIO%d, GPIO%d\n", ext_wakeup_pin_1, ext_wakeup_pin_2);
    ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask | ext_wakeup_pin_2_mask, ESP_EXT1_WAKEUP_ANY_HIGH));

IDF 5.1: esp-idf/examples/system/deep_sleep/main/deep_sleep_example_main.c at release/v5.1 · espressif/esp-idf (github.com)

This is the way how IDF 5.x does it:

    const int ext_wakeup_pin_1 = CONFIG_EXAMPLE_EXT1_WAKEUP_PIN_1;
    const int ext_wakeup_pin_2 = CONFIG_EXAMPLE_EXT1_WAKEUP_PIN_2;
    const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;
    const uint64_t ext_wakeup_pin_2_mask = 1ULL << ext_wakeup_pin_2;
    printf("Enabling EXT1 wakeup on pins GPIO%d, GPIO%d\n", ext_wakeup_pin_1, ext_wakeup_pin_2);

#if SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
    ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(ext_wakeup_pin_1_mask, CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_1));
    ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(ext_wakeup_pin_2_mask, CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_2));
#else
    ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(ext_wakeup_pin_1_mask | ext_wakeup_pin_2_mask, CONFIG_EXAMPLE_EXT1_WAKEUP_MODE));
#endif

The IDF Calls are different. IDF 4.x uses esp_sleep_enable_ext1_wakeup(MASK, MODE); + necessary disabling PULL_UP/DOWN. IDF 5.x uses esp_sleep_enable_ext1_wakeup_io(MASK, MODE); + necessary disabling PULL_UP/DOWN.

My suggestion is about reading the manual and checking those examples. https://docs.espressif.com/projects/esp-idf/en/v5.1/esp32/api-reference/system/sleep_modes.html#external-wakeup-ext1

SuGlider commented 2 months ago

The solution for this issue is:

  esp_sleep_enable_ext1_wakeup_io(BUTTON_PIN_BITMASK(WAKEUP_GPIO), ESP_EXT1_WAKEUP_ANY_HIGH);
  /*
    If there are no external pull-up/downs, tie wakeup pins to inactive level with internal pull-up/downs via RTC IO
         during deepsleep. However, RTC IO relies on the RTC_PERIPH power domain. Keeping this power domain on will
         increase some power comsumption. However, if we turn off the RTC_PERIPH domain or if certain chips lack the RTC_PERIPH
         domain, we will use the HOLD feature to maintain the pull-up and pull-down on the pins during sleep.
  */
  rtc_gpio_pulldown_en(WAKEUP_GPIO);  // GPIO33 is tie to GND in order to wake up in HIGH
  rtc_gpio_pullup_dis(WAKEUP_GPIO);   // Disable PULL_UP in order to allow it to wakeup on HIGH

The example from Arduino has been fixed as well. Please check the cnahges in #9904

SuGlider commented 2 months ago

@CobaProgram - No pull down resistor is necessary because it is done internally to the chip using rtc_gpio_pulldown_en(GPIO_NUM);

SuGlider commented 2 months ago

Note: it is necessary to include a new file in order to use rtc_gpio_pulldown_en() etc.

#include "driver/rtc_io.h"