Improve sleep time calculation docs
This commit is contained in:
parent
771008495e
commit
06b721a71f
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user