When waking from deep sleep via a timer, I want to increment a counter and then go back to sleep. However, I also want to set wake interrupts for both EXT0 and EXT1 in the wake stub. I can do this no problem in the main code using esp_sleep_enable_ext0_wakeup and esp_sleep_enable_ext1_wakeup.
Is it possible to either retain these with the wake stub, or set them again in the stub before going back to sleep? Currently all I'm able to do is set a new timer, using the following code:
Code: Select all
static void RTC_IRAM_ATTR wake_stub() {
esp_default_wake_deep_sleep();
boots++;
switch (stub_esp_sleep_get_wakeup_cause())
{
case ESP_SLEEP_WAKEUP_EXT0:
ets_printf(wake_reason_ext0_msg);
return;
case ESP_SLEEP_WAKEUP_EXT1:
ets_printf(wake_reason_ext1_msg);
return;
case ESP_SLEEP_WAKEUP_TIMER:
ets_printf(wake_reason_timer_msg);
break;
default:
// Boot normally;
return;
}
ets_printf(wake_fmt_str, boots);
if (boots >= max_boots) {
// On revision 0 of ESP32, this function must be called:
esp_default_wake_deep_sleep();
// Return from the wake stub function to continue
// booting the firmware.
return;
}
// Print status
ets_printf(sleep_fmt_str);
// Wait for UART to end transmitting.
// feed the watchdog
REG_WRITE(TIMG_WDTFEED_REG(0), 1);
while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT)) {
}
deepsleep_for_us(sleep_duration * 1000000);
// Set the pointer of the wake stub function.
REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)&wake_stub);
// Go to sleep.
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
// A few CPU cycles may be necessary for the sleep to start...
while (true) {
;
}
// never reaches here.
}
// Comment out this line if you're using the internal RTC RC (150KHz) oscillator.
//#define USE_EXTERNAL_RTC_CRYSTAL
#ifdef USE_EXTERNAL_RTC_CRYSTAL
#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
#else
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
#endif // USE_EXTERNAL_RTC_CRYSTAL
RTC_IRAM_ATTR void deepsleep_for_us(uint64_t duration_us) {
// Feed watchdog
REG_WRITE(TIMG_WDTFEED_REG(0), 1);
// Get RTC calibration
uint32_t period = REG_READ(RTC_SLOW_CLK_CAL_REG);
// Calculate sleep duration in microseconds
int64_t sleep_duration = (int64_t)duration_us - (int64_t)DEEP_SLEEP_TIME_OVERHEAD_US;
if (sleep_duration < 0) {
sleep_duration = 0;
}
// Convert microseconds to RTC clock cycles
int64_t rtc_count_delta = (sleep_duration << RTC_CLK_CAL_FRACT) / period;
// Feed watchdog
REG_WRITE(TIMG_WDTFEED_REG(0), 1);
// Get current RTC time
SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE);
while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) {
ets_delay_us(1);
}
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_TIME_VALID_INT_CLR);
uint64_t now = READ_PERI_REG(RTC_CNTL_TIME0_REG);
now |= ((uint64_t)READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32;
// Set wakeup time
uint64_t future = now + rtc_count_delta;
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, future & UINT32_MAX);
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, future >> 32);
// Start RTC deepsleep timer
REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, RTC_TIMER_TRIG_EN); // Wake up on timer
// WRITE_PERI_REG(RTC_CNTL_SLP_REJECT_CONF_REG, 0); // Clear sleep rejection cause
// Go to sleep
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
}