@@ -157,33 +157,38 @@ void DisplayApp::InitHw() {
157157}
158158
159159TickType_t DisplayApp::CalculateSleepTime () {
160- TickType_t ticksElapsed = xTaskGetTickCount () - alwaysOnStartTime;
161- // Divide both the numerator and denominator by 8 to increase the number of ticks (frames) before the overflow tick is reached
160+ // Calculates how many system ticks DisplayApp should sleep before rendering the next AOD frame
161+ // Next frame time is frame count * refresh period (ms) * tick rate
162+
162163 auto RoundedDiv = [](uint32_t a, uint32_t b) {
163164 return ((a + (b / 2 )) / b);
164165 };
165- TickType_t elapsedTarget = RoundedDiv ((configTICK_RATE_HZ / 8 ) * alwaysOnTickCount * alwaysOnRefreshPeriod, 1000 / 8 );
166166 // RoundedDiv overflows when numerator + (denominator floordiv 2) > uint32 max
167- // in this case around 9 hours
168- constexpr TickType_t overflowTick = (UINT32_MAX - (1000 / 16 )) / ((configTICK_RATE_HZ / 8 ) * alwaysOnRefreshPeriod);
167+ // in this case around 9 hours (=overflow frame count / always on refresh period)
168+ constexpr TickType_t overflowFrameCount = (UINT32_MAX - (1000 / 16 )) / ((configTICK_RATE_HZ / 8 ) * alwaysOnRefreshPeriod);
169+
170+ TickType_t ticksElapsed = xTaskGetTickCount () - alwaysOnStartTime;
171+ // Divide both the numerator and denominator by 8 (=GCD(1000,1024))
172+ // to increase the number of ticks (frames) before the overflow tick is reached
173+ TickType_t targetRenderTick = RoundedDiv ((configTICK_RATE_HZ / 8 ) * alwaysOnFrameCount * alwaysOnRefreshPeriod, 1000 / 8 );
169174
170175 // Assumptions
171176
172177 // Tick rate is multiple of 8
173178 // Needed for division trick above
174179 static_assert (configTICK_RATE_HZ % 8 == 0 );
175180
176- // Local tick count must always wraparound before the system tick count does
177- // As a static assert we can use 64 bit ints and therefore dodge overflows
181+ // Frame count must always wraparound more often than the system tick count does
178182 // Always on overflow time (ms) < system tick overflow time (ms)
179- static_assert ((uint64_t ) overflowTick * (uint64_t ) alwaysOnRefreshPeriod < (uint64_t ) UINT32_MAX * 1000ULL / configTICK_RATE_HZ);
183+ // Using 64bit ints here to avoid overflow
184+ static_assert ((uint64_t ) overflowFrameCount * (uint64_t ) alwaysOnRefreshPeriod < (uint64_t ) UINT32_MAX * 1000ULL / configTICK_RATE_HZ);
180185
181- if (alwaysOnTickCount == overflowTick ) {
182- alwaysOnTickCount = 0 ;
186+ if (alwaysOnFrameCount == overflowFrameCount ) {
187+ alwaysOnFrameCount = 0 ;
183188 alwaysOnStartTime = xTaskGetTickCount ();
184189 }
185- if (elapsedTarget > ticksElapsed) {
186- return elapsedTarget - ticksElapsed;
190+ if (targetRenderTick > ticksElapsed) {
191+ return targetRenderTick - ticksElapsed;
187192 } else {
188193 return 0 ;
189194 }
@@ -240,7 +245,7 @@ void DisplayApp::Refresh() {
240245 if (lv_task_handler () > 0 ) {
241246 // Drop frames that we've missed if drawing/event handling took way longer than expected
242247 while (queueTimeout == 0 ) {
243- alwaysOnTickCount += 1 ;
248+ alwaysOnFrameCount += 1 ;
244249 queueTimeout = CalculateSleepTime ();
245250 }
246251 }
@@ -311,7 +316,7 @@ void DisplayApp::Refresh() {
311316 if (msg == Messages::GoToAOD) {
312317 lcd.LowPowerOn ();
313318 // Record idle entry time
314- alwaysOnTickCount = 0 ;
319+ alwaysOnFrameCount = 0 ;
315320 alwaysOnStartTime = xTaskGetTickCount ();
316321 PushMessageToSystemTask (Pinetime::System::Messages::OnDisplayTaskAOD);
317322 state = States::AOD;
0 commit comments