Pages: [1] 2 3   Go Down
Author Topic: Interrupt still happening after detached. ( fix now available)  (Read 3191 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

EDIT: The problem is an interrupt is happening when it is not expected. Actually, as Dave explains, it's being triggered before the attach call, not after the detach call (which I first thought). There is now a work-around available.


I wrote a simple sketch to play with interrupts.  When the led is on, the interrupt is attached. When the led is off, the interrupt is detached.  However, if I pulse the input pin low while the interrupt is detached, the isr still gets called.  Any insight?

Let's see if this "copy for forum" option works.
Quote

volatile long interrTime;   //micros() when isr0 is called

void setup() {
  pinMode(2, INPUT);         //interrupt 0
  pinMode(13, OUTPUT);       //LED
  digitalWrite(2, HIGH);      //pullup 2
  Serial.begin(9600);
}

void loop() {
  digitalWrite(13, HIGH);                //led on
  attachInterrupt(0, isr0, FALLING);     //enable interrupt
  delay(3000);                           //wait 3 seconds
  detachInterrupt(0);                    //disable interrupt
  digitalWrite(13, LOW);                 //led off

  Serial.print("interrTime = "  );      //print time of isr being called. "0" if not called.
  Serial.println(interrTime, DEC  );
  Serial.println(""  );
 
  interrTime = 0;                       //clear the interrupt time
  delay(3000);                          
}

void isr0 () {
  interrTime = micros();               //record time isr called
}




« Last Edit: April 23, 2011, 12:06:51 pm by Loudhvx » Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Floating pin.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

pin 2 is pulled up. I'm pulling down by touching a ground wire to it while the led is off (3 second interval).

The pin should be stabilized in that amount of time.

Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Board?
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

UNO board with Duemilanove bootloaded atmega328.

Further test show evidence this may be a bug (if it's not a programming issue on my part).  

It is not a hardware issue (ie floating pin).  I added a counter to the isr that increments every time the isr is called.  I also added a flag to indicate attached or detached, and another counter to increment every time the isr is called while interrupt is detached. These would be invalid interrupts.

While the interrupt is attached, the interrupt counter increments each time I ground the pin (many times actually, due to contact bounce). This is expected.

However, if I ground the pin multiple times while the interrupt is detached, the interrupt counter only increments 1 time, as does the invalid-interrupt counter. (If I don't ground the pin at all, there is no increment.)

This would imply there is at least one interrupt that will occur after the interrupt is detached (if the interrupting action occurs).  This would be a bug, no?
 
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I wonder if this would explain some of the interrupt headaches so many seem to have. (me included)
« Last Edit: April 22, 2011, 12:43:33 pm by Loudhvx » Logged

Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 7
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote from: Loudhvx
...a bug, no?

Well, there is a bug in the program, not a bug in Arduino or ATmega.


Here's the deal:

If an edge-triggered interrupt condition occurs while the interrupt is enabled, the interrupt flag for that particular condition is set and the the Interrupt Service Routine is executed.  The interrupt flag is automatically reset when the program returns from the ISR.

However...

If an edge-triggered interrupt condition occurs while the interrupt is disabled, the interrupt flag is set but the Interrupt Service Routine is not executed.  That is, the ATmega remembers that an interrupt condition has occurred.  Then, when you re-enable the interrupt, the interrupt flag causes the ISR to be executed immediately.

Bottom line: Make sure the interrupt flag is reset before re-enabling the interrupt.

Maybe something like the following:
Code:
.
.
.
void loop()
{
    digitalWrite(13, HIGH);               //led on
    //
    // Write 1 to Interrupt Flag 0 to make sure it is reset
    //
    EIFR = (1 << INTF0);
    attachInterrupt(0, isr0, FALLING);     //enable interrupt
.
.
.

Regards,

Dave
« Last Edit: April 22, 2011, 03:44:26 pm by davekw7x » Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The interrupt flag is automatically reset when the program returns from the ISR.

As far as I can tell from the 328 datasheet, the flag is cleared when the ISR is called not when it returns.
Logged

Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 7
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

...flag is cleared when the ISR is called not when it returns.

I don't disagree.


Actual wording is
"The flag is cleared when the interrupt routine is executed."

Now, if people are using un-debounced inputs for edge-triggered interrupts, maybe it could make a difference whether the flag is cleared going-into or coming-out-of, but for me all bets would be off anyhow.  I mean, the mind boggles and the flabber is gasted...


Regards,

Dave
« Last Edit: April 22, 2011, 03:45:30 pm by davekw7x » Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17303
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Having played with interrupts some, and while not an expert by far, my advice is to simply not use detachInterrupt(0);, as there are better ways to structure your program then rely on it.

 It's not unlike using Serial.flush, while it may have a rare useful purpose once and a while, it almost always is either mistake to use or comes with side effects.


Lefty
                   
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bug?  Feature?  Someone else will have to decide.  In my opinion it's a bug because the behaviour deviates from what is expected.

@Loudhvx: What do you want?  Are you looking for a solution to this problem?  Or are you trying to report a bug?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26522
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
In my opinion it's a bug because the behaviour deviates from what is expected.
But if that is what is documented in the processor datasheet, the behaviour is exactly as expected.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 504
Posts: 19095
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have reproduced it on a Uno.

Extensive reading and testing seems to indicate what the problem is. Rather bizarrely the processor, when attachInterrupt is called, can "remember" whether the interrupt condition has already been met. Hence, if you ground the pin, and then call attachInterrupt, the interrupt fires.

This proves it:

Code:
volatile int flag = 0;

void setup() {
  Serial.begin (115200);
  digitalWrite(2, HIGH);      //pullup 2

  pinMode(13, OUTPUT);       //LED
  Serial.println ("go!");
  digitalWrite(13, HIGH);                 //time to go!
  delay (5000);
  digitalWrite(13, LOW);                 //time is up!
  
   // interrupt on
  attachInterrupt(0, isr0, FALLING);     //enable interrupt

  // did we get an interrupt?
  Serial.println (flag, DEC);
  }

void loop() {}

void isr0 () {
  flag = 1;
}

There is no detachInterrupt there. After the sketch starts and displays "go" you have 5 seconds to ground (and release) pin 2. If you do, and only if, then it displays 1, otherwise it displays 0. And this is despite the fact that you generate the "interrupt" before interrupts are enabled on that pin.

Now, add this line just before attaching the interrupt:

Code:
EIFR = 1;

That clears the interrupt flag (for interrupt 0). According to the datasheet:

Quote
The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it.

So this is manually clearing the "I saw an interrupt" flag, before enabling interrupts.

Arguably, attachInterrupt should do this. And note that detachInterrupt has no effect on the flag at all.

I don't know whether there would be programs around that rely on interrupts being "pre-triggered" before you even attach the interrupt. Perhaps there are.

Note that if you are using interrupt 1, it would be:

Code:
EIFR = 2;
Logged


Offline Offline
Jr. Member
**
Karma: 0
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bug?  Feature?  Someone else will have to decide.  In my opinion it's a bug because the behaviour deviates from what is expected.

@Loudhvx: What do you want?  Are you looking for a solution to this problem?  Or are you trying to report a bug?

I agree, as far as I'm concerned, it's a bug in the Arduino system. Not an Atmega bug, but as far as anyone programming an Arduino using the Arduino Reference documentation, it's a bug.  

I don't think it matters if the input is a de-bounced switch or not. The same bug would happen with any pulsing input were applied.  I produced the input pulse several seconds before the false interrupt happened. The same could happen with an encoder etc.

I think there should be some sort of note in the Attach/Detach Reference if an interrupt can be triggered by some event that happened before the attach statement.  It may save someone a lot of frustration.  I chose Arduino because it's aimed at non-programmers like me.  

...maybe just a note to clear the flag or whatever before doing the attach statement.  Dave's and Nick Gammon's notes will surely be in my personal notes on the Arduino. Thanks for that.  I agree, I would have assumed that should have been taken care of in the Attach routine.

EIFR = 1;   // for interrupt 0
EIFR = 2;   // for interrupt 1

What would be better, or different etc.  using Dave's bit-shift statement (if that's what it is) or just Nick's simple assignment?
« Last Edit: April 22, 2011, 07:58:55 pm by Loudhvx » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 504
Posts: 19095
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Dave's is more correctly documented. However more accurately than what either of us suggested you should "or" it in (or you have the effect of clearing the other interrupt flag, almost certainly what you don't want). That is (one of):

Code:
   EIFR |= (1 << INTF0);    // clear any outstanding interrupt 0
    EIFR |= (1 << INTF1);    // clear any outstanding interrupt 1

You will find (depending on the processor however) INTF0 and INTF1 defined like this:

Code:
#define INTF0 0
#define INTF1 1

So 1 << 0 is going to be 1, and 1 << 1 is going to be 2, so we are using the same numbers. Dave's method just follows the mnemonics in the datasheet better, and probably translates better into different processors, which might have them defined as different values.
« Last Edit: April 22, 2011, 11:44:13 pm by Nick Gammon » Logged


Pages: [1] 2 3   Go Up
Jump to: