Interrupt Juggling for my Chornograph

Hi!

I'm writing code for a chonograph. My sensors and signal conditioning for my chronograph work well as verified by an o-scope. I'm getting clean square signals on the order of a couple hundred microseconds. I have 2 light channels, CHANNEL_1 and CHANNEL_2. The signal conditioning is setup such that as the light channel is blocked my output goes from low to high and when the channel is unblocked the signal goes from high to low.

My issues is my code on my Arduino at the moment.

I'm juggling some interrupts to accomplish the task and wondering if my approach is good or not. The code utilizes the TimerOne library, the timer1 interrupt, and the 2 interrupts "0" and "1" corresponding to pins 2 and 3 on my Arduino Nano (ATmega328). Right now, I'm just trying to test the code out. I've enabled pull up resistors on my pins 2 and 3. For testing purposes I have a wire connecting pin 2 to ground. My goal was to quickly detach the wire and attach the wire to ground to simulate a signal rise and fall coming into that pin. But when I pull the wire the arduino fires my timeout_ISR() code and not the correct ISR.

My guess is that I'm probably missing something major about interrupts. This is my first time using interrupts on the Arduino.

Thanks for your input. Here is my code (note that the reset_variables() subroutines sets my initial interrupt setting).

#include <TimerOne.h>


/*

Constants

*/

#define CHANNEL_1 2  //set light channel 1 to pin 2  NOTE: most Arduino boards only have two external interrupts, numbers 0 and 1 (digital pins 2 and 3).
                      //the signal for the channels needs to be sent to a pin that is interrupt enabled in this current version of the software.
#define CHANNEL_2 3  //set light channel 2 to pin 3

#define CHANNEL_1_INT 0    //interrupt number associated with channel 1

#define CHANNEL_2_INT 1    //interrupt number associated with channel 2

#define TIMEOUT 8000000  //sets the time duration in microseconds

#define WAIT_STATE 0
#define MONITOR_STATE 1
#define OUTPUT_STATE 2

/*

Global Variables

*/

unsigned long channel_1_initial = 0;
unsigned long channel_1_final = 0;
unsigned long channel_2_initial = 0;
unsigned long channel_2_final = 0;
boolean is_timeout = false;
unsigned int current_state = WAIT_STATE;




void setup() {
  pinMode(CHANNEL_1, INPUT);
  pinMode(CHANNEL_2, INPUT);
  digitalWrite(CHANNEL_1, HIGH);  //turn on pullup resistor
  digitalWrite(CHANNEL_2, HIGH);
  reset_variables();
  Serial.begin(9600);
  
  
}

void loop() {
  switch (current_state) {
    case WAIT_STATE:
    
    break;
    case MONITOR_STATE:
    
    break;
    case OUTPUT_STATE:
      output_serial_info();
      reset_variables();
      
      current_state = WAIT_STATE;
    break;
  }
}

void channel_1_rise_ISR() {
  channel_1_initial = 0;
  Timer1.initialize(TIMEOUT);
  Timer1.start();
  Timer1.attachInterrupt(timeout_ISR);
  attachInterrupt(CHANNEL_1_INT, channel_1_fall_ISR, FALLING);
  attachInterrupt(CHANNEL_2_INT, channel_2_rise_ISR, RISING);
  current_state = MONITOR_STATE;
}

void channel_1_fall_ISR() {
  channel_1_final = Timer1.read();
  detachInterrupt(CHANNEL_1_INT);
}

void channel_2_rise_ISR() {
  channel_2_initial = Timer1.read();
  attachInterrupt(CHANNEL_2_INT, channel_2_rise_ISR, FALLING);
}

void channel_2_fall_ISR() {
  channel_2_final = Timer1.read();
  detachInterrupt(CHANNEL_2_INT);
  Timer1.stop();
  Timer1.detachInterrupt(); 
  current_state = OUTPUT_STATE;
}

void timeout_ISR() {
  is_timeout = true;
  detachInterrupt(CHANNEL_1_INT);
  detachInterrupt(CHANNEL_2_INT);
  Timer1.stop();
  Timer1.detachInterrupt();
  current_state = OUTPUT_STATE;
}

