diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index c2d78ae0..914a4589 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -12,7 +12,8 @@ #include #include #include -#include "driver/rtc_io.h" +#include "soc/rtc.h" +#include "esp_system.h" class ESP32Board : public mesh::MainBoard { protected: @@ -60,25 +61,56 @@ public: return raw / 4; } - void enterLightSleep(uint32_t secs) { -#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(P_LORA_DIO_1) // Supported ESP32 variants - if (rtc_gpio_is_valid_gpio((gpio_num_t)P_LORA_DIO_1)) { // Only enter sleep mode if P_LORA_DIO_1 is RTC pin - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - esp_sleep_enable_ext1_wakeup((1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet + uint32_t getIRQGpio() { + return P_LORA_DIO_1; // default for SX1262 + } + + void sleep(uint32_t secs) override { + // Skip if not allow to sleep + if (inhibit_sleep) { + return; + } - if (secs > 0) { - esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs - } + // Use more accurate clock in sleep +#if SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 + if (rtc_clk_slow_src_get() != SOC_RTC_SLOW_CLK_SRC_RC_FAST) { - esp_light_sleep_start(); // CPU enters light sleep + // Switch slow clock source to RC_FAST / 256 (~31.25 kHz) + rtc_clk_slow_src_set(SOC_RTC_SLOW_CLK_SRC_RC_FAST); + + // Calibrate slow clock + esp_clk_slow_boot_cal(1024); } #endif - } - void sleep(uint32_t secs) override { - if (!inhibit_sleep) { - enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet + // Configure GPIO wakeup + gpio_num_t wakeupPin = (gpio_num_t)getIRQGpio(); + esp_sleep_enable_gpio_wakeup(); + gpio_wakeup_enable((gpio_num_t)wakeupPin, GPIO_INTR_HIGH_LEVEL); // Wake up when receiving a LoRa packet + + // Configure timer wakeup + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000ULL); // Wake up periodically to do scheduled jobs + } + + // Disable CPU interrupt servicing + noInterrupts(); + + // Skip sleep if there is a LoRa packet + if (digitalRead(wakeupPin) == HIGH) { + interrupts(); + return; } + + // MCU enters light sleep + esp_light_sleep_start(); + + // Avoid ISR flood during wakeup due to HIGH LEVEL interrupt + gpio_wakeup_disable(wakeupPin); + gpio_set_intr_type(wakeupPin, GPIO_INTR_POSEDGE); + + // Enable CPU interrupt servicing + interrupts(); } uint8_t getStartupReason() const override { return startup_reason; }