Stuck in an interrupt?

I am working on a program for a RC mixer. It needs to measure incoming pulses and do some mixing. I have managed to get the whole program working on a PIC, but i now want to use a Arduino, and add a few more features.
The first feature i want to add is a failsafe. So if no pulse is received in 25ms then a failsafe value is used. So i have decided to use a Timer1 interrupt. So the code seems to work well, it measure the pulse and displays the value on the serial port. When i turn of the transmitter the timer1 overflow happens but seems to get stuck in the interrupt with the LED toggerling all the time. even when i turn the Transmitter back on it still stays in the interrupt loop.
I am guessing i have done something daft, but i cant see it.
Any clues??
Thanks for any help you may give!

#define ledPin 13
#define RxThro 3
int Time1 = 0;
int Time2 = 0;
int pulse1 = 0;
int failSafe = LOW;
int FST = 0;
boolean toggle = false;
void setup()
{
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);// initialize timer1 
  pinMode(RxThro, INPUT);
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = FST;            // preload timer 65536-16MHz/256/2Hz
  TCCR1B |= (1 << CS11);    // 256 prescaler
  TCCR1B |= (1 << CS10); 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}
void doCalcs()
{
  if (failSafe == HIGH)
  {
    pulse1 = 900;
  }
  else
  {
    TCNT1 = FST; //reset the failsafe timer
    pulse1 = Time2 - Time1;
  }
}

void getInputs()
{
  failSafe = LOW;
  while ((digitalRead(RxThro) == LOW)|(failSafe == HIGH))
  {
  }
  Time1 = micros();
  while ((digitalRead(RxThro) == HIGH)|(failSafe == HIGH))
  {
  }
  Time2 = micros();
}

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  Serial.print("+");
  TCNT1 = FST;            // preload timer with Fail Safe Time
  failSafe = HIGH;
  toggle = !toggle;
  digitalWrite(ledPin, toggle);
}

void loop()
{
  getInputs();
  doCalcs();
  Serial.print("\t");
  Serial.println(pulse1);
}

You made the classic beginner's mistake of printing in an interrupt.

Printing depends on interrupts, and they are turned off within an interrupt.

Interrupts should be as short and fast as possible.

Hi Thanks for your very quick reply. I have quickly changed the code to the following

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = FST;            // preload timer with Fail Safe Time
  failSafe = HIGH;
}

But it still does the same!

Don't use int for storing micros() use unsigned long

Don't use | instead of || for or in your while

failSafe should be declared as volatile (and should be a Boolean with true or false and not an int with HIGH or LOW just for clarity and good memory usage)

Your logic seems a bit screwed up.

  • Your ISR sets failSafe to HIGH
  • The first function that loop() calls sets failSafe to LOW
  • The next function that loop() calls expects failSafe to be HIGH
  • And in the function getInputs() as well as setting failSafe LOW it has a WHILE failSafe is HIGH

Back the drawing board I think.

...R

Ok thanks for your replies. i have made adjustments but still have the same problem. maybe i have the wrong understanding of the logic? so if i could please explain how i think it is working then please tell me what i haven’t understood?

while ((digitalRead(RxThro) == LOW)||(failSafe == HIGH))

So what i wanted to do was wait for the input pulse to go high. Or if the pulse doesn’t go high then the interrupt will set the failsafe to true and the condition will be met? and the program continue?

When i turn of the transmitter the timer1 overflow happens but seems to get stuck in the interrupt with the LED toggerling all the time.

TCCR1B |= (1 << CS11);    // 256 prescaler
  TCCR1B |= (1 << CS10);

That code set the prescaler to 64 not 256.

With the timer in Normal Mode, it will overflow in 2^16 x 64 x .0625 us which works out to a little over 262ms. The led will be toggling quite quickly. What were you expecting?

TCCR1B |= (1 << CS12);    // 256 prescaler

Will set the interrupt driven led toggle to more like one second.

Are you sure you have failSafe as volatile now?

You don't need interrupts for this ;) 25ms is an eternity in nowadays microprocessors / microcontrollers.

