Framerate Timing
I’ve been trying to track down an annoying timing issue in my main loop.
My target is 20 frames/second (capped), which means 50ms between frames. I start a 50ms countdown timer at the beginning of the main loop, then process messages in a tight loop until the timer expires. When time’s up, I process events tied to the framerate once, then reset the timer and go back to processing messages. The problem is that the message processing is periodically skipped.
;; ----------------------------------------------
;; void Ifos.main()
;;
;; Main execution loop. This routine cycles endlessly, updating the state of
;; the application and responding to external events.
;;
Ifos.main:
; See if a new message has arrived.
movlw Modbus.kState_MsgQueued
cpfseq Modbus.State ; is a MODBUS message waiting for us?
bra doWork ; no, do normal stuff
; We received a message, so do something with it.
SetTableBase Modbus.VTable ; point to virtual function table
call Modbus.dispatchMsg ; process message and build reply
call Modbus.replyMsg ; send reply
doWork:
; See if we've entered a vertical blank.
call Clock.isAwake ; has 50ms elapsed?
bnc Ifos.main ; no, go check for incoming messages again
;-------------------------------------
; do useful stuff here
;-------------------------------------
; Reset the vertical blank timer.
btg PORTA, RA3 ; toggle I/O for debugging
SetAlarmMS 50
bra Ifos.main
To aid debugging, I replaced the frame event processing with a simple I/O toggle of RA3, producing a straightforward trace (not to scale):
It’s clear something is shortening the cycle on a regular basis (red lines). The actual number of pulses between each pair of red lines is about 22—close enough to 20 to seem significant, except that the total time is greater than 1s. I might expect it to be less, if the code were trying to ensure a minimum of 20fps, but it’s written to cap the framerate, instead.
It’s particularly strange since the timer is reset relative to when it expires, not some fixed beat. That is, when the timer hits zero, it’s reset to 50, not 50 minus the time spent processing messages.
I’ve been looking at this for a while and not making much progress. I started down this path trying to debug a different problem (something wonky in the message handling state machine), but that’s obviously going nowhere. My only thought is that the timeout comparison is sketchy… I need to investigate actual countdown values to see if they appear suspicious.