diff options
| author | mark9064 <30447455+mark9064@users.noreply.github.com> | 2024-01-25 22:28:53 +0000 |
|---|---|---|
| committer | JF <JF002@users.noreply.github.com> | 2024-08-05 20:32:43 +0200 |
| commit | 2bb611db8e5be5731d848edef351f780c676deae (patch) | |
| tree | 7cb6e36f1ac7313b95ce8e0fb1fd1998840f7532 /src | |
| parent | ef88e8165c3d8475da2d7dcae78fd1b2ac7ff34d (diff) | |
aod: constant frequency idle frames
Diffstat (limited to 'src')
| -rw-r--r-- | src/displayapp/DisplayApp.cpp | 49 | ||||
| -rw-r--r-- | src/displayapp/DisplayApp.h | 7 |
2 files changed, 55 insertions, 1 deletions
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 6fda99db..88ce085f 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -154,6 +154,36 @@ void DisplayApp::InitHw() { lcd.Init(); } +TickType_t DisplayApp::CalculateSleepTime() { + TickType_t ticksElapsed = xTaskGetTickCount() - alwaysOnStartTime; + // Divide both the numerator and denominator by 8 to increase the number of ticks (frames) before the overflow tick is reached + TickType_t elapsedTarget = ROUNDED_DIV((configTICK_RATE_HZ / 8) * alwaysOnTickCount * alwaysOnRefreshPeriod, 1000 / 8); + // ROUNDED_DIV overflows when numerator + (denominator floordiv 2) > uint32 max + // in this case around 9 hours + constexpr TickType_t overflowTick = (UINT32_MAX - (1000 / 16)) / ((configTICK_RATE_HZ / 8) * alwaysOnRefreshPeriod); + + // Assumptions + + // Tick rate is multiple of 8 + // Needed for division trick above + static_assert(configTICK_RATE_HZ % 8 == 0); + + // Local tick count must always wraparound before the system tick count does + // As a static assert we can use 64 bit ints and therefore dodge overflows + // Always on overflow time (ms) < system tick overflow time (ms) + static_assert((uint64_t) overflowTick * (uint64_t) alwaysOnRefreshPeriod < (uint64_t) UINT32_MAX * 1000ULL / configTICK_RATE_HZ); + + if (alwaysOnTickCount == overflowTick) { + alwaysOnTickCount = 0; + alwaysOnStartTime = xTaskGetTickCount(); + } + if (elapsedTarget > ticksElapsed) { + return elapsedTarget - ticksElapsed; + } else { + return 0; + } +} + void DisplayApp::Refresh() { auto LoadPreviousScreen = [this]() { FullRefreshDirections returnDirection; @@ -204,7 +234,21 @@ void DisplayApp::Refresh() { switch (state) { case States::Idle: if (settingsController.GetAlwaysOnDisplay()) { - queueTimeout = lv_task_handler(); + if (!currentScreen->IsRunning()) { + LoadPreviousScreen(); + } + // Check we've slept long enough + // Might not be true if the loop received an event + // If not true, then wait that amount of time + queueTimeout = CalculateSleepTime(); + if (queueTimeout == 0) { + lv_task_handler(); + // Drop frames that we've missed if the loop took way longer than expected to execute + while (queueTimeout == 0) { + alwaysOnTickCount += 1; + queueTimeout = CalculateSleepTime(); + } + } } else { queueTimeout = portMAX_DELAY; } @@ -247,6 +291,9 @@ void DisplayApp::Refresh() { if (settingsController.GetAlwaysOnDisplay()) { brightnessController.Set(Controllers::BrightnessController::Levels::AlwaysOn); lcd.LowPowerOn(); + // Record idle entry time + alwaysOnTickCount = 0; + alwaysOnStartTime = xTaskGetTickCount(); } else { brightnessController.Set(Controllers::BrightnessController::Levels::Off); lcd.Sleep(); diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 96bce4dd..356e490f 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -135,6 +135,13 @@ namespace Pinetime { Utility::StaticStack<FullRefreshDirections, returnAppStackSize> appStackDirections; bool isDimmed = false; + + TickType_t CalculateSleepTime(); + TickType_t alwaysOnTickCount; + TickType_t alwaysOnStartTime; + // If this is to be changed, make sure the actual always on refresh rate is changed + // by configuring the LCD refresh timings + static constexpr uint32_t alwaysOnRefreshPeriod = 500; }; } } |