unsigned long currentTime;
void loop()
{
  // start time of failsafe check period
  static unsigned long startTime = 0;
  // flag to remember if failsafe is triggered
  static bool fFailsafeActivated = false;


  // get current time
  currentTime = millis();

  // if 25 ms lapsed
  if(currentTime - startTime >=25000UL)
  {
     fFailsafeActivated = true;
  }

  
  // other code here
  if(fFailsafeActivated == true || ....)
  {
  }

}

I leave it up to you to implement a means to reset the failsafe flag.

OK thanks for all your replies.

Cattledog, i tried a few different times and prescalers but it was clear the program wasn't working so its just been left as it untill i can work out why it sticks in the interrupt.

J-M-L, i believe i have done this... volatile boolean failSafe = false;

Sterretje, thanks for your idea, if i fail on the interrupt then i will change to what you have suggested, i started the program how you explained but decided that an interrupt would allow better resolution on the measured pulse?

Anyway the problem still exists!

can you post your code as it stands now?

Evening
I have set the interrupt time to 25ms and checked via a oscilloscope. the reading of the receiver pulse works well, and the interrupt works when a pulse is missing, but i still get stuck in the interrupt.

#define ledPin 13
#define RxThro 3
unsigned long Time1 = 0;
unsigned long Time2 = 0;
unsigned long pulse1 = 0;
volatile boolean failSafe = false;
int FST = 15000;
boolean toggle = false;
void setup()
{
  Serial.begin(115200);
  pinMode(13, OUTPUT);
  pinMode(ledPin, OUTPUT);// initialize timer1 
  pinMode(RxThro, INPUT);
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = FST;            // preload timer 65536-16MHz/256/2Hz
  //TCCR1B |= (1 << CS12);    // 
  TCCR1B |= (1 << CS11);
  //TCCR1B |= (1 << CS10); 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}
void doCalcs()
{
  if (failSafe == true)
  {
    pulse1 = 900;
  }
  else
  {
    TCNT1 = FST; //reset the failsafe timer
    pulse1 = Time2 - Time1;
  }
}

void getInputs()
{
  while ((digitalRead(RxThro) == LOW)||(failSafe == true))
  {
  }
  Time1 = micros();
  while ((digitalRead(RxThro) == HIGH)||(failSafe == true))
  {
  }
  Time2 = micros();
}

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = FST;            // preload timer with Fail Safe Time
  failSafe = true;
  toggle = !toggle;
  digitalWrite(13, toggle);
}

void loop()
{
  failSafe == false;
  getInputs();
  doCalcs();
  Serial.println(pulse1);
}

mr_fid: Ok thanks for your replies. i have made adjustments but still have the same problem. maybe i have the wrong understanding of the logic? so if i could please explain how i think it is working then please tell me what i haven't understood?

while ((digitalRead(RxThro) == LOW)||(failSafe == HIGH))

So what i wanted to do was wait for the input pulse to go high. Or if the pulse doesn't go high then the interrupt will set the failsafe to true and the condition will be met? and the program continue?

If you're talking about this while:

while ((digitalRead(RxThro) == LOW)||(failSafe == true))
  {
  }

That while loop is empty. So it means "do nothing while the condition is true". That means that it is just the opposite of what you said. If the interrupt sets failSafe to true then you will be trapped in this while loop forever. Remember, while loop repeats as long as the condition is true. When the condition is false, then it moves on.

 failSafe == false;

This first statement in loop intending to clear the failSafe flag should have only one =

OK Thanks for both of our comments. cattledog you have solved one of the problems! the failsafe now resets when a pulse is received.

And When i can get my head around what Delta_G has said then i believe i will have what i need?

Currently i measure the pulse correctly, But when i turn of the transmitter the interrupt is called but nothing happens apart from a flashing LED. However when i turn the transmitter on again the interrupt is called and the serial displays the pulse again.

Should i have used something other than a while? i didn't want the loop to do anything other than wait for a pulse on RxThro OR a interrupt.

void getInputs()
{
  failSafe = LOW;
  while ((digitalRead(RxThro) == LOW)|(failSafe == HIGH))
  {
        // this while loop waits, as long as RxThro is LOW or failSafe is HIGH.
        //  IF RxThro goes HIGH while failSafe is still LOW, then you exit this loop
        //  If the interrupt happens first, then failSafe is HIGH so you're trapped here forever
  }
  Time1 = micros();
  while ((digitalRead(RxThro) == HIGH)|(failSafe == HIGH))
  {
       // Same as the one above, but waits for RxThro to go LOW
       // as long as either RxThro is HIGH or failSafe is HIGH it stays here doing nothing.
       //  IF the interrupt fires and makes failSafe HIGH while you're here then you're trapped here
  }
  Time2 = micros();
}

