I would study Gary’s example code. It gives you a lot of control over several pins. However, I can’t think of a way immediately that would wake-up with one pin going HIGH or another going LOW.
Hi there,
And Welcome here… after a few posts you can post code and pics and other stuff so reply if you can. First Start with the Basics, NO Kitchen Sink approaches here.
Do you have a wakeup working on GPIO4 going low? that’s the lowest hanging fruit (easiest) first.
Start there.
Note : it’s wise to Post up a Picture of how it’s connected if it’s more than just a button on the pin 3 or D2 logically. KNOW this… sometimes the libraries or BSP file used to compile the code with(BSP=pins for what MCU, etc & MACROS) wants the pins as GPIO nomenclature others and some of the LIB’s have PIN macros , so the Logical pin names will work.
If you get stuck, always try that switch up.
Post up the code you have tried, use the code tags above “</>” paste it in there.
Be aware, The C3 is Different than the REST of the esp32 family. in the SPI, UARTS, and GPIO’s especially. You can see from previous posts, that assumptions on how it works will lead you the wrong way and waste your time. If your using a dev kit (a true one like pictured) don’t expect everything to translate to a Xiao’s or AFruit, or SparksRfun or Robot guy’s Hardware offering’s FYI
a real C3 is pictured.
Some choices…
A real C6 dev board… BTW

