Timer2 not working independent from interrupt duration

Hello,

I'm noticing a rather odd behaviour in the Timer2 on an Arduino pro compatible (Atmel328) board. I can use Timer2 and it fires the interrupt vector routine. If no code is executed in the interrupt routine, the Timer2 correctly fires the interrupt at the set interval time, in my case 500 microseconds. However if I use some code in the interrupt rouine (basic port switching code, no interrupts or functions that use interrupts) and that particular code takes up about 300 microseconds, the Timer2 now only fires every 800 microseconds i.s.o the set 500 microseconds. This time difference applies to any code in the interrupt routine, so changing code and making it take up more (or less) time also reflects in the time it take to fire the interrupt.

My conclusion is that either the Timer2 stops counting in the interrupt routine, or the counter is reset after the interrupt is finished. The first I checked with a simple serial print and the counter does seem to count upwards, the latter looks like the only explanation...

Is there sometihing I'm missing here?

I'm using the TimerTwo files that are attached and I'm simply setting up te timer to fire every 500 microseconds.

Greetings
Gesture

TimerTwo.cpp (9.76 KB)

TimerTwo.h (1002 Bytes)

The code you posted does not look like Arduino code - where are setup() and loop()

Trying to make sense of someone's program when it uses a lot of register writes and reads would be far too time consuming (or perhaps I'm just lazy).

Can't you make a short program that illustrates your problem?

...R

Is there sometihing I'm missing here?

The sketch that actually uses the library.

PaulS:
The sketch that actually uses the library.

Haha

Ok I'll post it tonight as I don't have access to my code right now.

Uh-oh, I already see what is going on. I overlooked the lines 18-30 in the TimeTwo.cpp:

18 ISR(TIMER2_OVF_vect) // timer overflow interrupt service routine that wraps a user defined function supplied by attachInterrupt
19 {
20 if(Timer2.pwm_arr!=NULL && Timer2.pwm_arr[0]!=Timer2.tcnt2_init){
21 Timer2.pwm_arr[3]^=0x01;
22 Timer2.PinToDigital(Timer2.pwm_arr[2],Timer2.pwm_arr[3]);
23 TCNT2=(RESOLUTION-1)-Timer2.pwm_arr[Timer2.pwm_arr[3]];
24 }
25 else{
26 Timer2.isrCallback();
27 TCNT2=Timer2.tcnt2_init;
28 }
29
30 }

In line 27 the counter is indeed reset to it's initial value meaning after the interrupt call the timer starts with another timer interval. This explains the extra time:

interval of 500uS has passed > interrupt is called (but timer continues) > interrupt takes 300uS > interval is reset (L27)> interval of 500uS starts again....

this is gving 500 + 300 (+500 + 300 etc) = an 800uS interval :frowning:

Removing/commenting line 27 should do the trick!

@OP

The time discrepancy in the interval of 'TC2 Overflow interrupt' could be visualized from the following example.

1. Desired interval for TC2 overflow interrupt is: 500 us.
Let us choose suitable clkTC2 frequency and pre-set count (n) for TCNT2 so that the TC2 overflow (rollover) occurs exactly at the elapse of 500 us. The 'overflow/rollover event' occurs when the TCNT2 Register turns from all 1s to all 0s.

(a) clkTC2 = fosc/64 = 16000000/64 = 250000Hz.
(b) To elapse 500 us time, the TCNT2 must count 25000050010-6 = 125 clock pulses.
(c) Therefore: n (preset count) + 125 = 0x100 and n stands as: 131 = 0x83. This is the value that must be loaded into TCNT2 Register during initialization and just after every overflow interrupt; otherwise, the interrupt interval will be 1024 us (256*1/250000). (If clkTC2 is chosen as 16000000/32 = 500000 Hz, the pre-set count (n) will be 250. At the failure of reloading the pre-set count in the TCNT2 register, the interrupt interval will be 512 us). I am unable to come up to the figure 800 us that has happened in the case of OP!

2. Codes

void setup()
{
  TCCR2A = 0x00; //TC2 as nornal up counter
  TCCR2B = 0x00; //TC2 is OFF
  TCNT2 = 0x83;    //preset count
  TCCR2B = 0x04;   //TC2 is ON with clkTC2 = 16000000/64
  bitSet(TIMSK2, 0);   //TC2 overflow interrupt enable bit is made active
  bitSet(SREG, 7);      //global interrupt enable bit is mad active
}

void loop()
{
  
}

ISR(TIMER2_OVF_vect)
{
  //set a flag to indicate overflow interrupt; use this flag in the loop() function to do something useful
  //the job must be done in less than interrupt interval and then clear the flag.
  TCNT2 = 0x83;   //reload preset count
}

Thanks for the input. Indeed the code uses the prescaler value of 32, thus the number of ticks to be counted for a time interval of 500uS will be 250. The code also initializes this by substracting this number from the (8-bit timer) maximum value of 256. The OVF will fire on 255 + 1 so there has to be a substracteion of one from the total, leading up to 256 - 1 - 250 = 5. This all works just fine. But this initialization should take place every time the next interval is to be fired.

The problem was in the lines 26 and 27. In the original code the initialization of each interval was done AFTER the ISR routine has finished. This leads up to a wait time for the next interval to start counting again by the execution time of the ISR routine! The solution is to simply swap both lines, making the time interval start again BEFORE the ISR routine, so after this has finished the counter will still hold the correct remaining time value. Of course one should mind that the execution time of the ISR routine does not surpass the timer interval.

so:
26 Timer2.isrCallback();
27 TCNT2=Timer2.tcnt2_init;

becomes:
26 TCNT2=Timer2.tcnt2_init;
27 Timer2.isrCallback();

Problem solved!

I'd also like to thank the creator of the library that is used here.