Forcing an ISR execution gracefully

Hello

I have some routine called when Timer1 matches the Output Compare Register. Works fine. But I also want to be able to trigger an "unscheduled" execution of this ISR from within the main loop. Furthermore, I'd like that ISR be able to tell if it's been called the regular way (by the timer interrupt) or "manually" forced and to differentiate its actions on that basis. So, to summerize, I'd like to have following functionality:

void setup(){
  TCCR1A &= ~(_BV(WGM13) | _BV(WGM12) | _BV(WGM11) | _BV(WGM10)); //Normal Timer mode (no PWM)
  TCCR1B |= _BV(CS12) | _BV(CS10); //prescaler of 1024
  TCCR1B &= ~_BV(CS11);
  TIMSK1 |= _BV(OCIE1A); //Output Compare A Match Interrupt 
Enable
  OCR1A = 0;  //For this example only - in the real code it'll be updated by the ISR itself
}

ISR(TIMER1_COMPA_vect) {
  if (normal_call){
    doSomethingAccordingtoSchedule; //normal response for counter match
  }
  else {
    doSthSpecial;  //called forcibly from the main loop
  }
}

void loop(){
   blablablah
   delay(500);
   blablablah;
   force_TIMER1_COMPA_vect();
}

I've tried to call the ISR "by hand" (TIMER1_COMPA_vect()) and then testing the OCF1A in TIFR1 in the ISR scope but it doesn't work - the bit is always set to 0, regardless of the "calling" source. I've also tried to manually set FOC1A in TCCR1C (TCCR1C |= _BV(FOC1A)) from the main code, but it doesn't trigger an interrupt at all. Does anyone have some solution? I'd rather avoid any lousy (volatile byte calledByHand = 1)-type solution, which could cause some race conditions and look just ugly ;)

Thanks in advance! Regards Zbig

I don't know much about ISRs but would something like this work?

void setup(){
  TCCR1A &= ~(_BV(WGM13) | _BV(WGM12) | _BV(WGM11) | _BV(WGM10)); //Normal Timer mode (no PWM)
  TCCR1B |= _BV(CS12) | _BV(CS10); //prescaler of 1024
  TCCR1B &= ~_BV(CS11);
  TIMSK1 |= _BV(OCIE1A); //Output Compare A Match Interrupt
Enable
  OCR1A = 0;  //For this example only - in the real code it'll be updated by the ISR itself
}

void myStuff(boolean normalCall) {
  if (normalCall){
    doSomethingAccordingtoSchedule; //normal response for counter match
  }
  else {
    doSthSpecial;  //called forcibly from the main loop
  }
}

ISR(TIMER1_COMPA_vect) {
  myStuff(true);
}

void loop(){
   blablablah
   delay(500);
   blablablah;
   myStuff(false);
}

I guess you might want/need to disable interrupts in myStuff().

Andrew

I guess you might want/need to disable interrupts in myStuff().

It might even be worse than that. Maybe I'm paranoid, but I'd block interrupts even before the first invisible statement of entering myStuff() happens. Thus,

void myStuff(boolean isr) {
   // whatever
}

ISR(TIMER1_COMPA_vect) {
  myStuff(true);
}

inline void invokeMyStuff() {
   cli();
   myStuff(false);
   sei();
}

void loop() {
   invokeMyStuff();
}

Thank you for hints about disabling the interrupts temporarily to avoid race conditions. Now my two steppers are running and changing speeds smoothly and 100% glitch-free driven by a timed interrupt.

Regards

Glad you got it working. I'd be interested to see your code as one day I'm going to pull my finger out and build a tabletop CNC "something".

Andrew

Sure thing :-) I just have to "polish" it a little. And by saying that, I mean cleaning it just enough for other people not to be (too) scared ;-)

Oh, maybe you'll be interested in my other thread at ladyada's tea party: http://forums.ladyada.net/viewtopic.php?f=31&t=10630

Regards!