void output_serial_info() {
      if(is_timeout)
        Serial.println("TIMEOUT");
      Serial.print("Channel 1 Init: ");
      Serial.println(channel_1_initial);
      Serial.print("Channel 1 Final: ");
      Serial.println(channel_1_final);
      Serial.print("Channel 2 Init: ");
      Serial.println(channel_2_initial);
      Serial.print("Channel 2 Final: ");
      Serial.println(channel_2_final);
      Serial.print("Channel 1 Duration: ");
      Serial.println((channel_1_final - channel_1_initial));
      Serial.print("Channel 2 Duration: ");
      Serial.println((channel_2_final - channel_2_initial));
      Serial.print("Total Duration: ");
      Serial.println((channel_2_initial - channel_1_initial));  
}

void reset_variables() {
  channel_1_initial = 0;
  channel_1_final = 0;
  channel_2_initial = 0;
  channel_2_final = 0;
  is_timeout = false;
  attachInterrupt(CHANNEL_1_INT, channel_1_rise_ISR, RISING);
  detachInterrupt(CHANNEL_2_INT);
}

Ok, so now it looks like my code is executing the channel_1_rise_ISR correctly, but then immediately jumps to the timeout_ISR() and locks up before it finishes the output_serial_info() subroutine. I added the line Serial.println("Channel 1 Rise Executed") to my channel_1_rise_ISR. I get the following output:

Channel 1 Rise Executed
TIMEOUT
Channel 1 Init: 0
Channel 1 Final: 0
Channel 2 Init: 0
Channel 2 Final: 0
Ch

Hmm..it looks like a lot of the methods for the TimerOne class disable global interrupts, but I don't see it ever re-enabling the global interrupts... odd.

Try forcing the TIMEOUT to be a long integer.

#define TIMEOUT 8000000L

Pete

Thanks for the reply. That didn't seem to help but defining the value as an unsigned long global variable did...something...

I'm still having problems where when it first calls the channel_1_rise_ISR() I get immediate output indicating a timeout. I don't think I'm using this TimerOne library correctly... maybe I should interact directly with the timer register so I know what is going on exactly...

I would think I would have enough time in 8 seconds to open and close the first wire and then open and close the second wire. Is it OK to setup new interrupts while servicing old interrupts? I feel like I'm getting a build up of interrupts that are probably firing as the first one is getting serviced due to bounce or something like that.... maybe I should try disabling global interrupts while I'm servicing and then enable them on the exit....

-Nic

Here is my code updated. It seems like I can get both the channel_1 and channel_2 rise/fall subroutines to fine but my timeout_ISR keeps firing and I know that if my timeout was set to 8 seconds that should be plenty of time to disconnect and reconnect both wires in a sequence. I suspect bounce may be an issue, but don't want it to be. The first time "channel_1_rise_ISR()" is executed (for instance) it should detach the interrupt from calling that function. Anyway, here is my code. The cli(); and sei(); function calls didn't seem to fix the issue.

#include <TimerOne.h>


/*

Constants

*/

#define CHANNEL_1 2  //set light channel 1 to pin 2  NOTE: most Arduino boards only have two external interrupts, numbers 0 and 1 (digital pins 2 and 3).
                      //the signal for the channels needs to be sent to a pin that is interrupt enabled in this current version of the software.
#define CHANNEL_2 3  //set light channel 2 to pin 3

#define CHANNEL_1_INT 0    //interrupt number associated with channel 1

#define CHANNEL_2_INT 1    //interrupt number associated with channel 2

//#define TIMEOUT 8000000L  //sets the time duration in microseconds

#define WAIT_STATE 0
#define MONITOR_STATE 1
#define OUTPUT_STATE 2

/*

Global Variables

*/

unsigned long channel_1_initial = 0;
unsigned long channel_1_final = 0;
unsigned long channel_2_initial = 0;
unsigned long channel_2_final = 0;
boolean is_timeout = false;
unsigned int current_state = WAIT_STATE;
unsigned long my_timeout = 8000000;



void setup() {
  pinMode(CHANNEL_1, INPUT);
  pinMode(CHANNEL_2, INPUT);
  digitalWrite(CHANNEL_1, HIGH);  //turn on pullup resistor
  digitalWrite(CHANNEL_2, HIGH);
  reset_variables();
  Serial.begin(9600);
  
  
}

void loop() {
  switch (current_state) {
    case WAIT_STATE:
    
    break;
    case MONITOR_STATE:
    
    break;
    case OUTPUT_STATE:
      output_serial_info();
      reset_variables();
      
      current_state = WAIT_STATE;
    break;
  }
}

