XIAO ESP32S3 Deep Sleep with XIAO Expansion Board

Hi, I am unsure if I am doing this correctly, but I wanted to use my xiao expansion board with its button connected to D1 or GPIO_2 and when that button is clicked, wake the esp32s3 from deep sleep. I am trying to modify the exisiting demo code and I cant seem to get the functionality working. When I click the button, nothing seems to happen. I have attached the code below and I have tried pulling the pin high and the pin low and I cant get the deep sleep working with the button. I have however got the button working on its own with some debouncing to make sure the button works so any advice will be appreciated:

#define BUTTON_PIN_BITMASK 0x4 // 2^2 in hex

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 doesnt 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_2,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
}

This is my debounce code:

#include <Arduino.h>
#include <U8x8lib.h>

// OLED Display setup
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset= */ U8X8_PIN_NONE);

// Pin configurations
const uint8_t buttonPin = 2;

// Debounce variables
const unsigned long debounceDelay = 50; // Debounce time in milliseconds
volatile unsigned long lastDebounceTime = 0; // Last time the button state changed

// Button states
enum class ButtonState : uint8_t {
    Released, // Button released
    Pressed   // Button pressed
};

volatile ButtonState buttonState = ButtonState::Released; // Current state of the button
volatile bool buttonPressed = false; // Flag indicating if the button is currently pressed
unsigned long buttonPressedTime = 0; // Time when the button was pressed

// Display duration when debugging (5s)
const unsigned long debugDisplayTime = 5000;

void updateDisplay();
void handleButtonPress();

void setup() {
    u8x8.begin();                    // Initialize OLED display
    u8x8.setFlipMode(1);             // Set display rotation
    Serial.begin(115200);            // Initialize serial communication
    pinMode(LED_BUILTIN, OUTPUT);    // Set built-in LED pin as output
    pinMode(buttonPin, INPUT_PULLUP); // Set button pin as input with internal pull-up resistor
    attachInterrupt(digitalPinToInterrupt(buttonPin), handleButtonPress, CHANGE); // Attach interrupt for button press detection
}

void loop() {
    if (buttonPressed) {
        unsigned long currentTime = millis();
        if (currentTime - buttonPressedTime >= debugDisplayTime) {
            buttonPressed = false;   // Reset button press flag
            u8x8.clearDisplay();     // Clear display
            digitalWrite(LED_BUILTIN, HIGH); // Turn off built-in LED
        } else {
            updateDisplay();         // Update OLED display
        }
    } else {
        u8x8.clearDisplay();        // Clear display if button not pressed
    }
}

void updateDisplay() {
    u8x8.setFont(u8x8_font_chroma48medium8_r); // Set font
    u8x8.setCursor(0, 0);                      // Set cursor position
    u8x8.print("Button Pressed");                // Print message on display
}

void handleButtonPress() {
    unsigned long currentTime = millis();
    if ((currentTime - lastDebounceTime) > debounceDelay) {
        buttonState = (digitalRead(buttonPin) == HIGH) ? ButtonState::Released : ButtonState::Pressed;
        if (buttonState == ButtonState::Pressed) {
            Serial.println("Button Pressed");
            digitalWrite(LED_BUILTIN, LOW);    // Turn on built-in LED
            buttonPressed = true;              // Set button pressed flag
            buttonPressedTime = currentTime;   // Record button press time
        } else {
            digitalWrite(LED_BUILTIN, HIGH);   // Turn off built-in LED
        }
        lastDebounceTime = currentTime;        // Record last debounce time
    }
}

i do know i think the button works backwards from what you would think logical
i think the button brings the pin to ground

FYI

Hi sorry for the late reply, Yh so looking at the datasheet and schematic, I can see that it brings the pin to ground so therefore when I set the esp_sleep_enable_ext0_wakeup, I choose the GPIO_NUM_2 and set it to low (0) and this just wakes up on its own when I do not press the button and I get the response saying Wakeup cause by external signal using RTC_IO. I am wondering if when the esp goes into deep sleep, that it brings the GPIO low automatically causing the wake up

Hi there,
Check out the Grove Expansion Memory test with Sleep Button demo I posted here.
examine the button logic and you’ll figure it out, You are close.
This one also has the logic for a sleep , wakeup button.

HTH
GL :slight_smile: PJ :v:

Hi PJ_Glasso,
Thanks for the response, I have managed to look into the documentation a bit more and found out that the RTC GPIO Pin needs to be pulled up or down using the rtc_gpio_pullup_en commands instead of the pinmode way. I have attached the code that allowed me to perform deep sleep with the push button.

#include "driver/rtc_io.h"

const gpio_num_t WAKEUP_BUTTON_PIN = GPIO_NUM_2; // Define GPIO_NUM_2 as a const

RTC_DATA_ATTR int bootCount = 0;

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();

  rtc_gpio_pullup_en(WAKEUP_BUTTON_PIN); // Use the const here
  rtc_gpio_pulldown_dis(WAKEUP_BUTTON_PIN); // Use the const here
  esp_sleep_enable_ext0_wakeup(WAKEUP_BUTTON_PIN, 0);   // When the button is pressed, wake up

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

1 Like