View previous topic :: View next topic |
Author |
Message |
chaertl1
Joined: 17 Aug 2009 Posts: 9
|
Accurate timer interrupt programming |
Posted: Mon Aug 17, 2009 6:15 am |
|
|
HI,
I discovered a problem, nobody explained in this forum.
If you need an interrupt frequency of 6400Hz at 4Mhz clock frequency,
someone might get in trouble with the accuracy of the interrupt.
Ok, let's start.
Code: |
Clock CLK = 4Mhz
Effective clock CLKeff = CLK/4 = 4000000Hz/4 = 1000000Hz
Desired interrupts per sec INTfreq = 6400
Time between interrrupt Tint = CLKeff/INTfreq = 1000000Hz/6400Hz = 156,25 us
instruction exec time Tinstr = 1/CLKeff = 1s/1000000Hz = 1us
That means that there are 156 timer clocks between two interrupts, what results in a timer prescaler of '1' because 156 < 256
Timer prescaler DIV_TMR = 1
Timer clock CLKtmr = CLKeff/DIV_TMR = 1000000Hz
The trick is the presetting the timer to the needed value to get our 6400Hz interrupt frequency
If the timer is initialized to 0 (also after an overflow) we have to count 256 instruction
cycles until the interrupt is fired.
But this is to slow for our 6400Hz interrupt frequency:
INTfreq = CLKeff/256 = 1000000Hz/256 = 3906,25Hz
So everybody would initialize the timer with the presetValue:
Vpreset = 256-156 = 100
That means the timer overflows after 156 instructions what results in an interrupt
frequency of:
INTfreq = CLKeff/156 = 1000000Hz/156 = 6410,25Hz
But you also need to initialize the timer at the beginning of your interrupt service routine.
#int_rtcc
isr() {
set_timer0(100);
}
There comes the problem:
The compiler adds code for the interrupt handling at the start of your program.
The time needed from the timer overflow until the set_timer0() function is executed
is 35us in my setup (PIC 12F629@4Mhz) that means 35 clocks at the timer.
So we have to substract that time from our Vpreset:
Vpreset = 256-(156us-35us)
I don't know if the interrupt handling code generated by the compiler is allways of the same legth,
But my setup is working fine with that calculations.
|
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
Re: Accurate timer interrupt programming |
Posted: Mon Aug 17, 2009 7:09 am |
|
|
chaertl1 wrote: | I discovered a problem, nobody explained in this forum. | You are discussing the timer accuracy problems caused by interrupt overhead. The solution you propose is a standard programming technique used on the PIC processors and mentioned in every good book on the PIC processors. The reason for you not finding it mentioned in the forum is because you did not search good enough.
Here is a four year old thread discussing the same problem: http://www.ccsinfo.com/forum/viewtopic.php?t=21573
A better technique is proposed there. Instead of: use Code: | set_timer0( get_timer0() + 100); | This solves the problems introduced by variable delays when multiple interrupts are enabled.
Still better is to use Timer2 which has a hardware preset register. Saves the interrupt processing overhead and is even more accurate. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
and there is old dependable |
Posted: Mon Aug 17, 2009 9:34 am |
|
|
If all you need is timing repeatability- ie taking the int at a precise leading
edge interval ( but not neccessarly your ideal frequency)
- pick the nearest prescalar to the 'tick' interval you want - and just let the timer roll over - and all you do is reset the timer INT flag for the next time.
I have several apps implementing a DDS ( frequency synthesis not dentistry) where I use the timer0 to generate marks for another DDS signal being counted by timer1 - and convenient rollover timer0 tick is 8.192ms - then I just clean up my long period value from timer1 for a final frequency measuerment with a snippet of floating point math.
If you don't need an EXACT freq, but rather an exact repeated INTERVAL -
/freq for some counting or gating purpose - relativity and FP correction can be quite satisfactory.
Last edited by asmboy on Mon Aug 17, 2009 10:00 am; edited 1 time in total |
|
|
Ttelmah Guest
|
|
Posted: Mon Aug 17, 2009 9:50 am |
|
|
It is also worth doing a search here about 'RTC' programming, and in particular the 'integer' solution from Neutone originally. With this, you use integer maths, to give the required final accurate results, by allowing the arithmetic to maintain a 'rollover'.
For _real_ accuracy, the timer2 approach, or letting the clock rollover on it's own will always be the most accurate. Unfortunately, manually setting the timer, even by adding a value, has the problem that it always resets the prescaler as well. The entry time into an interrupt, has a small variabilty in the hardware, even if nothing else is going on, since the interrupt response occurs in phase one, of the instruction following the event. Jumps etc., are two instruction times long, while 90% of instructions are only one instruction time long. As a result, even with perfect code, if there are any jump in the external code, there _will_ be variation in the response time, and the effect on the prescaler in the handler...
Best Wishes |
|
|
chaertl1
Joined: 17 Aug 2009 Posts: 9
|
|
Posted: Mon Aug 17, 2009 12:08 pm |
|
|
@ckielstra
the set_timer_x(get_timer_X + Y) is only possible if you are not to close to
the rollover point (256). |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Aug 17, 2009 1:48 pm |
|
|
chaertl1 wrote: | @ckielstra
the set_timer_x(get_timer_X + Y) is only possible if you are not to close to
the rollover point (256). | If this poses a problem, then there is a serious timing problem and the interrupt frequency should be lowered.
Again, Timer2 does not have these problems.
In the end all mentioned solutions have their strong and weak points and should all be considered in view of your application. |
|
|
chaertl1
Joined: 17 Aug 2009 Posts: 9
|
|
Posted: Tue Aug 18, 2009 10:55 pm |
|
|
Is it possible to prevent the compiler to implement its own interrupt code. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Aug 19, 2009 12:16 am |
|
|
yes, use #int_global. |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Wed Aug 19, 2009 7:47 am |
|
|
Just be aware that use of #int_global needs to be done with great care, and an understanding of the workings of your processor, and your program. I've done it, but it certainly led to some headaches. |
|
|
|