Improve sleep time calculation docs

This commit is contained in:
mark9064 2024-09-22 00:34:34 +01:00 committed by JF
parent 771008495e
commit 06b721a71f
2 changed files with 20 additions and 15 deletions

View File

@ -157,15 +157,20 @@ void DisplayApp::InitHw() {
} }
TickType_t DisplayApp::CalculateSleepTime() { TickType_t DisplayApp::CalculateSleepTime() {
TickType_t ticksElapsed = xTaskGetTickCount() - alwaysOnStartTime; // Calculates how many system ticks DisplayApp should sleep before rendering the next AOD frame
// Divide both the numerator and denominator by 8 to increase the number of ticks (frames) before the overflow tick is reached // Next frame time is frame count * refresh period (ms) * tick rate
auto RoundedDiv = [](uint32_t a, uint32_t b) { auto RoundedDiv = [](uint32_t a, uint32_t b) {
return ((a + (b / 2)) / b); return ((a + (b / 2)) / b);
}; };
TickType_t elapsedTarget = RoundedDiv((configTICK_RATE_HZ / 8) * alwaysOnTickCount * alwaysOnRefreshPeriod, 1000 / 8);
// RoundedDiv overflows when numerator + (denominator floordiv 2) > uint32 max // RoundedDiv overflows when numerator + (denominator floordiv 2) > uint32 max
// in this case around 9 hours // in this case around 9 hours (=overflow frame count / always on refresh period)
constexpr TickType_t overflowTick = (UINT32_MAX - (1000 / 16)) / ((configTICK_RATE_HZ / 8) * alwaysOnRefreshPeriod); constexpr TickType_t overflowFrameCount = (UINT32_MAX - (1000 / 16)) / ((configTICK_RATE_HZ / 8) * alwaysOnRefreshPeriod);
TickType_t ticksElapsed = xTaskGetTickCount() - alwaysOnStartTime;
// Divide both the numerator and denominator by 8 (=GCD(1000,1024))
// to increase the number of ticks (frames) before the overflow tick is reached
TickType_t targetRenderTick = RoundedDiv((configTICK_RATE_HZ / 8) * alwaysOnFrameCount * alwaysOnRefreshPeriod, 1000 / 8);
// Assumptions // Assumptions
@ -173,17 +178,17 @@ TickType_t DisplayApp::CalculateSleepTime() {
// Needed for division trick above // Needed for division trick above
static_assert(configTICK_RATE_HZ % 8 == 0); static_assert(configTICK_RATE_HZ % 8 == 0);
// Local tick count must always wraparound before the system tick count does // Frame count must always wraparound more often than 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) // 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); // Using 64bit ints here to avoid overflow
static_assert((uint64_t) overflowFrameCount * (uint64_t) alwaysOnRefreshPeriod < (uint64_t) UINT32_MAX * 1000ULL / configTICK_RATE_HZ);
if (alwaysOnTickCount == overflowTick) { if (alwaysOnFrameCount == overflowFrameCount) {
alwaysOnTickCount = 0; alwaysOnFrameCount = 0;
alwaysOnStartTime = xTaskGetTickCount(); alwaysOnStartTime = xTaskGetTickCount();
} }
if (elapsedTarget > ticksElapsed) { if (targetRenderTick > ticksElapsed) {
return elapsedTarget - ticksElapsed; return targetRenderTick - ticksElapsed;
} else { } else {
return 0; return 0;
} }
@ -240,7 +245,7 @@ void DisplayApp::Refresh() {
if (lv_task_handler() > 0) { if (lv_task_handler() > 0) {
// Drop frames that we've missed if drawing/event handling took way longer than expected // Drop frames that we've missed if drawing/event handling took way longer than expected
while (queueTimeout == 0) { while (queueTimeout == 0) {
alwaysOnTickCount += 1; alwaysOnFrameCount += 1;
queueTimeout = CalculateSleepTime(); queueTimeout = CalculateSleepTime();
} }
} }
@ -311,7 +316,7 @@ void DisplayApp::Refresh() {
if (msg == Messages::GoToAOD) { if (msg == Messages::GoToAOD) {
lcd.LowPowerOn(); lcd.LowPowerOn();
// Record idle entry time // Record idle entry time
alwaysOnTickCount = 0; alwaysOnFrameCount = 0;
alwaysOnStartTime = xTaskGetTickCount(); alwaysOnStartTime = xTaskGetTickCount();
PushMessageToSystemTask(Pinetime::System::Messages::OnDisplayTaskAOD); PushMessageToSystemTask(Pinetime::System::Messages::OnDisplayTaskAOD);
state = States::AOD; state = States::AOD;

View File

@ -139,7 +139,7 @@ namespace Pinetime {
bool isDimmed = false; bool isDimmed = false;
TickType_t CalculateSleepTime(); TickType_t CalculateSleepTime();
TickType_t alwaysOnTickCount; TickType_t alwaysOnFrameCount;
TickType_t alwaysOnStartTime; TickType_t alwaysOnStartTime;
// If this is to be changed, make sure the actual always on refresh rate is changed // If this is to be changed, make sure the actual always on refresh rate is changed
// by configuring the LCD refresh timings // by configuring the LCD refresh timings