From what I understand from what you said earlier, you want either RxThro going HIGH or failSafe going HIGH to get you OUT of the do nothing loop. So you want to stay in the whole loop while BOTH RxThro reads LOW AND failSafe is false. If you use && then either one of them changing gets you out of that do nothing loop.

But I have to admit that this is all kind of hard to follow. So I may be completely misreading you.

But when i turn of the transmitter the interrupt is called but nothing happens apart from a flashing LED

while ((digitalRead(RxThro) == LOW)||(failSafe == true))
  {
  }
while ((digitalRead(RxThro) == HIGH)||(failSafe == true))
  {
  }

You are going to get stuck in one or the other of the while loops. What is the state of the RxThro pin when the transmitter is turned off? I can change which while loop the code sticks in by changing pin 3 from INPUT to INPUT_PULLUP and not having any signal on that pin.

Your while loop can not be based on digitalRead(RxThro) but rather on waiting to see some change in RxThro. Start the time when RxThro goes from HIGH to LOW or when failSafe is true. End the time when RxThro goes from LOW to HIGH or when failSafe is true.

You are not getting stuck in the interrupt. You are getting stuck in one or the other of the while loops because RxThro is not changing.

The interrupt is triggering independently of the while loop, and that's why you see the led flash.

Delta_G wrote

If you use && then either one of them changing gets you out of that do nothing loop.

If you use &&, and read the state of RxThro you can implement a while loop with a timeout, and know which triggered the exit from the loop.

#define ledPin 13
#define RxThro 3
unsigned long Time1 = 0;
unsigned long Time2 = 0;
unsigned long pulse1 = 0;
volatile boolean failSafe = false;
boolean timeOut = false;
int FST = 15000;
boolean toggle = false;
void setup()
{
  Serial.begin(115200);
  Serial.println("begin");
  pinMode(13, OUTPUT);
  pinMode(ledPin, OUTPUT); // initialize timer1
  pinMode(RxThro, INPUT_PULLUP);
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = FST;            // preload timer 65536-16MHz/256/2Hz
  //TCCR1B |= (1 << CS12);    //
  TCCR1B |= (1 << CS11);
  // TCCR1B |= (1 << CS10);
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}
void doCalcs()
{
  if (timeOut == true)
  {
    pulse1 = 900;
    timeOut = false;
  }
  else
  {
    TCNT1 = FST; //reset the failsafe timer
    pulse1 = Time2 - Time1;
  }
}

void getInputs()
{
  Serial.println("get inputs");
  while ((digitalRead(RxThro) == LOW) && (failSafe == false))
  {
  }
  if (digitalRead(RxThro) == LOW) // exit trigered by failsafe
    timeOut = true;
  else
    Time1 = micros();

  while ((digitalRead(RxThro) == HIGH) && (failSafe == false))
  {
  }
  if (digitalRead(RxThro) == HIGH) //exit triggered by failSafe
    timeOut = true;
  else
    Time2 = micros();
}

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = FST;            // preload timer with Fail Safe Time
  failSafe = true;
  toggle = !toggle;
  digitalWrite(13, toggle);
}

void loop()
{
  failSafe == false;
  getInputs();
  doCalcs();
  Serial.println(pulse1);
}

Firstly thank you for persevering with me on this problem! I seem to have a knack of confusing people.

Delta_G: From what I understand from what you said earlier, you want either RxThro going HIGH or failSafe going HIGH to get you OUT of the do nothing loop. So you want to stay in the whole loop while BOTH RxThro reads LOW AND failSafe is false. If you use && then either one of them changing gets you out of that do nothing loop.

I want to wait until i see a pulse OR (if no pulse comes) then move on to the next loop when the interrupt happens. then if i have seen no pulse in the first loop then i was thinking it would then skip the second loop due to the Failsafe True?

cattledog: What is the state of the RxThro pin when the transmitter is turned off?

When the Transmitter is turned off the receiver gives out nothing. Hence the reason i want a failsafe!