From 6cf212d12a40a85f0ee9e49e6916cfb3374210d4 Mon Sep 17 00:00:00 2001 From: cottongin Date: Mon, 9 Mar 2026 05:19:48 -0400 Subject: [PATCH] fix: prevent idle freeze by hardening NTP and clock power management BootNtpSync now acquires a HalPowerManager::Lock for the entire WiFi/NTP task lifecycle, keeping the CPU at full speed during scan, connect, sync, and teardown. The clock refresh logic in the main loop now explicitly restores CPU frequency and resets the activity timer before requesting a render, preventing display SPI operations from running at 10 MHz. Made-with: Cursor --- chat-summaries/2026-03-09_06-00-summary.md | 28 ++++++++++++++++++++++ src/main.cpp | 4 ++++ src/util/BootNtpSync.cpp | 2 ++ 3 files changed, 34 insertions(+) create mode 100644 chat-summaries/2026-03-09_06-00-summary.md diff --git a/chat-summaries/2026-03-09_06-00-summary.md b/chat-summaries/2026-03-09_06-00-summary.md new file mode 100644 index 00000000..c551db52 --- /dev/null +++ b/chat-summaries/2026-03-09_06-00-summary.md @@ -0,0 +1,28 @@ +# Fix Idle Freeze: NTP Power Lock and Clock Refresh Hardening + +**Date**: 2026-03-09 + +## Task Description + +Fix device freeze during idle, where the device stops responding to button presses after idling on the Home screen and requires a hard reset. Root cause was the mod-specific clock refresh logic in the main loop triggering a display render while the CPU is at reduced frequency (10 MHz low-power mode), combined with the background BootNtpSync task running WiFi/NTP operations without holding a power lock. + +## Root Cause + +The freeze coincides with the clock minute boundary. The mod's clock refresh code detects the minute change and calls `activityManager.requestUpdate()`, triggering a Home screen render while the CPU is at 10 MHz. SPI display operations at reduced APB frequency can deadlock the display communication. Additionally, `BootNtpSync` runs WiFi/NTP on a background task with no power lock, risking instability during WiFi teardown when the main loop may enter low-power mode. + +## Changes Made + +### 1. `src/util/BootNtpSync.cpp` +- Added `#include ` +- Added `HalPowerManager::Lock powerLock;` at the top of `taskFunc()` to keep the CPU at full speed for the entire duration of WiFi scanning, connection, NTP sync, and teardown + +### 2. `src/main.cpp` (clock refresh block, ~lines 408-428) +- In the `sawInvalidTime` branch: added `lastActivityTime = millis()` and `powerManager.setPowerSaving(false)` before calling `requestUpdate()` +- In the minute-change branch: added `lastActivityTime = millis()` and `powerManager.setPowerSaving(false)` before calling `requestUpdate()` +- This ensures the CPU is restored to 160 MHz before any render-related code executes and prevents immediate re-entry into low-power mode + +## Follow-up Items + +- Verify on device that the freeze no longer occurs after idling for extended periods +- Monitor heap usage to confirm the power lock doesn't introduce memory issues +- Test that NTP sync still completes successfully with the power lock in place diff --git a/src/main.cpp b/src/main.cpp index 0924681f..110e95d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -416,9 +416,13 @@ void loop() { if (lastRenderedMinute < 0) { lastRenderedMinute = currentMinute; if (sawInvalidTime) { + lastActivityTime = millis(); + powerManager.setPowerSaving(false); activityManager.requestUpdate(); } } else if (currentMinute != lastRenderedMinute) { + lastActivityTime = millis(); + powerManager.setPowerSaving(false); activityManager.requestUpdate(); lastRenderedMinute = currentMinute; } diff --git a/src/util/BootNtpSync.cpp b/src/util/BootNtpSync.cpp index c4627201..61ef904c 100644 --- a/src/util/BootNtpSync.cpp +++ b/src/util/BootNtpSync.cpp @@ -10,6 +10,7 @@ #include "CrossPointSettings.h" #include "WifiCredentialStore.h" +#include #include "util/TimeSync.h" namespace BootNtpSync { @@ -93,6 +94,7 @@ static bool tryConnectToSavedNetwork(const TaskParams& params) { } static void taskFunc(void* param) { + HalPowerManager::Lock powerLock; auto* params = static_cast(param); bool connected = tryConnectToSavedNetwork(*params);