Pages: [1] 2   Go Down
Author Topic: External interrupt fires early?  (Read 1587 times)
0 Members and 1 Guest are viewing this topic.
Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a 1 Hz square wave connected to INT1, free-running so it is asynchronous WRT the µC. Using the following sketch, the interrupt appears to fire as soon as it's enabled; I consistently see 999 as the first number output. Then the time to the second interrupt varies, and is less than one second. I was expecting the opposite, i.e. the first number should be some random value less than one second, and then the rest should be one second apart.

I've been poring over the datasheet and I can't find anything that would indicate this behaviour, hoping someone can help. I've checked the interrupt flag (INTF1 in EIFR) to ensure it's not set going in, and it's not, have tried resetting it anyway, no joy, etc. etc.

Code:
#include <Streaming.h>    //http://arduiniana.org/libraries/streaming/

#define LED LED_BUILTIN

volatile boolean int1Flag;
boolean ledState;

void setup(void)
{
    delay(1000);
    Serial.begin(115200);
    pinMode(LED, OUTPUT);

    EICRA = _BV(ISC11);          //external interrupt 1 on falling edge
    EIMSK = _BV(INT1);           //enable external interrupt 1
}

void loop(void)
{
    if (int1Flag) {
        int1Flag = false;
        digitalWrite(LED, ledState = !ledState);
        Serial << millis() << endl;
    }
}

ISR(INT1_vect)
{
    int1Flag = true;
}

Typical output that I see:

Code:
999
1652
2652
3652
4652
--------
999
1056
2056
3056
4056
-------
999
1841
2840
3841
4840

I would have expected:

Code:
652
1652
2652
3652
4652
--------
56
1056
2056
3056
4056
--------
841
1841
2840
3841
4840
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 143
Posts: 5309
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Did you try setting the pin as an input and using the pullup resistor?
Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Did you try setting the pin as an input and using the pullup resistor?

Yes I did, it didn't make a difference.
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I also tried using an Arduino to supply the 1 Hz signal, same results. Would have been surprised if that had made a difference, but it eliminates another possibility, if a remote one.
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Norfolk UK
Offline Offline
Edison Member
*
Karma: 65
Posts: 2457
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

what happens if you put varying length delays before enabling the interrupt, does that alter the 999 value.
Logged

There is no such thing as a stupid question but there are a lot of inquisitive idiots.

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

what happens if you put varying length delays before enabling the interrupt, does that alter the 999 value.

Yes, for example, with delay(2000) instead, I get:

Code:
1999
2787
3787
4788
5788
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

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


Board?  (I don't think that matters but, at this point, it's a good idea to assume nothing.)
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Board?  (I don't think that matters but, at this point, it's a good idea to assume nothing.)

Chip-on-a-breadboard with Optiboot, telling the IDE it's an Uno smiley-grin  Would be easy enough to try a real one, though.
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

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


Try this...

Code:
    noInterrupts();
    EICRA = _BV(ISC11);          //external interrupt 1 on falling edge
    EIMSK = _BV(INT1);           //enable external interrupt 1
    EIFR = _BV(INTF1);
    interrupts();
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Try this...

That did it! I had tried resetting the interrupt flag, and I had tried inhibiting interrupts, but I hadn't put them together. Investigating further, it sure looks like the act of enabling the INT1 interrupt causes the interrupt flag to be set. This code

Code:
#include <Streaming.h>    //http://arduiniana.org/libraries/streaming/

#define LED LED_BUILTIN

volatile boolean int1Flag;
boolean ledState;
uint8_t eifr1, eifr2;

void setup(void)
{
    delay(1000);
    Serial.begin(115200);
    pinMode(LED, OUTPUT);

    cli();
    EICRA = _BV(ISC11);          //external interrupt 1 on falling edge
    eifr1 = EIFR;
    EIMSK = _BV(INT1);           //enable external interrupt 1
    eifr2 = EIFR;
    EIFR = _BV(INTF1);
    sei();
   
    Serial << "EIFR1=0x" << _HEX(eifr1) << " EIFR2=0x" << _HEX(eifr2) << endl;
}

