I'm trying to understand how to set up an overflow interrupt on ATmega328 TIMER1 to measure a frequency.

I'm feeding pin PD4, which is where TIMER1 is externally clocked, with a 503kHz square wave (4.8Vpp).

Given that TIMER1 is 16 bit, I would assume that it would overflow 7 times every second. My reasoning is the following:

$$ number\;of\;overflows = \frac{f}{TIMER1\;max\;count} = \frac{503,000Hz}{65,536} = 7.67$$

However, my program counts 988 overflows instead. That's 128 times more than I expected. Why??

I'm using the following code:

volatile unsigned long int running;

ISR(TIMER1_OVF_vect) {

void setup()

  // set up the 16 bit timer as an external frequency counter:
  TCCR1B |= (1 << CS10)|(1 << CS11)|(1 << CS12); // External clock, rising edge
  TIMSK1 |= (1 << TOIE1); // Enable overflow interrupt

  sei();  // enable global interrupts

void loop() {
  running = 0;
  delay(1000); // wait 1000ms

Below is the external clock signal on the scope:

External clock scope shot

The schematic I'm using is this one below. The inductor is 220uH instead of 68uH.


  • 2
    \$\begingroup\$ I'm guessing you absolutely need to clear a flag in the interrupt routine. Plus I'm not sure that delay(1000) will wait exactly 1s... That's the flag thing though. \$\endgroup\$ – Vladimir Cravero Aug 15 '14 at 18:05
  • \$\begingroup\$ Is the chip programmed with a bootloader? \$\endgroup\$ – Ignacio Vazquez-Abrams Aug 15 '14 at 18:24
  • \$\begingroup\$ Be sure you have defined F_CPU, otherwise the compiler will default to 1MHz for use with delay. It looks like you are mixing AVRgcc with Arduino API. Try using _delay_ms(1000), which is the inline implementation given in the AVR header file delay.h. The Arduino implementation probably just calls this routine anyway, however. \$\endgroup\$ – sherrellbc Aug 15 '14 at 18:33
  • \$\begingroup\$ @Ignacio yes, it's got an Arduino Uno bootloader (optiboot I suppose). \$\endgroup\$ – Ricardo Aug 15 '14 at 19:04
  • 1
    \$\begingroup\$ Check out Table 16-4 in the datasheet for your micro, and make sure you are in Normal mode. Otherwise, the overflow flag could be triggering for other reasons. \$\endgroup\$ – Mewa Aug 15 '14 at 20:37

As per page 140 of the datasheet the flag that must be cleared is called \$\mathtt{TOV1}\$ and is the LSB of the register \$\mathtt{TIFR1}\$. That bit should be cleared automatically but that feature might be disabled to use nested interrupts, which seems the case to me. I would have expected an higher value for running, but that's an int and might well be 8 bit wide, so it's overflowing like crazy (that's even signed!).

Try adding this line as the first thing in your overflow ISR:

TIFR1 &= 0x01;

Maybe something like:

TIFR1 &= 1 << TOV1;

will work too, but who knows? You should dive into headers. Try the first solution, that should work.

  • \$\begingroup\$ Tried both lines, but didn't work. It turns out that the problem was something else. Somehow TCCR1A comes set to 0x01 instead of 0x00 in my setup. See my own answer below for more details. Thanks for the effort and for digging into the datasheet, though! +1 \$\endgroup\$ – Ricardo Aug 15 '14 at 22:47

Thanks to Mewa's comment, which I copy below, I found what the problem was.

Check out Table 16-4 in the datasheet for your micro, and make sure you are in Normal mode. Otherwise, the overflow flag could be triggering for other reasons.

Somehow, in my programming environment, the TCCR1A is set initially to 1 and not to 0 as I assumed.

I verified and fixed the issue with the following lines:

  Serial.println(TCCR1A); // <- this line outputs 1
  TCCR1A = 0; // <- this line fixed the problem - I now get 7 to 8 overflows per second
  TCCR1B |= (1 << CS10)|(1 << CS11)|(1 << CS12); 
  TIMSK1 |= (1 << TOIE1);

If I understand it correctly, that means that bit WGM10 as set to 1, setting my TIMER1 to Mode 1 (PWM, Phase Correct, 8-bit) instead of the intended Mode 0 (Normal). The result was that the timer was overflowing at 511 and not 65535 as I assumed.

Thanks to all of you who helped me figure this one out!

  • 1
    \$\begingroup\$ And that's why I alsways set all the bits I need, also if on reset they should be as I like. \$\endgroup\$ – Vladimir Cravero Aug 15 '14 at 22:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.