void channel_1_rise_ISR() {
//  Serial.println("Channel 1 Rise Executed");
  cli();
  channel_1_initial = 0;
  Timer1.initialize(my_timeout);
//  Timer1.start();
  Timer1.attachInterrupt(timeout_ISR);
  attachInterrupt(CHANNEL_1_INT, channel_1_fall_ISR, FALLING);
  attachInterrupt(CHANNEL_2_INT, channel_2_rise_ISR, RISING);
  current_state = MONITOR_STATE;
  sei();
}

void channel_1_fall_ISR() {
  cli();
  channel_1_final = Timer1.read();
  detachInterrupt(CHANNEL_1_INT);
  sei();
}

void channel_2_rise_ISR() {
  cli();
  channel_2_initial = Timer1.read();
  attachInterrupt(CHANNEL_2_INT, channel_2_fall_ISR, FALLING);
  sei();
}

void channel_2_fall_ISR() {
  cli();
  channel_2_final = Timer1.read();
  detachInterrupt(CHANNEL_2_INT);
  Timer1.detachInterrupt(); 
  current_state = OUTPUT_STATE;
  sei();
}

void timeout_ISR() {
  cli();
  is_timeout = true;
  detachInterrupt(CHANNEL_1_INT);
  detachInterrupt(CHANNEL_2_INT);
//  Timer1.stop();
  Timer1.detachInterrupt();
  current_state = OUTPUT_STATE;
  sei();
}

void output_serial_info() {
      if(is_timeout)
        Serial.println("TIMEOUT");
      Serial.print("Channel 1 Init: ");
      Serial.println(channel_1_initial);
      Serial.print("Channel 1 Final: ");
      Serial.println(channel_1_final);
      Serial.print("Channel 2 Init: ");
      Serial.println(channel_2_initial);
      Serial.print("Channel 2 Final: ");
      Serial.println(channel_2_final);
      Serial.print("Channel 1 Duration: ");
      Serial.println((channel_1_final - channel_1_initial));
      Serial.print("Channel 2 Duration: ");
      Serial.println((channel_2_final - channel_2_initial));
      Serial.print("Total Duration: ");
      Serial.println((channel_2_initial - channel_1_initial));  
}

void reset_variables() {
  channel_1_initial = 0;
  channel_1_final = 0;
  channel_2_initial = 0;
  channel_2_final = 0;
  is_timeout = false;
  attachInterrupt(CHANNEL_1_INT, channel_1_rise_ISR, RISING);
  detachInterrupt(CHANNEL_2_INT);
}

Here is the output of my first try... the sequencing is funny and I get way more OUTPUT_STATE posts than I should have I think...

TIMEOUT
Channel 1 Init: 0
Channel 1 Final: 13312
Channel 2 Init: 0
Channel 2 Final: 0
Channel 1 Duration: 13312
Channel 2 Duration: 0
Total Duration: 0
TIMEOUT
Channel 1 Init: 0
Channel 1 Final: 350208
Channel 2 Init: 0
Channel 2 Final: 0
Channel 1 Duration: 350208
Channel 2 Duration: 0
Total Duration: 0
TIMEOUT
Channel 1 Init: 0
Channel 1 Final: 0
Channel 2 Init: 100352
Channel 2 Final: 0
Channel 1 Duration: 0
Channel 2 Duration: 4294866944
Total Duration: 100352

Nickerbocker:
Hmm..it looks like a lot of the methods for the TimerOne class disable global interrupts, but I don't see it ever re-enabling the global interrupts... odd.

Where?


One point made in there is that an interrupt can be queued even while that interrupt is off. You may need to set the "I have seen this interrupt" bit before enabling that interrupt.

void channel_1_rise_ISR() {
//  Serial.println("Channel 1 Rise Executed");
  cli();
  channel_1_initial = 0;
  Timer1.initialize(my_timeout);
//  Timer1.start();
  Timer1.attachInterrupt(timeout_ISR);
  attachInterrupt(CHANNEL_1_INT, channel_1_fall_ISR, FALLING);
  attachInterrupt(CHANNEL_2_INT, channel_2_rise_ISR, RISING);
  current_state = MONITOR_STATE;
  sei();
}

No point in the cli(), sei() pair. Interrupts are disabled inside an ISR and re-enabled as you leave it.

@Nick - Good to know about the cli() and sli(). In the TimerOne.cpp file there are several calls to cli();, for instance:

void TimerOne::setPeriod(long microseconds)		// AR modified for atomic access
{
  
  long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum
  
  oldSREG = SREG;				
  cli();							// Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;                                          // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;
  
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;                                          // reset clock select register, and starts the clock
}

Which is called when you call the initialize() method in the TimerOne class. My global interrupts must be turned back on somewhere.... not sure where though. No where in the .cpp file is a sli(); call.