void loop(void)
{
    if (int1Flag) {
        int1Flag = false;
        digitalWrite(LED, ledState = !ledState);
        Serial << millis() << endl;
    }
}

ISR(INT1_vect)
{
    int1Flag = true;
}

results in

Code:
EIFR1=0x0 EIFR2=0x2
1321
2322
3322
4323

I also discovered that using the Arduino interrupt functions causes the same undesirable behavior as my original code, so I feel just a little better:

Code:
#include <Streaming.h>    //http://arduiniana.org/libraries/streaming/

#define LED LED_BUILTIN

volatile boolean int1Flag;
boolean ledState;

void setup(void)
{
    delay(1000);
    Serial.begin(115200);
    pinMode(LED, OUTPUT);
    attachInterrupt(1, myInt1Handler, FALLING);
}

void loop(void)
{
    if (int1Flag) {
        int1Flag = false;
        digitalWrite(LED, ledState = !ledState);
        Serial << millis() << endl;
    }
}

void myInt1Handler(void)
{
    int1Flag = true;
}


Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

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

That did it!

Wow.  That's strange.  And annoying.  I know some of the interrupt types are automatically cleared when enabled.  I wonder if External Interrupts work differently by design, accident, or mistake.
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That did it!

Wow.  That's strange.  And annoying.  I know some of the interrupt types are automatically cleared when enabled.  I wonder if External Interrupts work differently by design, accident, or mistake.

Agree, not at all what I would have expected. Clearing on enable might make a little more sense. I wondered if it was some kind of latent thing, maybe while the bootloader did its thing or whatever, but it just doesn't make sense if the interrupt wasn't enabled along the way.

I sure appreciate your help on this one!
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

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

Does changing the interrupt direction to raising edge give the same behaviour?

Quote
//external interrupt 1 on falling edge

Lefty
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Does changing the interrupt direction to raising edge give the same behaviour?

Quote
//external interrupt 1 on falling edge

Lefty

Yes, I tried that too. Just verified it again as well.

I found these two comments in an application note, but they don't fit the scenario here. It looks to me like enabling the interrupt causes the interrupt.

Quote
4. When changing the ISCn bit, an interrupt can occur. Therefore, it is
recommended to first disable INTn by clearing its Interrupt Enable bit in the
EIMSK Register.
5. Before enabling an interrupt, it is recommended to clear the flag bit of the
corresponding interrupt because when the flag bit is set, the interrupt will be
triggered the moment we enable the interrupt.
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 3942
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

AHA! That app note was right. Setting the sense control bit (ISCxx) causes the interrupt. Using the code below, I didn't see it earlier, but by adding delay(1) I see it now. Wasn't seeing it before no doubt because the code was picking up EIFR before the four clock cycles it takes to respond to an interrupt.

Code:
#include <Streaming.h>    //http://arduiniana.org/libraries/streaming/

#define LED LED_BUILTIN

volatile boolean int1Flag;
boolean ledState;
uint8_t eifr1, eifr2;

void setup(void)
{
    delay(1000);
    Serial.begin(115200);
    pinMode(LED, OUTPUT);

    cli();
    EICRA = _BV(ISC11);          //external interrupt 1 on falling edge
    delay(1);            //   <------- AHA!
    eifr1 = EIFR;
    EIMSK = _BV(INT1);           //enable external interrupt 1
    eifr2 = EIFR;
    EIFR = _BV(INTF1);
    sei();
   
    Serial << "EIFR1=0x" << _HEX(eifr1) << " EIFR2=0x" << _HEX(eifr2) << endl;
}

void loop(void)
{
    if (int1Flag) {
        int1Flag = false;
        digitalWrite(LED, ledState = !ledState);
        Serial << millis() << endl;
    }
}

ISR(INT1_vect)
{
    int1Flag = true;
}

Output:

Code:
EIFR1=0x2 EIFR2=0x2
1909
2910
3909
4910
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Pages: [1] 2   Go Up
Jump to: