CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Accurate timer interrupt programming

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
chaertl1



Joined: 17 Aug 2009
Posts: 9

View user's profile Send private message

Accurate timer interrupt programming
PostPosted: Mon Aug 17, 2009 6:15 am     Reply with quote

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

View user's profile Send private message

Re: Accurate timer interrupt programming
PostPosted: Mon Aug 17, 2009 7:09 am     Reply with quote

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:
Code:
set_timer0(100);
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

View user's profile Send private message AIM Address

and there is old dependable
PostPosted: Mon Aug 17, 2009 9:34 am     Reply with quote

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







PostPosted: Mon Aug 17, 2009 9:50 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Aug 17, 2009 12:08 pm     Reply with quote

@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

View user's profile Send private message

PostPosted: Mon Aug 17, 2009 1:48 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Aug 18, 2009 10:55 pm     Reply with quote

Is it possible to prevent the compiler to implement its own interrupt code.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Aug 19, 2009 12:16 am     Reply with quote

yes, use #int_global.
John P



Joined: 17 Sep 2003
Posts: 331

View user's profile Send private message

PostPosted: Wed Aug 19, 2009 7:47 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group