This does it:

  oldSREG = SREG;			     // save processor status flags	
  cli();							// Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;                                          // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;     // <-------- put back status flags, including interrupt flag if it happened to be set before

It is written this way in case you happen to call it from code that has interrupts disabled. Disabling them twice won't hurt, but enabling them afterwards, if they were not enabled before, will.

Interrupt Juggling for my Chornograph

...

I'm writing code for a chonograph.

...

My sensors and signal conditioning for my chronograph work well

Out of curiosity, is it a Chornograph, chonograph or chronograph?

Chronograph :slight_smile:

@Nick - the article you wrote is very revealing and I see now that interrupts are not the right approach because of the delays associated with them. Rats, I thought this was the perfect project for me to get my hands dirty with interrupts on the Arduino platform.

Looks like I'm going to be spinning the CPU monitoring for pin changes.

Thanks for the article. Bookmarked it for future reference. I think my main issue was probably due to not using the volatile flag but there were likely others. Once I saw I was losing about 5us on entering and leaving the pin change ISRa I knew that it wouldn't work well for my application.

Sounds an interesting project. Waiting in a loop has its own drawbacks, for example the condition you are testing may change when you are not actually checking it (maybe a few clock cycles out).

I'm not sure exactly what you are doing, another possible thing to use is hardware timers (an incoming pulse can make the timer count up).

You can also sleep until the interrupt, that gives you a fixed interval (a known interval) between the event and the ISR becoming active.

Nick - Yeah, I'm thinking about switching to maybe external hardware timers. The propagation delay for starting and stopping the internal timers in the AVR seem to slow to me at 16MHz. I'm going to try this polling, which seems to work a lot more reliably than the interrupt setup.

What it is I am doing is making a chronograph to track the speed of a projectile. There are two IR beams with detectors setup and the detectors are connected to an opamp in a comparator mode. When a projectile breaks the beam the comparator goes high on the output, and when the beam is reformed the comparator goes low on the output. See the attached O-Scope image.

For the speeds I'm looking at, about 1us is a good resolution. The channel durations represent the duration the projectile broke a particular beam. If the projectile size is approximately known, and it can be assumed that the center of the projectile went through the center of the beam then an approximate speed using just 1 detector/light beam setup can be used. The amount of time it took to brake the first and then the second beam is a better estimate because that does not need the assumptions that are required for the calculation based on 1 beam.

Here is the current state of my code:

#include <TimerOne.h>


/*

Constants

*/

#define CHANNEL_1 2  //set light channel 1 to pin 2  NOTE: most Arduino boards only have two external interrupts, numbers 0 and 1 (digital pins 2 and 3).
                      //the signal for the channels needs to be sent to a pin that is interrupt enabled in this current version of the software.
#define CHANNEL_2 3  //set light channel 2 to pin 3

#define WAIT_STATE 0
#define MONITOR_STATE 1
#define OUTPUT_STATE 2

/*

Global Variables

*/

unsigned long channel_1_initial = 0;
unsigned long channel_1_final = 0;
unsigned long channel_2_initial = 0;
unsigned long channel_2_final = 0;
volatile boolean is_timeout = false;
volatile unsigned int current_state = WAIT_STATE;
unsigned long my_timeout = 5000000;
char my_oldSREG;    //to hold status register while ints are disabled


void setup() {
  pinMode(CHANNEL_1, INPUT);
  pinMode(CHANNEL_2, INPUT);
  digitalWrite(CHANNEL_1, HIGH);  //turn on pullup resistor
  digitalWrite(CHANNEL_2, HIGH);

  reset_variables();
  Serial.begin(9600);

}

void loop() {
  switch (current_state) {
    case WAIT_STATE:
      if(digitalRead(CHANNEL_1)==HIGH) {
        channel_1_initial = micros();
        current_state = MONITOR_STATE;
        Timer1.initialize(my_timeout);
        Timer1.attachInterrupt(timeout_ISR, my_timeout);
      }
    break;
    case MONITOR_STATE:
      while(digitalRead(CHANNEL_1)==HIGH && !is_timeout);    //loop until channel 1 goes LOW
      if(!is_timeout)
        channel_1_final = micros();
      while(digitalRead(CHANNEL_2)==LOW && !is_timeout);  //loop until the channel goes HIGH
      if(!is_timeout)
        channel_2_initial = micros();
      while(digitalRead(CHANNEL_2)==HIGH && !is_timeout);  //loop until the channel goes LOW
      if(!is_timeout)
        channel_2_final = micros();
      current_state = OUTPUT_STATE;
    break;
    case OUTPUT_STATE:
      output_serial_info();
      reset_variables();
      current_state = WAIT_STATE;
    break;
  }
}


