The Short Answer: Which Sleep Mode Needs gpio_wakeup_enable?

If you are searching for gpio_wakeup_enable arduino, you are likely working with the ESP32 and trying to wake it from a low-power state using a physical button or sensor. Here is the direct answer: gpio_wakeup_enable() is strictly an ESP-IDF function used to configure wakeup sources for Light Sleep. It is not used for Deep Sleep, and it does not exist on standard AVR Arduino boards (like the Uno or Nano), which rely on hardware interrupts and LowPower libraries instead.

If your goal is Deep Sleep (where RAM is lost and current drops to ~10µA), you must use esp_sleep_enable_ext0_wakeup() instead. If your goal is Light Sleep (where RAM is retained, CPUs are paused, and current sits around 0.8mA), gpio_wakeup_enable() is the correct API. This guide targets the ESP32-WROOM-32 DevKit V1 running the Arduino ESP32 Core (v2.0.x or v3.0.x), mapping out the exact hardware and software requirements to make light sleep wakeup function reliably.

Parts List & Pin Mapping for ESP32 Light Sleep

Not all GPIOs on the ESP32 are created equal when it comes to sleep modes. The gpio_wakeup_enable() function requires the pin to be connected to the Real-Time Clock (RTC) controller. If you attempt to use a non-RTC pin (like GPIO 16 or 17), the function will silently fail or throw an error, and your board will sleep indefinitely.

Required Hardware & Pin Mapping
Component Specification / Variant Connection / Notes
Microcontroller ESP32-WROOM-32 DevKit V1 (30-pin or 38-pin) Main processing unit. Ensure it is the original ESP32, not the C3 or S3 (which have different RTC mappings).
Wakeup Switch 6x6mm Tactile Pushbutton (SPST-NO) Connects between GPIO 33 and GND.
Pull-up Resistor 10kΩ (0.25W, 1% tolerance) Optional if using internal pull-ups, but recommended for noise immunity in high-EMI environments.
Decoupling Capacitor 0.1µF (100nF) Ceramic (X7R) Place across 3V3 and GND near the ESP32 module to stabilize voltage during sleep/wake transitions.
Wakeup Pin GPIO 33 RTC-capable. Supports internal pull-up. Avoid GPIO 34-39 (input-only, no internal pull-ups).
Callout Tip: Why GPIO 33?
GPIOs 34, 35, 36 (VP), and 39 (VN) are RTC-capable and can wake the ESP32, but they are input-only and lack internal pull-up/pull-down resistors. Using them requires an external 10kΩ resistor to prevent the pin from floating and triggering immediate, unwanted wakeups. GPIO 33 is an RTC pin that supports internal pull-ups, making it the optimal choice for a simple button interface.

Complete Compilable Code: Light Sleep with GPIO Wakeup

The following code configures GPIO 33 for light sleep wakeup. It includes explicit pin definitions, error handling for the ESP-IDF API calls, and serial debugging to confirm the wake reason. Copy and paste this directly into your Arduino IDE.


#include <Arduino.h>
#include <driver/gpio.h>
#include <esp_sleep.h>

// --- PIN DEFINITIONS ---
#define WAKE_PIN GPIO_NUM_33
#define LED_PIN  GPIO_NUM_2  // Built-in LED on most DevKit V1 boards

void setup() {
  Serial.begin(115200);
  delay(1000); // Allow time for serial monitor to attach
  
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  Serial.println("ESP32 Booting...");

  // 1. Determine Wake Reason
  esp_sleep_wakeup_cause_t wake_reason = esp_sleep_get_wakeup_cause();
  if (wake_reason == ESP_SLEEP_WAKEUP_GPIO) {
    Serial.println("Woke up from Light Sleep via GPIO button press.");
  } else if (wake_reason == ESP_SLEEP_WAKEUP_UNDEFINED) {
    Serial.println("First boot (Hard Reset / Power On).");
  } else {
    Serial.printf("Woke up from other source: %d\n", wake_reason);
  }

  // 2. Configure the Wakeup Pin
  // Set pin as input
  gpio_set_direction(WAKE_PIN, GPIO_MODE_INPUT);
  
  // Enable internal pull-up (Pin rests HIGH)
  gpio_pullup_en(WAKE_PIN);
  gpio_pulldown_dis(WAKE_PIN);

  // 3. Enable GPIO Wakeup for Light Sleep
  // We want to wake when the pin goes LOW (button pressed to GND)
  esp_err_t err = gpio_wakeup_enable(WAKE_PIN, GPIO_INTR_LOW_LEVEL);
  
  if (err != ESP_OK) {
    Serial.printf("ERROR: gpio_wakeup_enable failed with code %d\n", err);
    Serial.println("Check if WAKE_PIN is a valid RTC-capable GPIO.");
    while(1) { delay(1000); } // Halt execution
  }

  // Keep LED on for 3 seconds to show we are awake
  Serial.println("System awake for 3 seconds...");
  delay(3000);
  
  digitalWrite(LED_PIN, LOW);
  Serial.println("Entering Light Sleep now. Press button to wake.");
  Serial.flush(); // Ensure all serial data is transmitted before sleeping

  // 4. Enter Light Sleep
  // The CPU halts here. RAM is retained. Execution resumes on the next line after wakeup.
  esp_light_sleep_start();
  
  // --- WAKEUP RESUMES HERE ---
  // Note: setup() does NOT run again. We must handle post-wake logic here or use a loop.
}

