How to cancel a pending ISR from within another ISR?

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi,

 

I'm trying to cancel a pending ISR from another ISR that is triggered by a vector higher in the priority table (using Atmega8a).

 

here is the relevant code:

 

ISR(INT1_vect){ //external interrupt
	clearbit(TIMSK, OCIE1A); //Timer/Counter1, Output Compare A Match Interrupt DISABLE
	TIFR = (1 << OCF1A); //CLEAR OCF1A: Timer/Counter1, Output Compare A Match Flag
	mySerial_atmega8::write((byte)(0x55));
}

ISR(TIMER1_COMPA_vect){ //compare interrupt
	mySerial_atmega8::write((byte)(0xF8));
}

 

The problem is that the TIMER1 Compare A interrupt executes (intermittently) even after the externally triggered INT1 ISR executes (INT1 interrupt has higher priority).

 

So I'm thinking that if the Compare A interrupt happens a few micro, nano seconds or perhaps a few clock cycles before INT1 triggers, does it mean that it's already pending an that clearing the OCIE1A and OCF1A bits does not prevent it from executing right after the INT1 ISR is finished? If so, how could it canceled?

 

here is an oscilloscope screenshot showing 0xF8 right after 0x55, it happens often but not always.

 

Yellow is the external INT1, triggering on the rising edge.

Red is the Tx pin.

 

 

 

I've also tried a slight modification to see if the OCF1A bit really gets cleared, and it seems that it doesn't because I get the same result on the scope, i.e. 0x55 gets sent.

 

ISR(INT1_vect){ //external interrupt
    clearbit(TIMSK, OCIE1A); //Timer/Counter1, Output Compare A Match Interrupt DISABLE
    TIFR = (1 << OCF1A); //CLEAR OCF1A: Timer/Counter1, Output Compare A Match Flag
    if (!(readbit(TIFR, OCF1A))){
        mySerial_atmega8::write((byte)(0x55));
    }   
}

ISR(TIMER1_COMPA_vect){ //compare interrupt
    mySerial_atmega8::write((byte)(0xF8));
}

 

thanks for any ideas

 

Attachment(s): 

Last Edited: Wed. Mar 4, 2015 - 09:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Um. Set a volatile flag some where and include an if statement in the ISR you want to "stop"?

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the externally triggered INT1 ISR executes (INT1 interrupt has higher priority).

On an AVR8, interrupt priorities have little impact in general use.  In a typical app with several interrupt sources enabled, the only time they come into play is when there are more than one triggered but unserviced interrupts.  Example, to add on to your code:  A USART interrupt is being serviced, and it takes some microseconds.  During the time the USART interrupt is being serviced, both your external interrupt and the timer interrupt are triggered.  When the USART interrupt servicing is complete and the RETI executed, one instruction from the mainline is executed.  Then the highest-priority enabled interrupt is serviced.

 

In scores and scores of production AVR8 apps, I can't recall any such races except a couple ICP applications where the timer could roll over right around the ICP point.  So, in general, I'd re-think the cause of your race.

 

But certainly, you can clear the timer flag in the external interrupt ISR.  And it looks like you are approaching it as I would.  Perhaps it takes a clock otr two for the clear to propagate--try putting a few NOPs between the TIFR clear and the subsequent readbit().

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In theory,   you can clear OCF1A inside the ISR(INT0_vect) and the ISR(TIM1_COMPA_vect) will never fire.

 

I suspect that if you hardwired OC1A to the INT0 pin,   both INTF0 and OCF1A will be set simultaneously.   

The INT0_vect will be serviced first.

 

You may need to use some sophisticated hardware to get both flags set together.

Mind you,   just hardwiring INT0 and INT1 pins should set both INTF0 and INTF1.    And INT0_vect will have priority over INT1_vect.

 

The real mystery is:  "Why do you want to do this?"

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Um. Set a volatile flag some where and include an if statement in the ISR you want to "stop"?

I thought about it and it might be a good solution, but I wanted to see if I can do it differently, and understand why this problem is happening in the first place.

 

@theusch

 

During the time the USART interrupt is being serviced, both your external interrupt and the timer interrupt are triggered.  When the USART interrupt servicing is complete and the RETI executed, one instruction from the mainline is executed.  Then the highest-priority enabled interrupt is serviced.

But in my case the UART interrupt (Serial write 0xF8) is serviced after the external interrupt (Serial write 0x55) and that's whats' puzzling me since the compare A and timer 1 interrupt flag are cleared. Unless my assumption is correct, i.e. the 0xF8 ISR gets triggered a few clock cycles before the 0x55 gets triggered and so it is pending and the clearing of the compare and interrupt flags do not cancel it, it just gets moved and executes after 0x55 finishes.

 

But certainly, you can clear the timer flag in the external interrupt ISR. And it looks like you are approaching it as I would. Perhaps it takes a clock otr two for the clear to propagate--try putting a few NOPs between the TIFR clear and the subsequent readbit().

I added 10 NOPs but it did not help, the if statement still executes:

 

__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");	

        if (!(readbit(TIFR, OCF1A))){
		mySerial_atmega8::write((byte)(0x55));
	}	

@david.prentice

 

In theory,   you can clear OCF1A inside the ISR(INT0_vect) and the ISR(TIM1_COMPA_vect) will never fire.

What's the difference? I'm doing that in INT1_vect, should be the same thing.

 

The real mystery is:  "Why do you want to do this?"

This for a - audio pulse to MIDI clock converter - , a related topic: https://www.avrfreaks.net/forum/f...

Last Edited: Wed. Mar 4, 2015 - 10:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A compare will re-trigger every time the timer cycles around ?

A good sanity check is to change slow operations like Uart SEND, to  a Pin-toggle inside each interrupt.

Then you can easily see what is enabled/disabled.