Possible IntervalTimer bug

rbrockman

Active member
or more likely I'm missing something here..

I'm using the newly released IntervalTimer function with the Teensy3, and have been going in circles, so I'm asking for a sanity check. I've stripped out some basic functionality which demonstrates the problem.

Problem: When using all 4 timers, one of them does not end properly.

Circuit: This does require an external pulsed signal to be present on the listed input pins to serve as triggers to start the timers. I'm using input signals which pulse high every 1.5mS.

The code: listed below is the code which reproduces the problem I'm experiencing. It switches the LED on for the duration of a timer. With all 4 timers active, the last timer will not end - leaving the LED on.

Is this a bug somewhere in IntervalTimer, or am I missing something?



Code:
IntervalTimer timer_1;          
IntervalTimer timer_2;          
IntervalTimer timer_3;          
IntervalTimer timer_4;          

#define CH1_IN 12          // channel 1 input pulse 
#define CH2_IN 10          // channel 2 input pulse 
#define CH3_IN 9           // channel 3 input pulse 
#define CH4_IN 8           // channel 4 input pulse 

#define LED 13


void setup()
{
  // setup input & output pins
  pinMode(CH1_IN, INPUT);        
  pinMode(CH2_IN, INPUT);        
  pinMode(CH3_IN, INPUT);        
  pinMode(CH4_IN, INPUT);
  pinMode(LED, OUTPUT);  
  
  // attach Interrupts
  attachInterrupt(CH1_IN,ISR_change_ch1,RISING);  //CH1 signal change
  attachInterrupt(CH2_IN,ISR_change_ch2,RISING);  //CH2 signal change
  attachInterrupt(CH3_IN,ISR_change_ch3,RISING);  //CH3 signal change
  attachInterrupt(CH4_IN,ISR_change_ch4,RISING);  //CH4 signal change  
}


void loop()
{
 // do nothing here
}


void ISR_change_ch1()  
{
  //digitalWriteFast(LED,HIGH);  
  timer_1.begin(timer_1_output_end, 300);  // start a timer for the desired output pw, when timer ends the pulse will be stopped
}

void timer_1_output_end()
{
  //digitalWriteFast(LED, LOW);    
  timer_1.end();              
}

void ISR_change_ch2()  
{
  //digitalWriteFast(LED,HIGH);   
  timer_2.begin(timer_2_output_end, 300);  // start a timer for the desired output pw, when timer ends the pulse will be stopped
}

void timer_2_output_end()
{
  //digitalWriteFast(LED, LOW);   
  timer_2.end();              
}

void ISR_change_ch3()  
{
  //digitalWriteFast(LED,HIGH);   
  timer_3.begin(timer_3_output_end, 300);  // start a timer for the desired output pw, when timer ends the pulse will be stopped
}

void timer_3_output_end()
{
  //digitalWriteFast(LED, LOW);   
  timer_3.end();               
}

void ISR_change_ch4()  
{
  digitalWriteFast(LED,HIGH);   
  timer_4.begin(timer_4_output_end, 300);  // start a timer for the desired output pw, when timer ends the pulse will be stopped
}

void timer_4_output_end()
{
  digitalWriteFast(LED, LOW);    
  timer_4.end();               
}
 
I've written another example code which illustrates this problem. No external signals are necessary with this code.

The code blinks the LED correctly using IntervalTimer with up to 3 timers. However, when enabling the 4th IntervalTimer, the timer never ends and the LED stays on.

Code:
IntervalTimer timer_1;          
IntervalTimer timer_2;          
IntervalTimer timer_3;          
IntervalTimer timer_4;          
elapsedMicros period;

#define LED 13


void setup()
{
  // setup output pins
  pinMode(1, OUTPUT);        
  pinMode(2, OUTPUT);        
  pinMode(3, OUTPUT);        
  pinMode(4, OUTPUT);
  pinMode(LED, OUTPUT);  
  
  // attach Interrupts to output pins
  attachInterrupt(1,ISR_signal1,RISING);  //pin1 signal change
  attachInterrupt(2,ISR_signal2,RISING);  //pin2 signal change
  attachInterrupt(3,ISR_signal3,RISING);  //pin3 signal change
  attachInterrupt(4,ISR_signal4,RISING);  //pin4 signal change  
}


void loop()
{
  // pulse 4 pins high every 1500uS
  if (period >=1500) // 
  {
    period -= 1500;  // reset time period
    digitalWriteFast(1,HIGH);
    digitalWriteFast(2,HIGH);
    digitalWriteFast(3,HIGH);
    digitalWriteFast(4,HIGH);
    digitalWriteFast(1,LOW);
    digitalWriteFast(2,LOW);
    digitalWriteFast(3,LOW);
    digitalWriteFast(4,LOW);        
  }
}


void ISR_signal1()  
{
  //digitalWriteFast(LED,HIGH);   // turn LED on
  timer_1.begin(timer_1_output_end, 300);  // start a timer for 300uS, when timer ends the LED will be turned off
}

void timer_1_output_end()
{
  //digitalWriteFast(LED, LOW);    // turn LED off
  timer_1.end();               // stop the timer 
}

void ISR_signal2()  
{
  //digitalWriteFast(LED,HIGH);   // turn LED on
  timer_2.begin(timer_2_output_end, 300);  // start a timer for 300uS, when timer ends the LED will be turned off
}

void timer_2_output_end()
{
  //digitalWriteFast(LED, LOW);    // turn LED off
  timer_2.end();               // stop the timer 
}

