Hi there,
So , The S3 is the more stable of the two, They are not Identical as I have said in the past, Just because it says “ESP32” , Espressif wants you to think they are. but I digress;
Cut to the chase… **REMOVE **
"esp_sleep_cpu_retention_init(); " // REMOVE on ESP32-C6
may be enough but here is the full breakdown:
Key Differences Between ESP32-S3 and ESP32-C6 Sleep Handling:
Feature |
ESP32-S3 |
ESP32-C6 |
Sleep APIs |
Stable across light/deep sleep |
Light sleep still has quirks/limitations in ESP-IDF (especially <v5.1) |
CPU retention for light sleep |
Supported fully |
May require different setup or is not fully stable depending on the revision of the chip and SDK |
Wake-up sources |
Timer + GPIO reliable |
Timer wake-up is deep sleep reliable — light sleep wake-up may fail without proper RTC domain setup |
Clock domains / retention |
More automatic retention config |
RTC peripherals require explicit retention and sometimes cannot retain properly in light sleep |
esp_sleep_cpu_retention_init();
is not supported / not required on C6:
- On ESP32-C6, CPU retention is not yet stable or fully functional for light sleep, depending on silicon revision and IDF version.
- This call is specific to ESP32-S3 and ESP32-S2 series.
- No call to
esp_sleep_enable_timer_wakeup()
before esp_light_sleep_start()
inside the loop:
- It’s outside the loop logic due to where the switch/case is placed.
- It might need to be explicitly called each time before sleep if not persistent across calls.
- The wakeup cause check is done immediately without going to sleep yet:
switch (esp_sleep_get_wakeup_cause())
But this is before entering esp_light_sleep_start()
, so the wake-up cause is likely still “undefined” at that moment.
Move the wakeup source check AFTER waking up:
esp_sleep_enable_timer_wakeup(400000); // Always call before sleep
ESP_LOGI(TAG, "Entering light sleep ");
esp_light_sleep_start(); // Actually enter light sleep
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); // Now it's valid
const char *wakeup_reason;
switch (cause)
{
case ESP_SLEEP_WAKEUP_TIMER:
wakeup_reason = "timer";
printf("TIMER WAKE UP \n");
break;
case ESP_SLEEP_WAKEUP_GPIO:
wakeup_reason = "pin";
break;
default:
wakeup_reason = "other";
break;
}
Check power domain settings:
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON);
but C6 sometimes needs RTC_SLOW_MEM or FAST_MEM retention explicitly handled. Also, double-check if those domains are required to stay on in light sleep. I forget which way it is for C6
Try deep sleep as a sanity check on the C6 to verify that wake-up itself works:
esp_sleep_enable_timer_wakeup(400000);
esp_deep_sleep_start();
If this works, but light sleep doesn’t, it confirms light sleep retention isn’t properly configured or not stable on the ESP-IDF version for C6.
Bottom Line:
The Xiao ESP32-C6 handles light sleep differently than ESP32-S3.
Remove esp_sleep_cpu_retention_init()
(it’s S3-specific).
Always check wake-up cause after esp_light_sleep_start()
.
Also confirm that your ESP-IDF version fully supports light sleep retention on the C6 — some features may not be stable depending on your chip revision.
HTH
GL
PJ 
Please don’t forget to mark it as the Solution so others may find it faster. 