void timeout_ISR() {
  if(current_state != WAIT_STATE)
    is_timeout = true;
}

void output_serial_info() {
      if(is_timeout)
        Serial.println("TIMEOUT");
      Serial.print("Channel 1 Init: ");
      Serial.println(channel_1_initial);
      Serial.print("Channel 1 Final: ");
      Serial.println(channel_1_final);
      Serial.print("Channel 2 Init: ");
      Serial.println(channel_2_initial);
      Serial.print("Channel 2 Final: ");
      Serial.println(channel_2_final);
      Serial.print("Channel 1 Duration: ");
      Serial.println((channel_1_final - channel_1_initial));
      Serial.print("Channel 2 Duration: ");
      Serial.println((channel_2_final - channel_2_initial));
      Serial.print("Total Duration: ");
      Serial.println((channel_2_initial - channel_1_initial));  
}

void reset_variables() {
  channel_1_initial = 0;
  channel_1_final = 0;
  channel_2_initial = 0;
  channel_2_final = 0;
  is_timeout = false;
  Timer1.detachInterrupt();
}

I still need to use an internal timer that is used as a "timeout" timer and that is why the TimerOne library still remains. This is just in case the first beam gets interrupted and starts the pin-polling process... there needs to be a way out so that the controller does not get locked up. But I'm having an issue where my Timer1 calls an interrupt as soon as it is attached :(. I've tried modifying the timeout_ISR so that it doesn't flip the is_timeout flag to true if it is still in the WAIT_STATE (basically ignore the first interrupt), but that isn't working (the interrupt must be firing with some delay after the current_state variable is set to MONITOR_STATE).

I've thought about using a watchdog timer instead, but really want there to be some output even in the event of a timeout. I don't necessarily need the AVR to reboot.

I understand the concern of missing the signal as my AVR polls... however I think that is not very likely as the signal swing high for about 80us (this was with a 4.4mm BB). As the speed goes up and the projectile size goes down, this is going to become more tricky. For one I think my phototransistors are too slow...I have some faster photodiodes but I don't have a good emitter for them and my lens configuration is for an LED not a laser diode. Probably have to worry about that, though, as the projectiles get faster.

I think I will probably have to go to some external timer that is read by the AVR somehow. Hmmm..... I'm open for any suggestions. Thanks for your input and time.

F0003TEK.BMP (76.1 KB)

Probably what would work best would be an external counter that has an I2C interface and preferably its own integrated high speed oscillator (~16MHz+). I am working this project off of a breadboard which isn't the best place to setup a high speed oscillator (at least that is my understanding). I will need the I2C interface to communicate to the Arduino because a parallel interface would take way too many pins.

Seems like something like this would be good if it had a faster clock:
http://datasheets.maxim-ic.com/en/ds/DS1672.pdf

Nickerbocker:
What it is I am doing is making a chronograph to track the speed of a projectile. There are two IR beams with detectors setup and the detectors are connected to an opamp in a comparator mode. When a projectile breaks the beam the comparator goes high on the output, and when the beam is reformed the comparator goes low on the output. See the attached O-Scope image.

I did something similar to that a little while back. Here is the code:

const byte LED = 12;
const float DISTANCE = 0.9; // m

unsigned long startTime;
volatile unsigned long elapsedTime;
volatile boolean done;
boolean started;

void ballPassesGate1 ()
{
  startTime = micros (); 
  started = true;
    
  digitalWrite (LED, HIGH);  
}  // end of ballPassesGate1

void ballPassesGate2 ()
{
  if (!started)
    return;
    
  elapsedTime = micros () - startTime;  
  done = true;
  started = false;
  
  digitalWrite (LED, LOW);  
}  // end of ballPassesGate2


void setup ()
{
  Serial.begin (115200);
  Serial.println ("Timer sketch started.");  
  pinMode (LED, OUTPUT);
  attachInterrupt (0, ballPassesGate1, FALLING);
  attachInterrupt (1, ballPassesGate2, FALLING);
}  // end of setup

void loop ()
  {
  if (!done)
    return;
    
  Serial.print ("Time taken = ");
  Serial.print (elapsedTime);
  Serial.println (" uS");
  float secs = float (elapsedTime) / 1.0e6;
  float velocity = DISTANCE / secs;
  Serial.print ("Time taken = ");
  Serial.print (secs);
  Serial.println (" seconds.");
  Serial.print ("Average velocity = ");
  Serial.print (velocity);
  Serial.println (" m/s.");
  Serial.println ();
  
  done = false;
  }  // end of loop