void loop() {
  // After waking from light sleep, the code drops into loop().
  Serial.println("Awake in loop()! Doing work...");
  digitalWrite(LED_PIN, HIGH);
  delay(2000);
  digitalWrite(LED_PIN, LOW);
  
  Serial.println("Returning to Light Sleep.");
  Serial.flush();
  
  // Re-enter light sleep from the loop
  esp_light_sleep_start();
}

Troubleshooting: "gpio_wakeup_enable" Errors & Failures

When working with ESP-IDF sleep APIs inside the Arduino wrapper, things often fail silently or throw cryptic ESP-IDF log errors in the serial monitor. If your board refuses to wake, or throws an error upon entering sleep, check these three things first:

  1. Verify RTC Capability: Ensure your chosen pin is physically wired to the RTC peripheral. (See table above).
  2. Verify Pull-up/Pull-down State: If you configure GPIO_INTR_LOW_LEVEL but the pin is already physically held LOW (or floating low), the ESP32 will wake up instantly, creating a boot-loop that looks like a crash.
  3. Check for Deep Sleep Confusion: If you are actually calling esp_deep_sleep_start() later in your code, gpio_wakeup_enable() will do absolutely nothing. Deep sleep requires the esp_sleep_enable_ext0_wakeup() API.

Exact Error Strings and Ranked Causes

Exact Serial Monitor Error String Root Cause Fix
E (142) gpio: gpio_wakeup_enable (231): GPIO wakeup from light sleep is only supported on RTC IOs You passed a non-RTC pin (e.g., GPIO 16, 17, 5, 18) to the function. The RTC controller cannot monitor these pins while the main CPU is powered down. Change #define WAKE_PIN to an RTC-capable pin like GPIO_NUM_33 or GPIO_NUM_32.
(No error, but board wakes up instantly in a continuous loop) The pin is floating, or the interrupt level matches the pin's current resting state. For example, waking on LOW when the pin has no pull-up and is reading LOW. Add gpio_pullup_en(WAKE_PIN); before enabling wakeup, and ensure your physical button switches the pin to GND (LOW).
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1) You attached a standard attachInterrupt() ISR that takes too long, or you attempted to use I2C/SPI inside the wakeup ISR before the peripherals were fully re-initialized. Remove attachInterrupt(). gpio_wakeup_enable handles the hardware trigger natively. Do not use standard Arduino ISRs alongside light sleep wakeup triggers.

Extending and Simplifying the Build

Once you have basic GPIO light sleep working, you will likely need to adapt it for a real-world deployment. Here is how to scale the project up or strip it down.

How to Simplify (Switching to Deep Sleep)

If you realize you do not actually need to retain RAM variables between button presses, light sleep is overkill. Light sleep draws roughly 0.8mA to 1.5mA. Deep sleep draws 10µA to 20µA. To simplify your code and drop power consumption by 98%, delete gpio_wakeup_enable() and replace it with:

esp_sleep_enable_ext0_wakeup(WAKE_PIN, 0); // 0 = Wake on LOW
esp_deep_sleep_start();

Note: Deep sleep resets the ESP32. Execution will restart at the top of setup(), not resume in loop().

How to Extend (Adding a Timeout Failsafe)

In battery-powered sensor nodes, you cannot rely solely on a user pressing a button. You must extend the build to include a timer wakeup so the device can periodically poll sensors even if the button is never pressed. Add this before calling esp_light_sleep_start():

// Wake up after 60 seconds if the button isn't pressed
esp_sleep_enable_timer_wakeup(60 * 1000000ULL); 

After waking, check esp_sleep_get_wakeup_cause() to determine if the wake was triggered by ESP_SLEEP_WAKEUP_GPIO (button) or ESP_SLEEP_WAKEUP_TIMER (timeout).

Final Decision Path: Deep Sleep vs. Light Sleep API

Choosing between gpio_wakeup_enable (Light Sleep) and esp_sleep_enable_ext0_wakeup (Deep Sleep) dictates your entire firmware architecture. Use this decision matrix to lock in your final approach.

Project Requirement Light Sleep (gpio_wakeup_enable) Deep Sleep (esp_sleep_enable_ext0)
Must retain RAM variables / state? Yes. RAM is powered. Variables persist. No. RAM is lost. Must use RTC_MEMORY or NVS.
Acceptable Wakeup Latency? < 1 millisecond (Instant resume) ~200-500 milliseconds (Full hardware reboot)
Target Current Draw (Idle)? ~0.8 mA (800 µA) ~0.01 mA (10 µA)
Code Execution Flow? Resumes on the exact line after sleep call. Restarts at the beginning of setup().
The Default Recommendation:
Unless your application strictly requires retaining complex RAM state (like an active TCP connection or a large local buffer) and you have a generous battery capacity, default to Deep Sleep using esp_sleep_enable_ext0_wakeup(). The 100x reduction in standby current and the simplicity of a standard reboot-cycle architecture make Deep Sleep the superior choice for 90% of battery-powered ESP32 button-triggered projects. Reserve gpio_wakeup_enable exclusively for ultra-low-latency remote controls or stateful audio streaming devices.

For deeper technical specifications on ESP32 power domains and RTC peripheral mappings, consult the official Espressif Sleep Modes API Reference and the ESP-IDF GPIO Configuration Guide.