MultiTrack (Advanced): Accuracy of SuperTimers
The SuperTimer mechanism has been designed to avoid problems of cumulative timing errors due to program latency when using MultiTrack.
The following program illustrates the point. If you run this in an MMi201 (or earlier) as it is, the 1 second flasher will manage just 58 flashes in a minute. In a more recent controller this will become closer to 59 flashes, because the processor is faster. By comparison, if you remove the very first line and let Flash1S run as a MultiTrack task, the flasher produces as close to 60 flashes per second as can reasonably checked with a watch.
(Click here for some tips for working around problems with copy and paste out of Internet Explorer and HTML-help (.chm) files)
GoTo Flash1S
LaunchTask Flash1S
RunTasksForever
Flash1S
On 7
GoSub SlowIt
Pause 5
Off 7
fRecallW fCounter
fInc
fStore fCounter
OBLCD_SetCur 0,0
OBLCD_fDispW 5,0
Pause 95
GoTo Flash1S
SlowIt
fLoadW 1.111111
fLoadQ 0.00001
SetMem Counter,100
SAA1
fAdd
DMGNZ Counter,SAA1
Return
Counter defBYTE
fCounter defFLOAT
So, what is happening????
The subroutine SlowIt has been designed simply to waste time, about 40mS in an MMi201. If Flash1S is run outside the MultiTrack task queue, that 40mS adds directly to the 50mS generated by Pause 5, giving a total output ON time of 90mS. So, instead of 1000mS total period we get 1040mS, or 57.6 flashes per minute.
When we change the program so Flash1S is a MultiTrack task, our super timer magic comes into effect. The SuperTimer is generated via a system timer that counts up 10mS ticks. That timer runs all the time, and is used for any timing outside the task queue. Inside the task queue, however, it is different. Each time the task queue is to be run, the system timer is copied to a separate buffer register, and that same, static value is used for all SuperTimer calculations. It is as if time stands still during each run of the task queue. It then jumps forward at the start of the next run, when the buffer register is again updated from the system timer. When the Pause 5 is first encountered the termination time is calculated starting from the time captured in the buffer.
This scheme would fail to work if subroutine SlowIt took more than 50mS, because SlowIt won’t complete until after the Pause 5 should have completed.