Grand Blanc, MI, USA
Offline
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« on: January 25, 2013, 11:32:54 am » |
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. #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: 999 1652 2652 3652 4652 -------- 999 1056 2056 3056 4056 ------- 999 1841 2840 3841 4840
I would have expected: 652 1652 2652 3652 4652 -------- 56 1056 2056 3056 4056 -------- 841 1841 2840 3841 4840
|
|
|
|
|
Logged
|
|
|
|
|
Valencia, Spain
Online
Edison Member
Karma: 65
Posts: 2249
|
 |
« Reply #1 on: January 25, 2013, 12:03:39 pm » |
Did you try setting the pin as an input and using the pullup resistor?
|
|
|
|
|
Logged
|
|
|
|
|
Grand Blanc, MI, USA
Offline
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #2 on: January 25, 2013, 12:28:04 pm » |
Did you try setting the pin as an input and using the pullup resistor?
Yes I did, it didn't make a difference.
|
|
|
|
|
Logged
|
|
|
|
|
Grand Blanc, MI, USA
Offline
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #3 on: January 25, 2013, 12:55:13 pm » |
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
|
|
|
|
|
Norfolk UK
Offline
Edison Member
Karma: 23
Posts: 1320
|
 |
« Reply #4 on: January 25, 2013, 01:06:56 pm » |
what happens if you put varying length delays before enabling the interrupt, does that alter the 999 value.
|
|
|
|
|
Logged
|
|
|
|
|
Grand Blanc, MI, USA
Offline
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #5 on: January 25, 2013, 01:27:28 pm » |
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: 1999 2787 3787 4788 5788
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 118
Posts: 10153
|
 |
« Reply #6 on: January 25, 2013, 01:46:04 pm » |
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
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #7 on: January 25, 2013, 01:55:37 pm » |
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  Would be easy enough to try a real one, though.
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 118
Posts: 10153
|
 |
« Reply #8 on: January 25, 2013, 02:14:32 pm » |
Try this... 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
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #9 on: January 25, 2013, 04:45:56 pm » |
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 #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 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: #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
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 118
Posts: 10153
|
 |
« Reply #10 on: January 25, 2013, 07:36:40 pm » |
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
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #11 on: January 25, 2013, 07:42:02 pm » |
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
|
|
|
|
|
Left Coast, CA (USA)
Offline
Brattain Member
Karma: 279
Posts: 15316
Measurement changes behavior
|
 |
« Reply #12 on: January 25, 2013, 07:43:46 pm » |
Does changing the interrupt direction to raising edge give the same behaviour? //external interrupt 1 on falling edge Lefty
|
|
|
|
|
Logged
|
|
|
|
|
Grand Blanc, MI, USA
Offline
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #13 on: January 25, 2013, 07:59:07 pm » |
Does changing the interrupt direction to raising edge give the same behaviour? //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. 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
|
|
|
|
|
Grand Blanc, MI, USA
Offline
Edison Member
Karma: 43
Posts: 2498
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #14 on: January 25, 2013, 08:06:43 pm » |
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. #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: EIFR1=0x2 EIFR2=0x2 1909 2910 3909 4910
|
|
|
|
|
Logged
|
|
|
|
|
|