Input Capture using T4 stops working after a few seconds

Hi fellow developers,

I'm using and Arduino Mega 2560 and I'm attempting to measure a signal period using timer 4 in input capture mode.

I'm using an example from Nick Gammon as a base that I have altered.
(example found here : Gammon Forum : Electronics : Microprocessors : Timers and counters)

Things that I changed:
Example was meant for timer 1 I switch the registers to use the ones for timer 4.
I created my own simple square wave generation for testing (could be the culprit)
Added a simple counter to see how many period are gathered successfully.

Hardware: I have D47 and D49 connected together and I have a logic analyzer snooping the signal to compare the actual period of the signal.

So my problem is that the code is working at first, but after around 2-3 seconds it seems that the interrupt vector TIMER4_CAPT_vect stops being raised but, the code is not stuck. Interrupt TIMER4_OVF_vect is still being raised (I checked with a global counter being print in the main loop) and the main loop is still executing. Performing a reset makes the code working again for a similar amount of time (as expected).

Here is the code:

void setup() 
{
  pinMode(47, OUTPUT);
 
  Serial3.begin(115200); 
  prepareForInterrupts ();
  Serial3.print ("Starting test");
}

volatile boolean first;
volatile boolean triggered;
volatile unsigned long overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;
volatile uint16_t TimerCaptCounter = 0;

// timer overflows (every 65536 counts)
ISR (TIMER4_OVF_vect) 
{
  overflowCount++;
}  // end of TIMER4_OVF_vect

ISR (TIMER4_CAPT_vect)
{
  TimerCaptCounter ++;
  // grab counter value before it changes any more
  unsigned int timer4CounterValue;
  timer4CounterValue = ICR4;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;
  
  // if just missed an overflow
  if ((TIFR4 & bit (TOV4)) && timer4CounterValue < 0x7FFF)
    overflowCopy++;
  
  // wait until we noticed last one
  if (triggered)
    return;

  if (first)
  {
    startTime = (overflowCopy << 16) + timer4CounterValue;
    first = false;
    return;  
  }
    
  finishTime = (overflowCopy << 16) + timer4CounterValue;
  triggered = true;
  TIMSK4 = 0;    // no more interrupts for now
}  // end of TIMER4_CAPT_vect
  
void prepareForInterrupts ()
{
  noInterrupts ();  // protected code
  first = true;
  triggered = false;  // re-arm for next time
  // reset Timer 4
  TCCR4A = 0;
  TCCR4B = 0;
  
  TIFR4 = bit (ICF4) | bit (TOV4);  // clear flags so we don't get a bogus interrupt
  TCNT4 = 0;          // Counter to zero
  overflowCount = 0;  // Therefore no overflows yet
  
  // Timer 4 - counts clock pulses
  TIMSK4 = bit (TOIE4) | bit (ICIE4);   // interrupt on Timer 4 overflow and input capture
  // start Timer 4, no prescaler
  TCCR4B =  bit (CS40) | bit (ICES4);  // plus Input Capture Edge Select (rising on D8)
  interrupts ();
}  // end of prepareForInterrupts

bool flip = false;
uint16_t Counter = 0;

void loop() 
{ 
  // wait till we have a reading
  if (triggered)
  {
    // period is elapsed time
    unsigned long elapsedTime = finishTime - startTime;
    
    Counter ++;
    Serial3.print ("Took: ");
    Serial3.print (float (elapsedTime) * 62.5e-9 * 1e6);  // convert to microseconds
    Serial3.print (" uS. ");
    Serial3.println(Counter); 
    prepareForInterrupts (); 
  }

  if(flip)
  {
    flip = false;
    digitalWrite(47, HIGH);
  }
  else
  {
    flip = true;
    digitalWrite(47, LOW);
  }

  delay(10);
}

I have tried adding a timeout where if I don't have a period after a certain amount of time
I recall the prepareForInterrupts () function but it doesn't seem to be helping in anyway.

Here are some answers to some of the questions that you might be wondering about.

No I don't always get the exact same number of periods before the code fails.
Changing the period of my square wave, lets say from 20 ms to 120ms means that the overall time until it stops working is the same but I get a smaller number of periods.

I have added some snippets of the testing runs bellow. As you can see the last couple of measures always seems to lose accuracy compared the the rest.

Here are my questions:
Do you know what could cause this behavior ?
Do you think it's interrupt related or am I missing a register that should be cleared periodically ?

Any help would be greatly appreciated

Here are results of a few runs:
image


To be able to observe what really happens you could add toggling an output pin within the interrupt handlers and loop(). With a state analyzer you can see how those three pins are behaving. Adding even more such pins you can go to more details and hopefully find the location where the problem is.

After all started from scratch with another example and it seems to work better : Arduino Input Capture Unit Interrupt Pin Tutorial & Examples

(again switched the register to use another timer)

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.