diff --git a/include/parameter.h b/include/parameter.h index a047652..ea98c38 100644 --- a/include/parameter.h +++ b/include/parameter.h @@ -109,6 +109,7 @@ unsigned long t_batteryIcon = 0; bool b_showBatteryIcon = true; // volatile: now also written from the AsyncTCP task (WS soft-sleep command). volatile bool b_softSleep = false; +unsigned long t_lastSerialActivity = 0; #if defined(ACC_MPU6050) || defined(ACC_BMA400) bool b_gyroEnabled = true; #endif diff --git a/platformio.ini b/platformio.ini index 78afc7d..0f56430 100644 --- a/platformio.ini +++ b/platformio.ini @@ -92,3 +92,37 @@ platform = native test_build_src = no test_framework = unity build_flags = -Iinclude + +# Tier-2 automatic light-sleep build (AI FYI, see PR). Opt-in, from-source: the +# CONFIG_PM_* / tickless / BT-controller-sleep flags below are compile-time and +# require rebuilding the framework from source (custom_sdkconfig triggers it). +# The BT low-power clock is RTC_SLOW because this board has no external 32kHz +# crystal (CONFIG_RTC_CLK_SRC_INT_RC). Pair with the CONFIG_PM_ENABLE-guarded +# esp_pm_configure() + loop yield + UART wake in src/hds.ino. Build: +# pio run -e esp32s3_pm -t upload +# custom_component_remove skips unused managed IDF components that the from-source +# build would otherwise compile (esp-modbus fails a static assert); none are +# #included by this firmware, so removal is image-identical. +[env:esp32s3_pm] +extends = env:esp32s3 +custom_component_remove = + espressif/esp-modbus + espressif/esp-sr + espressif/esp-zboss-lib + espressif/esp-zigbee-lib + espressif/esp_insights + espressif/esp_diagnostics + espressif/esp_diag_data_store + espressif/esp_rainmaker + espressif/rmaker_common + espressif/esp_modem + espressif/esp-dsp + chmorgan/esp-libhelix-mp3 + espressif/qrcode +custom_sdkconfig = + CONFIG_PM_ENABLE=y + CONFIG_FREERTOS_USE_TICKLESS_IDLE=y + CONFIG_PM_DFS_INIT_AUTO=y + CONFIG_BT_CTRL_MODEM_SLEEP=y + CONFIG_BT_CTRL_MODEM_SLEEP_MODE_1=y + CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW=y diff --git a/src/hds.ino b/src/hds.ino index e99c9bf..0cc5b4d 100644 --- a/src/hds.ino +++ b/src/hds.ino @@ -1,5 +1,8 @@ #include #include +#include "esp_pm.h" +#include "esp_sleep.h" +#include "driver/uart.h" #include "config.h" #include "parameter.h" @@ -423,6 +426,13 @@ void wifi_init() { MyUsbCallbacks usbCallbacks; +#if CONFIG_PM_ENABLE +// Held while the scale is connected + live (not soft-sleep), pinning the CPU at +// max freq so on-scale extensions have full compute; released otherwise so DFS +// scales down and light sleep engages. +esp_pm_lock_handle_t s_activeFreqLock = nullptr; +#endif + // Map esp_reset_reason() to a short string for the boot log only. The raw // numeric code is what we ship in the ADS debug packet (byte 24); this is // purely for human-readable serial output. @@ -882,6 +892,22 @@ void setup() { } else { hdsOtaRollbackMarkValid(); } + +#if CONFIG_PM_ENABLE + { + esp_pm_config_t pmcfg = { + .max_freq_mhz = 240, + .min_freq_mhz = 80, + .light_sleep_enable = true, + }; + esp_err_t pmrc = esp_pm_configure(&pmcfg); + Serial.printf("[pm] esp_pm_configure ls=on 240/80 -> %s\n", esp_err_to_name(pmrc)); + esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "active", &s_activeFreqLock); + uart_set_wakeup_threshold(UART_NUM_0, 3); + esp_err_t urc = esp_sleep_enable_uart_wakeup(UART_NUM_0); + Serial.printf("[pm] uart0 wake-on-rx -> %s\n", esp_err_to_name(urc)); + } +#endif } /** @@ -1570,6 +1596,19 @@ void loop() { // here on the loop task rather than racing peripheral drivers. processWsPendingCmds(); +#if CONFIG_PM_ENABLE + { + static bool prevActive = false; + bool active = deviceConnected && !b_softSleep; + if (active != prevActive && s_activeFreqLock != nullptr) { + if (active) esp_pm_lock_acquire(s_activeFreqLock); + else esp_pm_lock_release(s_activeFreqLock); + prevActive = active; + Serial.printf("[pm] cpu %s (connected+live=%d)\n", active ? "pinned 240" : "released->DFS", active); + } + } +#endif + if (b_powerOff){ shut_down_now_nobeep(); return; @@ -1605,6 +1644,7 @@ void loop() { data[len++] = Serial.read(); } usbCallbacks.onStream(data, len); // Process serial byte stream + t_lastSerialActivity = millis(); } usbCallbacks.poll(); @@ -1785,6 +1825,16 @@ void loop() { } } } + +#if CONFIG_PM_ENABLE + if (millis() - t_lastSerialActivity <= 250) { + vTaskDelay(1); + } else if (b_softSleep) { + vTaskDelay(pdMS_TO_TICKS(50)); + } else { + vTaskDelay(pdMS_TO_TICKS(10)); + } +#endif }