1 out of 1 members found this post helpful.
Did you find this post helpful?

|
Re: Elapsed Timer findings
I would like to provide a follow up to the discussion in this thread regarding Darrel Taylor's Elapsed Timer demo application.
The Elasped Timer demo we are speaking of is a project that Darrel had posted here and on his website.
The Project was called Elapsed_Demo.bas (code dated Jan 10, 2006) and also had the following include files.
INCLUDE "DT_INTS-14.bas"
INCLUDE "ReEnterPBP.bas"
INCLUDE "Elapsed_INT.bas"
The issue is within the "Elapsed_INT.bas" include file where Darrel provided hard-coded values for the "TimerConst" variable for Oscillator rates of 4/8/10/16/20 MHz.
It is these hard-coded values that are incorrect.
Code:
Relevant section of Elapsed_INT.bas:
Asm
IF OSC == 4 ; Constants for 100hz interrupt from Timer1
TimerConst = 0D8F7h ; Executed at compile time only
EndIF
If OSC == 8
TimerConst = 0B1E7h
EndIF
If OSC == 10
TimerConst = 09E5Fh
EndIF
If OSC == 16
TimerConst = 063C7h
EndIF
If OSC == 20
TimerConst = 03CB7h
EndIF
As Art had pointed out a little earlier in this thread, and we have confirmed through code review and testing, Darrel's hard-coded values he used for the Timer1 Preload values (TimerConst) for a 10ms (100Hz) Interrupt were incorrect.
The value he used for each of the Oscillator rates is (1) less than it should be.
The reason is that he calculated the Timer1 counter overflow value as 65535 instead of using 65536.
Timer1 is a 16bit counter from 0 to 65535.
It takes 65536 counts to overflow (Wrap back to 0) and trigger the Timer1 interrupt.
This means that his 10ms interrupt will actually run longer by (1) instruction than it should.
As an example of the wrong value used, for a 4MHz Oscillator rate the interrupt will fire at 10ms + 1 instruction cycle (1us).
Darrel's Preload value (TimerConst) was hard-coded to 0D8F7h (55543 dec), which is incorrect and it should be 0DF8h (55544 dec)
For those interested, here is the math.
When using a Timer1 Interrupt without any prescale or postscale values, Timer1's counter will increment by 1 for each instruction executed.
Each instruction takes (1 / (Fosc / 4)) amount of time.
So for a 4Mhz Oscillator rate, 1 instruction cycle (Tcy) = 1 / (4000000 / 4) = 1 / 1000000 = .000001 seconds (1us).
Darrel calculated the preload value (number to preset the counter to) this way.
Tpl = 65535 - (It / (1 / (Fosc / 4)) - Tric)
Where:
Tpl = Timer Preload value
65535 = Timer1 Counter Overflow value (Which is wrong, should be 65536)
Fosc = OSC Frequency
It = Target Interrupt Time
Tric = Timer Reload Instruction Cycles
So for the 4MHz Oscillator rate example:
Tpl = 65535 - (.01 / (1 / (4000000 / 4)) - 8)
Tpl = 65535 - (.01 / (1 / (1000000)) -8)
Tpl = 65535 - (.01 / (.000001) - 8)
Tpl = 65535 - (10000 – 8)
Tpl = 65535 - 9992
Tpl = 55543 (D8F7h)
This will load 55543 into Timer1's counter.
Now how many counts does it take for Timer1 to overflow from here?
If your target is a 10ms interrupt and the Instruction Cycle time is 1us, then you want it to count exactly 10000 instructions including the instructions it uses when it reloads the Timer preset (which the code does in 8 instructions).
So starting at 55543 + (10000-8) = 55543 + 9992 = 65535
Timer1's counter is now at 65535 and it will not overflow until 1 more instruction occurs.
So this 4MHz example shows that the Timer1 interrupt will fire at 10.001ms not 10ms.
Even though the error is just 1 instruction cycle, the timing impact could be significant.
The timing error is inversely proportional to the Oscillator rate.
The slower the Oscillator rate, the worse the timing will be off.
And as Art pointed out the error is cumulative.
Every time the interrupt fires, 1 extra instruction is executed, so if the interrupt fires 10 times the total elapsed time for the 4MHz example would be 10.010ms instead of the correct 10ms.
I hope this clarifies Art's observations and our subsequent findings.
Last edited by Tabsoft; - 20th May 2015 at 14:45.
Reason: Grammatical Issue
Regards,
TABSoft
Bookmarks