From f2ed0f7c8c0333d6dff91718a11d5e10062d5942 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Wed, 3 Apr 2024 08:55:48 +1300 Subject: [PATCH] Fix Light-sleep for ESP32 (#3521) * Change wakeup source from EXT0 to GPIO * Avoid ISR issue on wake * Detect press from wake reason, instead of digitalRead * Missing #ifdef Risky phone-typed commit * Fix PowerFSM timed transition preventing light sleep Addresses https://github.com/meshtastic/firmware/issues/3517 --------- Co-authored-by: Ben Meadors --- src/PowerFSM.cpp | 39 ++++++++++++++++++++++----------------- src/sleep.cpp | 18 +++++++++++------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index b6e267e28..0002a62b4 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -102,23 +102,18 @@ static void lsIdle() powerFSM.trigger(EVENT_SERIAL_CONNECTED); break; + case ESP_SLEEP_WAKEUP_GPIO: + // GPIO wakeup is now used for all ESP32 devices during light sleep + powerFSM.trigger(EVENT_PRESS); + break; + default: - // We woke for some other reason (button press, device interrupt) - // uint64_t status = esp_sleep_get_ext1_wakeup_status(); + // We woke for some other reason (device interrupt?) LOG_INFO("wakeCause2 %d\n", wakeCause2); -#ifdef BUTTON_PIN - bool pressed = !digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN); -#else - bool pressed = false; -#endif - if (pressed) { // If we woke because of press, instead generate a PRESS event. - powerFSM.trigger(EVENT_PRESS); - } else { - // Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc) - // we lie and say "wake timer" because the interrupt will be handled by the regular IRQ code - powerFSM.trigger(EVENT_WAKE_TIMER); - } + // Let the NB state handle the IRQ (and that state will handle stuff like IRQs etc) + // we lie and say "wake timer" because the interrupt will be handled by the regular IRQ code + powerFSM.trigger(EVENT_WAKE_TIMER); break; } } else { @@ -348,9 +343,6 @@ void PowerFSM_setup() powerFSM.add_timed_transition(&statePOWER, &stateDARK, Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout"); - powerFSM.add_timed_transition(&stateDARK, &stateDARK, - Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, - "Screen-on timeout"); // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) #ifdef ARCH_ESP32 @@ -361,11 +353,24 @@ void PowerFSM_setup() powerFSM.add_timed_transition(&stateNB, &stateLS, Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout"); + + // If ESP32 and using power-saving, timer mover from DARK to light-sleep + // Also serves purpose of the old DARK to DARK transition(?) See https://github.com/meshtastic/firmware/issues/3517 powerFSM.add_timed_transition( &stateDARK, &stateLS, Default::getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, "Bluetooth timeout"); + } else { + // If ESP32, but not using power-saving, check periodically if config has drifted out of stateDark + powerFSM.add_timed_transition(&stateDARK, &stateDARK, + Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), + NULL, "Screen-on timeout"); } +#else + // If not ESP32, light-sleep not used. Check periodically if config has drifted out of stateDark + powerFSM.add_timed_transition(&stateDARK, &stateDARK, + Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, + "Screen-on timeout"); #endif powerFSM.run_machine(); // run one iteration of the state machine, so we run our on enter tasks for the initial DARK state diff --git a/src/sleep.cpp b/src/sleep.cpp index 2f4bd09e1..e91bda782 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -312,13 +312,11 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r // assert(esp_sleep_enable_uart_wakeup(0) == ESP_OK); #endif #ifdef BUTTON_PIN -#if SOC_PM_SUPPORT_EXT_WAKEUP - esp_sleep_enable_ext0_wakeup((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN), - LOW); // when user presses, this button goes low -#else + // The enableLoraInterrupt() method is using ext0_wakeup, so we are forced to use GPIO wakeup + gpio_num_t pin = (gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN); + gpio_intr_disable(pin); + gpio_wakeup_enable(pin, GPIO_INTR_LOW_LEVEL); esp_sleep_enable_gpio_wakeup(); - gpio_wakeup_enable((gpio_num_t)BUTTON_PIN, GPIO_INTR_LOW_LEVEL); -#endif #endif enableLoraInterrupt(); #ifdef PMU_IRQ @@ -342,6 +340,12 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r } assert(res == ESP_OK); +#ifdef BUTTON_PIN + gpio_wakeup_disable(pin); + // Would have thought that need gpio_intr_enable() here, but nope.. + // Works fine without it; crashes with it. +#endif + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); #ifdef BUTTON_PIN if (cause == ESP_SLEEP_WAKEUP_GPIO) { @@ -406,4 +410,4 @@ void enableLoraInterrupt() gpio_wakeup_enable((gpio_num_t)RF95_IRQ, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high #endif } -#endif \ No newline at end of file +#endif