# [SOLVED] precisely all 20 ms an interrupt - is this possible?

In the thread http://arduino.cc/forum/index.php/topic,97610.msg732311.html a generel solution for getting an timer based interrupt was given:

``````volatile boolean fired = false;

void setup()
{
// CTC mode with clk/8 prescaler
TCCR1A = 0;
TCCR1B = 1<<WGM12 | 1<<CS11;

TCNT1 = 0;         // reset counter
OCR1A =  39999;       // compare A register value
TIFR1 |= _BV (OCF1A);    // clear interrupt flag
TIMSK1 = _BV (OCIE1A);   // interrupt on Compare A Match
}

ISR (TIMER1_COMPA_vect)
{
fired = true;
TIFR1 = 1<<OCF1A;     // clear the Output Compare A Match Flag
}

void loop()
{
while (! fired) { }  // waits for the next timer interrupt
fired=false;         // clears the timer interrupt marker
// ... do stuff here
}
``````

This code indeed gives precisely all 20000 * 16 ticks a goo. But the ticks are not 1/16 us, as mentioned at other occassions already. Especially it was stated, that the millis() call has extra code to compensate for that.

So my question is, how one can achieve a real 20 ms goo. If lucky, we just have to change the 39999 to “something”, but maybe the solution is to set it to 43123 in general, but each seventh time to 43128, just to give an example.

So if one has figured out this thing already, please let me know!

The timer is driven by the system clock which is in most cases very accurate. What people mean is the code for micros() where we have to take into account the clock cycles needed to add two (long) integers. This code is approximatively as exact as you clock source is.

pylon: What people mean is the code for micros() where we have to take into account the clock cycles needed to add two (long) integers.

Really? The code shown above has 50 goos in around 0.9 seconds, so it is around 10% too fast. I thought the so called 16 MHz were actually around 10% off (of couse very preceice somehow 10 %).

How can it be then?

``````ISR (TIMER1_COMPA_vect)
{
fired = true;
//  TIFR1 = 1<<OCF1A;     // <<<<<<<<< REMOVE THIS LINE.  IT SERVES NO PURPOSE. <<<<<<<<<
}
``````

Thomas33:
This code indeed gives precisely all 20000 * 16 ticks a goo.

If that is true your processor is badly damaged and needs to be replaced (or the crystal is the wrong frequency or there is a design mistake). As the code is written, fired is set true every 20 milliseconds for a processor running at 16 MHz.

So my question is, how one can achieve a real 20 ms goo.

The code you posted does exactly that.

[quote author=Coding Badly link=topic=104871.msg786533#msg786533 date=1336419542] The code you posted does exactly that. [/quote]

I just played around with that 39999, and the results were a bit suspicious. In the "do stuff here" part I do ethernet stuff. Can it be, that the ethernet (w5100) is using timer 1 too?

Thomas33: Can it be, that the ethernet (w5100) is using timer 1 too?

I don't know. Someone else will have to answer that question.

Oh my - I had a "bug" in my counting part. (I counted the arrived ethernet packets, but always got some "empty" packets too.) Now it looks much better:

======================= Heartbeat 0 at 0.002 sec ======================= Heartbeat 500 at 9.968 sec ======================= Heartbeat 1000 at 19.977 sec ======================= Heartbeat 1500 at 29.986 sec ======================= Heartbeat 2000 at 39.994 sec ======================= Heartbeat 2500 at 50.002 sec ======================= Heartbeat 3000 at 60.011 sec ======================= Heartbeat 3500 at 70.019 sec ======================= Heartbeat 4000 at 80.028 sec ======================= Heartbeat 4500 at 90.037 sec ======================= Heartbeat 5000 at 100.045 sec ======================= Heartbeat 5500 at 110.054 sec ======================= Heartbeat 6000 at 120.063 sec ======================= Heartbeat 6500 at 130.071 sec ======================= Heartbeat 7000 at 140.080 sec

I think the remaining drift is within usual tolerance, hmm?

If you are using a board with a resonator (like an Uno) then...

(((140.08000 - 130.07100) - 10) / 10) * 100 = 0.09

...0.09% error is very low. (and I'm jealous. I think my Uno has about a 1% error.)

If you are using a board with a crystal (like a Duemilanove) then 0.09% error is high.

I have a mega2560. I think it is with crystal (the truth is hidden by the ethernet shield #-) )
However, this shall be good enough for my purpose.

Most of all: Thanks for sharing thoughts on this. Dragging me away from the believe, that it is not 16.000 MHz by design, was the push I needed! I’ll mark it as solved