This was basically with an LED and photo-detector at each end of a ramp, down which rolled a ball.

I didn't really care about microsecond accuracy, although the interrupts measured with that resolution.

Ok, my solution that used timer1 to force a "timeout" after 5 seconds of inactivity is working now. Not really sure of the entire issue, I'm unfamiliar with all the registry calls in the TimerOne source code. But doing some web searches, I came across the right way to set timer1 using the TimerOne library to fire an interrupt after so many seconds. Here is my code:

#include <TimerOne.h>


/*

Constants

*/

#define CHANNEL_1 2  //set light channel 1 to pin 2  NOTE: most Arduino boards only have two external interrupts, numbers 0 and 1 (digital pins 2 and 3).
                      //the signal for the channels needs to be sent to a pin that is interrupt enabled in this current version of the software.
#define CHANNEL_2 3  //set light channel 2 to pin 3

#define WAIT_STATE 0
#define MONITOR_STATE 1
#define OUTPUT_STATE 2

/*

Global Variables

*/

unsigned long channel_1_initial = 0;
unsigned long channel_1_final = 0;
unsigned long channel_2_initial = 0;
unsigned long channel_2_final = 0;
volatile boolean is_timeout = false;
volatile unsigned int current_state = WAIT_STATE;
unsigned long my_timeout = 5000000;
char my_oldSREG;    //to hold status register while ints are disabled


void setup() {
  pinMode(CHANNEL_1, INPUT);
  pinMode(CHANNEL_2, INPUT);
  digitalWrite(CHANNEL_1, HIGH);  //turn on pullup resistor
  digitalWrite(CHANNEL_2, HIGH);
  Timer1.initialize(my_timeout);
  Timer1.attachInterrupt(timeout_ISR, my_timeout);
  Timer1.stop();

  reset_variables();
  Serial.begin(9600);

}

void loop() {
  switch (current_state) {
    case WAIT_STATE:
      if(digitalRead(CHANNEL_1)==HIGH) {
        channel_1_initial = micros();
        current_state = MONITOR_STATE;

        Timer1.setPeriod(my_timeout);
      }
    break;
    case MONITOR_STATE:
      while(digitalRead(CHANNEL_1)==HIGH && !is_timeout);    //loop until channel 1 goes LOW
      if(!is_timeout)
        channel_1_final = micros();
      while(digitalRead(CHANNEL_2)==LOW && !is_timeout);  //loop until the channel goes HIGH
      if(!is_timeout)
        channel_2_initial = micros();
      while(digitalRead(CHANNEL_2)==HIGH && !is_timeout);  //loop until the channel goes LOW
      if(!is_timeout)
        channel_2_final = micros();
      current_state = OUTPUT_STATE;
    break;
    case OUTPUT_STATE:
      output_serial_info();
      reset_variables();
      current_state = WAIT_STATE;
    break;
  }
}


void timeout_ISR() {
  if(current_state != WAIT_STATE)
    is_timeout = true;
}

void output_serial_info() {
      Serial.println("BEGIN"); 
      Serial.print("Timeout?\t");    
      Serial.println(is_timeout);
      Serial.print("Channel 1 Init\t");
      Serial.println(channel_1_initial);
      Serial.print("Channel 1 Final\t");
      Serial.println(channel_1_final);
      Serial.print("Channel 2 Init\t");
      Serial.println(channel_2_initial);
      Serial.print("Channel 2 Final\t");
      Serial.println(channel_2_final);
      Serial.print("Channel 1 Duration\t");
      Serial.println((channel_1_final - channel_1_initial));
      Serial.print("Channel 2 Duration\t");
      Serial.println((channel_2_final - channel_2_initial));
      Serial.print("Total Duration\t");
      Serial.println((channel_2_initial - channel_1_initial));
      Serial.println("END");
 
}

void reset_variables() {
  channel_1_initial = 0;
  channel_1_final = 0;
  channel_2_initial = 0;
  channel_2_final = 0;
  is_timeout = false;
  Timer1.stop();
}

Basically, initialize and attach the interrupt vector to the timer then immediately stop it. To start it timing call SetPeriod(). To stop it from timing call stop().

unsigned long my_timeout = 5000000;

should be

unsigned long my_timeout = 5000000UL;