in common you keep all your Serial.begin() and Serial.print(“hello”) statements, when you start to run your ESP battery powered, using the battery pins, or directly the 3.3V pin.
Unfortunately the C3 seems to have a problem to wake up (timed) after deep sleep, as it will crash on the active Serial.xy lines within the code.
Any thoughts?
As soon as you remove all the Serial.xy lines C3 wil work properly again…?!
This is the test-project i created, that will only work without serial.xy lines:
#include <Arduino.h>
# define sensor_power_pin 3 /* power up sensor */
# define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
uint64_t time_to_sleep = 5; /* sleep for 5 seconds - short schedule just for testing */
void setup() {
//Serial.begin();
//Serial.println("Hello World");
pinMode(sensor_power_pin, OUTPUT);
/*power up sensor */
digitalWrite(sensor_power_pin, HIGH);
delay(5000);
digitalWrite(sensor_power_pin, LOW);
/* GO DEEP SLEEP */
Serial.println("Done - activating deepsleep mode");
time_to_sleep = time_to_sleep * uS_TO_S_FACTOR;
esp_sleep_enable_timer_wakeup(time_to_sleep);
Serial.flush();
esp_deep_sleep_start();
}
void loop() {
// put your main code here, to run repeatedly:
}
Hi,
thanks for the response… just tested your approach without success.
please keep in mind - the problem only occurs when the esp32c3 is battery powered, or connected to a USB cable without data-lines.
It looks like the ESP crashes somehow directly after wake up.
But how to debug? How to do error handling in that case?
Or is it simply a bug?
All other ESP’s do not crash due to missing serial/USB connection
This is the current code that will not work on a battery powered esp32c3 - remove all serial prints and it will work!
#include <Arduino.h>
# define sensor_power_pin 3 /* power up sensor */
# define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
uint64_t time_to_sleep = 5; /* sleep for 5 seconds - short schedule just for testing */
void setup() {
delay(2000);
Serial.begin();
Serial.println("Hello World");
pinMode(sensor_power_pin, OUTPUT);
/*power up sensor */
digitalWrite(sensor_power_pin, HIGH);
delay(1000);
digitalWrite(sensor_power_pin, LOW);
delay(1000);
digitalWrite(sensor_power_pin, HIGH);
delay(1000);
digitalWrite(sensor_power_pin, LOW);
delay(1000);
digitalWrite(sensor_power_pin, HIGH);
delay(1000);
digitalWrite(sensor_power_pin, LOW);
/* GO DEEP SLEEP */
Serial.println("Done - activating deepsleep mode");
time_to_sleep = time_to_sleep * uS_TO_S_FACTOR;
esp_sleep_enable_timer_wakeup(time_to_sleep);
Serial.flush();
esp_deep_sleep_start();
}
void loop() {
// put your main code here, to run repeatedly:
}```
Finally claude.code was able to explain the root cause! Many of you already pointed into the correct direction - thanks. This is the explanation:
Yes, this is a well-known issue specific to boards that use native USB CDC for Serial — and the XIAO ESP32-C3 is one of them.
Root Cause
Unlike older ESP8266/ESP32 boards that have a dedicated USB-to-UART chip (CH340, CP2102), the XIAO ESP32-C3 uses the ESP32-C3’s built-in USB CDC as Serial. This changes the behavior fundamentally:
When a USB host is connected, Serial.print() writes into a buffer that gets drained by the host
When no USB host is present, the CDC TX buffer fills up and blocks, waiting for a consumer that never comes
This eventually triggers the watchdog timer, which resets the chip
Serial.flush() explicitly blocks until the TX buffer is empty. Without a USB host, this never completes → watchdog reset fires → esp_deep_sleep_start() on line 36 is never reached. The chip just resets in a hard boot loop instead of entering sleep.
The fix
Wrap all serial output in a USB-connected check. Arduino’s USB CDC Serial object evaluates to true only when a host is connected:
if (Serial) {
Serial.println("Hello World");
}
and if not needed - removeSerial.flush() or wrap this line as well