Random C6 offering. (older antenna)
HTH
GL PJ
IMO, there certainly IS a software way to approach it, but walk before you run. (spoiler alert) checking the Serial port connected is a way to tell if it’s USB is plugged in too!, Keep in mind the C3 can get esp_sleep_get_wakeup_cause() in code too! not Ideal in every case this method detects if the device was woken up by USB power after a deep sleep. While not a direct detection, it’s useful for some power management applications.
Hi there,
So Leg up Here is one I used in December , tested now works good you can start with that! if you don’t have anything yet.
There’s probably a video of it in action too!
code as tested…
// Xiao ESP32C3 Sleep and Wake Up demo...
// Blinks LED on PIN D10 - 10 times then Sleeps , Outputs Blink and sleep on Serial port too!
// Keeps track of the Boot count. (I use this to do different sub functions)
// BSP 3.0.1 was used .
// Pressing button connected to D1 wakes Up the MCU
// The Wake up reason is Also printed.
// Tested AOK , by PJG 3/23/24 and 12/30/23
#define LED 10 // or use LED_BUILTIN for on-board LED
#define INTERRUPT_PIN 2 // I used a push button connected to Vcc and Pin 1
RTC_DATA_ATTR int bootCount = 0;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Xiao C3 Sleep/Wake Demo - Power ON - " __DATE__ " at " __TIME__);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
++bootCount;
Serial.println("Boot number: " + String(bootCount));
print_wakeup_reason();
Serial.println("Going to blink the LED 10 times");
blink(10); // Allow time for wakeup
Serial.println("Going to sleep now");
delay (250);
// esp_sleep_enable_bt_wakeup(void)
esp_deep_sleep_enable_gpio_wakeup(1 << INTERRUPT_PIN, ESP_GPIO_WAKEUP_GPIO_HIGH);
delay (250);
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() { }
void blink(int times) {
for (int i = 0; i < times; i++) {
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
delay(1000);
Serial.print("Blink ");
Serial.println(i + 1);
}
}
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;
}
}
Serial output ;
Xiao C3 Sleep/Wake Demo - Power ON - Mar 23 2025 at 14:10:16
Boot number: 1
Wakeup was not caused by deep sleep: 0
Going to blink the LED 10 times
Blink 1
Blink 2
Blink 3
Blink 4
Blink 5
Blink 6
Blink 7
Blink 8
Blink 9
Blink 10
Going to sleep now
Xiao C3 Sleep/Wake Demo - Power ON - Mar 23 2025 at 14:10:16
Boot number: 2
Wakeup was not caused by deep sleep: 7
Going to blink the LED 10 times
Blink 1
Blink 2
Blink 3
Blink 4
Blink 5
Blink 6
Blink 7
Blink 8
Blink 9
Blink 10
Going to sleep now
Xiao C3 Sleep/Wake Demo - Power ON - Mar 23 2025 at 14:10:16
Boot number: 3
Wakeup was not caused by deep sleep: 7
Going to blink the LED 10 times
Blink 1
Blink 2
Blink 3
Blink 4
Blink 5
Blink 6
Blink 7
Blink 8
Blink 9
Blink 10
Going to sleep now
HTH
GL PJ
@aaronhughelectron - Just call the ext wake twice, once for each level.
Each of the 5 wake sources can be set to wake on one of 5 settings…
0: disable wakeup by RTC GPIO
1: wake up the chip upon the rising edge
2: wake up the chip upon the failing edge
3: wake up the chip upon the rising edge or the failing edge
4: wake up the chip upon low level
5: wake up the chip upon high level
But only Low and High are supported (Arduino).
if (esp_deep_sleep_enable_gpio_wakeup(WAKE_PIN_LOW_MASK, ESP_GPIO_WAKEUP_GPIO_LOW) == ESP_OK) {
Serial.println("Wake Low Enabled, Mask = " + String(WAKE_PIN_LOW_MASK));
} else {
Serial.println("Wake Low Error");
noSleep = true;
}
if (esp_deep_sleep_enable_gpio_wakeup(WAKE_PIN_HIGH_MASK, ESP_GPIO_WAKEUP_GPIO_HIGH) == ESP_OK) {
Serial.println("Wake High Enabled, Mask = " + String(WAKE_PIN_HIGH_MASK));
} else {
Serial.println("Wake High Error");
noSleep = true;
}
Edit> Mask set accordingly… for example…
#define WAKE_PIN_0 GPIO_NUM_2 // D0
#define WAKE_PIN_1 GPIO_NUM_3 // D1
#define WAKE_PIN_2 GPIO_NUM_5 // D3
#define WAKE_PIN_LOW_MASK ((1 << WAKE_PIN_0) + (1 << WAKE_PIN_2))
#define WAKE_PIN_HIGH_MASK (1 << WAKE_PIN_1)
Hi there,
Have you tried this suggestion /Code on a XIAO C3 ?
I’m betting NO!
GL PJ
Hi there,
Yep , that’s a C3 Good Job… LOL
this is the GOLD.
" if (esp_deep_sleep_enable_gpio_wakeup(WAKE_PIN_LOW_MASK, ESP_GPIO_WAKEUP_GPIO_LOW) == ESP_OK) {"
GL PJ
Which BSP did you use , If I may ask?
Hi @PJ_Glasso, a big thank you for all the information! I need some time to go through it first. For your last question, I am using Arduino IDE with ESP32 package on a MacbookPro. (Good morning from the UK!)
And for the previous discussion on ESP32 variants, I have some other background information for the project I have been working that you might find useful also FYI…
This circuit I am testing is later to be used on designing a PCB that will be installed on a personal physical device. That being said, I am afraid there is a constraint to both the size and cost for the MCU dev board. If it is too big, like in some of your pictures, it wouldn’t be able to fit in the device (it is such a pity as they are well-known to be great dev boards)! XIAO ESP32C3 board is thought to be the best option so far balancing size and functionality (battery charging, BLE/WiFi, etc.).
So the plan is to eventually make a PCB where I install all the components including XIAO ESP32C3 board on it. Would you say this is how I should go about for the PCB?
Below is the schematic of my full circuit (so far):
NOW I HAVE TRIED IT, THIS IS REALLY GOOD THANK YOU SO MUCH!!
And thank you for your advice on:
If your using a dev kit (a true one like pictured) don’t expect everything to translate to a Xiao’s or AFruit, or SparksRfun or Robot guy’s Hardware offering’s FYI
Turns out that I can put more than one esp_deep_sleep_enable_gpio_wakeup() in my code with the correct calling order (like how you did in your example), like LOW first then HIGH. But it saves so much of my time and avoided extra components like diodes and no need to do OR circuit anymore yay!! Thanks PJ!
Hey, thanks for sharing your experience!
Yeah, dealing with external deep sleep on the Xiao ESP32C3 can be tricky, especially with GPIO wakeup sources. That bitmask part (1ULL << 3
) is a crucial detail that’s easy to overlook! A lot of people try using the GPIO number directly instead of the proper bitmask, which leads to frustrating issues.
Your approach makes perfect sense, and the delays for easier debugging are a smart move—definitely saves some headaches when making changes.
Appreciate you dropping your code snippet here! Hope it helps others struggling with the same issue.