void ISR_signal3()  
{
  //digitalWriteFast(LED,HIGH);   // turn LED on
  timer_3.begin(timer_3_output_end, 300);  // start a timer for 300uS, when timer ends the LED will be turned off
}

void timer_3_output_end()
{
  //digitalWriteFast(LED, LOW);    // turn LED off
  timer_3.end();               // stop the timer 
}

void ISR_signal4()  
{
  digitalWriteFast(LED,HIGH);   // turn LED on
  timer_4.begin(timer_4_output_end, 300);  // start a timer for 300uS, when timer ends the LED will be turned off
}

void timer_4_output_end()
{
  digitalWriteFast(LED, LOW);    // turn LED off
  timer_4.end();               // stop the timer 
}
 
I'm looking for any guidance on this issue. Perhaps it's the approach I'm using but would like to hear if this is a bug with IntervalTimer. I'm open to proving any further examples required to diagnose this.
 
Are you using the very latest teensyduino beta release?

I think the 4th timer is reserved for tone(), until recently.

I haven't used attachInterrupt in a long time, and I don't know if there's any conflict. I imagine you could check the pin in the loop() too, to start the timers at that point.

Actually, I'm kinda confused at what you are trying to do in the code.
 
Last edited:
Yes I am using the latest beta which is supposed to support 4 timers.

Both of the examples I provided above basically do the same thing. When a specified pin goes high, start a timer for a given duration and then end it. This seems to work fine with up to 3 timers, but not with a 4th.

Maybe I should eliminate the interrupts from the equation to figure out if there is any interference. However, they are required in my implementation of IntervalTimer.
 
Do you really need interrupts that overlapping each other for each LED, or can you use one or two to do the intervals?

I think you could pass the pin# into the interrupt or alter a volatile global, so it would act on that pin. Also, if they are all doing the same thing, you could just blink all the LEDs on/off in the same interrupt.

And if you take out all the references to any of the other timers, and those relevant pins in the loop(), does it still fail?

And I don't know when an interrupt is started does it do an interrupt call at time(0), meaning does it do it immediately and then counts for the next one. OR does it wait for the first interval before calling the interrupt routine?
 
I appreciate your input into this issue as it has kept me blocked for some time now.

Let me be clear - the code examples above do not represent entirely my implementation using IntervalTimer, which is much more complex and doesn't involved LED's. I've just tried to simplify the problem as best I could to determine the source of the problem.

I do need 4 separate interrupts, controlling the start time of 4 separate timers. The interrupts seem to be the easy part, it's the usage of 4 separate timers. I'll see if I can come up with an example not using interrupts to eliminate this variable.
 
Got it. You're just trying to troubleshoot the timers. I'd suggest pinging loglow who wrote most of the IntervalTimer library. He'll probably have a pretty good idea. This might be low on Paul's list. You might well be the only one using all 4 timers. Good luck.

It might make it easier to change the timer so that it's much longer, so it's a visible duration, at least initially.
 
I have eliminated the interrupts from the example code using IntervalTimer, and the timer issue still exists. I'm now using Teensyduino 1.14 Release Candidate #2

I've learned that the problem is not ending a timer - it's actually starting a timer (should have caught that much earlier...).

The code below illustrates the issue. When trying to start all 4 timers, the 4th timer will fail upon trying to start the timer. By commenting out one of the timers, everything runs peachy.. This is easily seen by attaching a scope probe to pin 13 of the Teensy3 or just looking at the LED.
Code:
IntervalTimer timer_1;          
IntervalTimer timer_2;          
IntervalTimer timer_3;          
IntervalTimer timer_4;          

#define LED 13

elapsedMicros period;


void setup()
{
  pinMode(LED, OUTPUT);  
}


void loop()
{
  if (period >=1500) // try and start all 4 timers every 1500uS
  {
    period -= 1500;  // reset time period
  
   // issue appears when trying to start all 4 timers 
   // by commenting out one of the lines below which start the timers - all timers start without error
    start_timer1();
    start_timer2();
    start_timer3();
    start_timer4();
  }
}

// on timer start failure - blink LED
void blinkLED()         
{
  digitalWriteFast(LED,HIGH);
  delayMicroseconds(100);      //understand this causes issues with interrupts - here it helps view error condition
  digitalWriteFast(LED,LOW);
}


void start_timer1()  
{
  if (timer_1.begin(timer_1_output_end, 300) != true)  // start a timer for 300uS, if it cannot be started - LED will blink
    blinkLED();
}

void timer_1_output_end()
{
  timer_1.end();               // stop the timer 
}

void start_timer2()  
{
  if (timer_2.begin(timer_2_output_end, 300) != true)   
    blinkLED();
}

void timer_2_output_end()
{
  timer_2.end();               
}

void start_timer3()  
{
  if (timer_3.begin(timer_3_output_end, 300) != true)  
    blinkLED();
}

void timer_3_output_end()
{
  timer_3.end();               
}

void start_timer4()  
{
  if (timer_4.begin(timer_4_output_end, 300) != true)  
    blinkLED();
}

void timer_4_output_end()
{
  timer_4.end();                
}
 
Thanks for posting this. I was able to reproduce the bug, and I've found the cause. In fact, it's an embarrassingly simple bug...

In IntervalTimer.h, change this:

Code:
    static const uint8_t NUM_PIT = 3;

to this:

Code:
    static const uint8_t NUM_PIT = 4;

I've updated the code here. It will be fixed in the final 1.14 release.
 
Back
Top