Pulse Counting and question about TOV1

Hi Everyone,

I looked at Nick’s code for frequency calculation [ Frequency Counter sketch for Atmega328: Gammon Forum : Electronics : Microprocessors : Timers and counters] and I stumbled on this line of code

  // if just missed an overflow
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256)
    overflowCopy++;

I am bit confused about what that piece of code does. I understand that if there is an overflow after the ISR(TIMER2_COMPA_vect) has been called, then we increase one count, but I am not sure how the condition – ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256) - is satisfied if the above event has occurred. What does ((TIFR1 & bit (TOV1))) mean? What is the time evolution of bit(TOV1) value as compare match occurs at different time instant? Does it keep changing its value from 1 to 0 and 0 to 1 as each match occurs? I guess I am not sure about what “raising a flag” means?

Thanks
Bu

"The simplest mode of operation is the Normal mode (WGM13:0 = 0). In this mode the counting direction is always up (incrementing), and no counter clear is performed. The counter simply overruns when it passes its maximum 16-bit value (MAX = 0xFFFF) and then restarts from the BOTTOM (0x0000). In normal operation the Timer/Counter Overflow Flag (TOV1) will be set in the same timer clock cycle as the TCNT1 becomes zero. The TOV1 Flag in this case behaves like a 17th bit, except that it is only set, not cleared. However, combined with the timer overflow interrupt that automatically clears the TOV1 Flag, the timer resolution can be increased by soft- ware. There are no special cases to consider in the Normal mode, a new counter value can be written anytime."

I think the code means:

The timer has overflowed within the last 256 timer cycles.

Without seeing the rest of the code I can't tell but I assume the overflow flag gets manually reset somewhere or the overflow interrupt is enabled to auto-reset the overflow flag.

Thanks, John. I am attaching code from Nick’s website here, but I am not sure where TOV1 is getting reset manually. Would you kindly help?

Further, you said:

The TOV1 Flag in this case behaves like a 17th bit, except that it is only set, not cleared. However, combined with the timer overflow interrupt that automatically clears the TOV1 Flag, the timer resolution can be increased by soft- ware

Overflow interrupt occurs the same timer clock cycle as the TCNT1 becomes zero and TOV1 is also set to 1. But, you are saying it is also cleared at the same clock cycle ( I am assuming clearing a bit means setting it to 0). How can the same thing happen in the same clock cycle?

Best,
Bu

// Timer and Counter example
// Author: Nick Gammon
// Date: 17th January 2012

// Input: Pin D5

// these are checked for in the main program
volatile unsigned long timerCounts;
volatile boolean counterReady;

// internal to counting routine
unsigned long overflowCount;
unsigned int timerTicks;
unsigned int timerPeriod;

void startCounting (unsigned int ms) 
  {
  counterReady = false;         // time not up yet
  timerPeriod = ms;             // how many 1 mS counts to do
  timerTicks = 0;               // reset interrupt counter
  overflowCount = 0;            // no overflows yet

  // reset Timer 1 and Timer 2
  TCCR1A = 0;             
  TCCR1B = 0;              
  TCCR2A = 0;
  TCCR2B = 0;

  // Timer 1 - counts events on pin D5
  TIMSK1 = bit (TOIE1);   // interrupt on Timer 1 overflow

  // Timer 2 - gives us our 1 mS counting interval
  // 16 MHz clock (62.5 nS per tick) - prescaled by 128
  //  counter increments every 8 µS. 
  // So we count 125 of them, giving exactly 1000 µS (1 mS)
  TCCR2A = bit (WGM21) ;   // CTC mode
  OCR2A  = 124;            // count up to 125  (zero relative!!!!)

  // Timer 2 - interrupt on match (ie. every 1 mS)
  TIMSK2 = bit (OCIE2A);   // enable Timer2 Interrupt

  TCNT1 = 0;      // Both counters to zero
  TCNT2 = 0;     

  // Reset prescalers
  GTCCR = bit (PSRASY);        // reset prescaler now
  // start Timer 2
  TCCR2B =  bit (CS20) | bit (CS22) ;  // prescaler of 128
  // start Timer 1
  // External clock source on T1 pin (D5). Clock on rising edge.
  TCCR1B =  bit (CS10) | bit (CS11) | bit (CS12);
  }  // end of startCounting

ISR (TIMER1_OVF_vect)
  {
  ++overflowCount;               // count number of Counter1 overflows  
  }  // end of TIMER1_OVF_vect


//******************************************************************
//  Timer2 Interrupt Service is invoked by hardware Timer 2 every 1ms = 1000 Hz
//  16Mhz / 128 / 125 = 1000 Hz

ISR (TIMER2_COMPA_vect) 
  {
  // grab counter value before it changes any more
  unsigned int timer1CounterValue;
  timer1CounterValue = TCNT1;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;

  // see if we have reached timing period
  if (++timerTicks < timerPeriod) 
    return;  // not yet

  // if just missed an overflow
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256)
    overflowCopy++;

  // end of gate time, measurement ready

  TCCR1A = 0;    // stop timer 1
  TCCR1B = 0;    

  TCCR2A = 0;    // stop timer 2
  TCCR2B = 0;    

  TIMSK1 = 0;    // disable Timer1 Interrupt
  TIMSK2 = 0;    // disable Timer2 Interrupt
    
  // calculate total count
  timerCounts = (overflowCopy << 16) + timer1CounterValue;  // each overflow is 65536 more
  counterReady = true;              // set global flag for end count period
  }  // end of TIMER2_COMPA_vect

void setup () 
  {
  Serial.begin(115200);       
  Serial.println("Frequency Counter");
  } // end of setup

void loop () 
  {
  // stop Timer 0 interrupts from throwing the count out
  byte oldTCCR0A = TCCR0A;
  byte oldTCCR0B = TCCR0B;
  TCCR0A = 0;    // stop timer 0
  TCCR0B = 0;    
  
  startCounting (500);  // how many mS to count for

  while (!counterReady) 
     { }  // loop until count over

  // adjust counts by counting interval to give frequency in Hz
  float frq = (timerCounts *  1000.0) / timerPeriod;

  Serial.print ("Frequency: ");
  Serial.print ((unsigned long) frq);
  Serial.println (" Hz.");
  
  // restart timer 0
  TCCR0A = oldTCCR0A;
  TCCR0B = oldTCCR0B;
  
  // let serial stuff finish
  delay(200);
  }   // end of loop

When the Timer2 interrupt is being processed, all other interrupts are temporarily disabled. In the Timer2 ISR a copy is made of the Counter1 overflow count. The check you are wondering about increments the copy if there is a Counter1 overflow pending but disabled due to the Timer2 ISR in progress. After the Timer2 ISR completes, the Counter1 ISR will be executed and the overflow flag will be cleared. The datasheet should say when the flag gets cleared. I think it is when control is passed to the overflow ISR.

johnwasser: When the Timer2 interrupt is being processed, all other interrupts are temporarily disabled. In the Timer2 ISR a copy is made of the Counter1 overflow count. The check you are wondering about increments the copy if there is a Counter1 overflow pending but disabled due to the Timer2 ISR in progress. After the Timer2 ISR completes, the Counter1 ISR will be executed and the overflow flag will be cleared. The datasheet should say when the flag gets cleared. I think it is when control is passed to the overflow ISR.

Thank you John, (and Bogaboo, because I’m also trying to use this useful sketch; have you got answer from Nick’s website?).

But if the flag is cleared, why Nick thought an overflow could be missed and so TOV1 will remain 1?

(In overflows TOV1 = 1 automatically, and TOV1 => 0 when interrupt fires; and I think that in this sketch all interrupts are “first type”):

In ATmega (48 – 328) datasheet we read:

(pag 14) There are basically two types of interrupts. The first type is triggered by an event that sets the Interrupt Flag. For these interrupts, the Program Counter is vectored to the actual Interrupt Vector in order to execute the interrupt handling routine, and hardware clears the corresponding Interrupt Flag. Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s) to be cleared. If an interrupt condition occurs while the corresponding interrupt enable bit is cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the flag is cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt Enable bit is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the Global Interrupt Enable bit is set, and will then be executed by order of priority.

The second type of interrupts will trigger as long as the interrupt condition is present. These interrupts do not necessarily have Interrupt Flags. If the interrupt condition disappears before the interrupt is enabled, the interrupt will not be trigger

(pag 123): In normal operation the Timer/Counter Overflow Flag (TOV1) will be set in the same timer clock cycle as the TCNT1 becomes zero. And, timer overflow interrupt automatically clears the TOV1 Flag

(pag 137): In Normal and CTC modes, the TOV1 Flag is set when the timer overflows. TOV1 is automatically cleared when the Timer/Counter1 Overflow Interrupt Vector is executed.

• Bit 0 (of TIMSK1) – TOIE1: Timer/Counter1, Overflow Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Overflow interrupt is enabled. The corresponding Interrupt Vector is executed when the TOV1 Flag, located in TIFR1, is set.

ISR (TIMER2_COMPA_vect) 
  {
  unsigned long overflowCopy = overflowCount;

  // if just missed an overflow
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256)
    overflowCopy++;
  }  // end of TIMER2_COMPA_vect

As you can see, the code you were asking about is in the TIMER2_COMPA ISR. Because it is in an ISR it is being executed with the Global Interrupt Enable flag cleared (that flag will be restored to its previous state [set] when the TIMER2_COMPA ISR returns). Since the Global Interrupt Enable is cleared the TIMER1_OVF ISR will not be executed even if Timer1 overflows. That would mean that the Timer1 counter has gone past 0xFFFF and wrapped around to 0x0000 without the overflowCount being incremented (yet). This leaves the overflowCounter low by 1 which would cause an error of 65,536 in the total count.

The code checks for a pending Timer1 Overflow interrupt that is being held back by the Global Interrupt Enable being cleared during the TIMER2_COMPA ISR. Since it already has a copy of TCNT1 (the Timer1 Counter register) it can tell from the fact that TCNT1 is low (<256) and the Timer1 Overflow flag is set that the overflowCount will be incremented in the TIMER1_OVF ISR shortly after the TIMER2_COMPA ISR returns.