An appearent bug in the Mega1280 IRQs 2-5

The routine below demos an appearent bug in the Mega1280 IRQs 2-5. The routine triggers each IRQ on the Mega1280 with a digitalwrite to a trigger pin wired to the IRQ pin. After the second IRQ is triggered, the remainder will be triggered by digitalwrites to another pin, not the one wired to the IRQ pin and its trigger. Can anyone shed light on this. To run the demo you need a Mega1280 and 6 jumper leads.

The routine first detaches all interrupt services, then in sequence from IRQ 0 to 5, an IRQ is enabled and attached to its ISR and then triggered by a signal from the digital IO pin jumpered to the IRQ pin. Six leads are jumpered, one for each interrupt and trigger.

What is observed is that IRQs 0 & 1 behave differently than 2-5. IRQs 0 & 1 behave as documented, and only trigger a RISING interrupt when a digitalwrite on the OUTPUT pin wired to the IRQ changes the pin state from LOW to HIGH. However, IRQs 2-5 will trigger on digitalwrites to pins not wired to the IRQ pin! Further, physically detaching the lead from the trigger pin being written (not the lead from the IRQ pin to its trigger) still triggers the interrupt in spite of having no jumper from the pin getting the digitalwrite. The unjumpered trigger pin that causes the erroneous IRQ is always the first pin in the TriggerPin list (see code) regardless of the actual pins in the list.

Can anyone shed light on this or find a flaw in the routine to explain the output? It's been tested on three Mega1280s from two different vendors with identical results. To run the demo you need a Mega1280 and 6 jumpers. Jumper the leads as
pins {46,47,48,49,50,51} to {2,3,18,19,20,21} , e.g: jumper pin 46 to pin 2, etc. Setup all the jumpers and then load and run the routine. The source includes two other (commented out) lists of trigger pins (the 46-51 above), one using just Port A pins, and another using different ports for the triggers: both lists behave like the default in my tests.

/* Exercise IRQ triggers

This routine exercises each interrupt & its assigned pin on a Mega1280. It sets output pins Low then High to trigger an interrupt. Only one interrupt should happen per loop (see "for (Ei=0;Ei<6;Ei++) { // for all 6 IRQs and IRQ pins, set a current IRQ and Pin to use in Ej loop"), as only one Input Pin/IRQ is set for input and attached per iteration. That input pin is
connected to a single output pin that changes state only one time to trigger the interrupt. What is observed here, however, is that IRQs are flagged from triggers being sent to pins not directly wired to the IRQ input pin, shown in the serial monitor report in the lines with  "|| Trigger pin"

To use this routine, jumper Mega1280 digital IO pins {46,47,48,49,50,51} to IRQ Pins {2,3,18,19,20,21} (e.g.: jumper pin 46 to Pin 2, etc), then upload and run this routine.  The serial monitor will show a table of trigger pins and flagged IRQs (example below).
Each line should have only one "Trigger Pin" result, e.g: "| Trigger pin 46 while wired to pin 2 triggered IRQ 0 on pin 2| Ei:Ej=0:0|", and never a "||" result which indicates that two (+) different trigger pins each flagged the interrupt.

Example Output (same for three different Mega1280s):
====================================
Mega1280 Pins & IRQs-> Pin 2:IRQ0, Pin 3:IRQ1, Pin 18:IRQ5, Pin 19:IRQ4, Pin 20:IRQ3, Pin 21:IRQ2.
| Trigger pin 46 while wired to pin 2 triggered IRQ 0 on pin 2| Ei:Ej=0:0|
| Trigger pin 47 while wired to pin 3 triggered IRQ 1 on pin 3| Ei:Ej=1:1|
| Trigger pin 46 while wired to pin 2 triggered IRQ 5 on pin 18| Ei:Ej=2:0|| Trigger pin 48 while wired to pin 18 triggered IRQ 5 on pin 18| Ei:Ej=2:2|
| Trigger pin 46 while wired to pin 2 triggered IRQ 4 on pin 19| Ei:Ej=3:0|| Trigger pin 49 while wired to pin 19 triggered IRQ 4 on pin 19| Ei:Ej=3:3|
| Trigger pin 46 while wired to pin 2 triggered IRQ 3 on pin 20| Ei:Ej=4:0|| Trigger pin 50 while wired to pin 20 triggered IRQ 3 on pin 20| Ei:Ej=4:4|
| Trigger pin 46 while wired to pin 2 triggered IRQ 2 on pin 21| Ei:Ej=5:0|| Trigger pin 51 while wired to pin 21 triggered IRQ 2 on pin 21| Ei:Ej=5:5|
====================================

*/

volatile int IntFlagged = false;		// ISR set flags- volatile vars set by the ISR to flag the polling check to service the encoder.
int IRQ_[6]  = {0,1,5,4,3,2};			// interrupt assigned to IRQ_Pin[]
int IRQ_Pin[6]  = {2,3,18,19,20,21};		// see arduino schematic for IRQ:PinA assignments
int TriggerPin[6] = {46,47,48,49,50,51};  	// digital output pins to trigger IRQ
//int TriggerPin[6] = {22,23,24,25,26,27};  	// Use only Port A pins for digital outputs to trigger IRQ, must rejumper trigger pins to use, seems to have no effect
//int TriggerPin[6] = {41,53,37,36,49,22};	// Use different ports to trigger, must rejumper trigger pins to use, seems to have no effect
int TriggerState = LOW;				// initial state on trigger pins
int Ei,Ej,Ek;					// array indexes


void SetIntFlag() {				// ISR called, set flag
    IntFlagged = true;
}

void Check4IntFlag(void) {			// Check for ISR/IRQ flags, report if flag set.  Should only be one trigger/IRQ reported per line.
    if (IntFlagged == true) {
        Serial.print("| Trigger pin ");
        Serial.print(TriggerPin[Ej],DEC);
        Serial.print(" while wired to pin ");
        Serial.print(IRQ_Pin[Ej],DEC);
        Serial.print(" triggered IRQ ");
        Serial.print(IRQ_[Ei],DEC);
        Serial.print(" on pin ");
        Serial.print(IRQ_Pin[Ei],DEC);
        Serial.print("| Ei:Ej=");
        Serial.print(Ei,DEC);
        Serial.print(":");
        Serial.print(Ej,DEC);
        Serial.print("|");
        IntFlagged = false;
    }
}

void setup(void) {				// make one pass thorugh IRQ test logic

    Serial.begin(38400);
    delay(500);
    interrupts();
    Serial.println("Mega1280 Pins & IRQs-> Pin 2:IRQ0, Pin 3:IRQ1, Pin 18:IRQ5, Pin 19:IRQ4, Pin 20:IRQ3, Pin 21:IRQ2.");
    for (Ei=0;Ei<6;Ei++) {
        detachInterrupt(IRQ_[Ei]); 	  	// first detach all interrupts - clear strays
        pinMode(TriggerPin[Ei], OUTPUT);	// set trigger pins {46,47,48,49,50,51} to output
        pinMode(IRQ_Pin[Ei], INPUT);      	// set IRQ pins to input
        digitalWrite(IRQ_Pin[Ei], HIGH);    	// turn ON pullup resistors, out 5V @ 20K Ohm on pin
//        digitalWrite(IRQ_Pin[Ei], LOW);       // turn OFF pullup resistors,out 0v : to use, uncomment and comment out line above
    }

    for (Ei=0;Ei<6;Ei++) { 			// for all 6 IRQs and IRQ pins, set a current IRQ and Pin to use in Ej loop
        Serial.println();			// print a new line on serial monitor
        for (Ej=0;Ej<6;Ej++) {			// for all 6 TriggerPins in sequence, attach the interrupt and change state from LOW to HIGH
            TriggerState = LOW;			// set the trigger pin to low, then attach the interrupt service to the pin.
            digitalWrite(TriggerPin[Ej], TriggerState);
            IntFlagged = false;			// clear flag so Check4IntFlag will fail and nothing reported, then attach interrupt.
            attachInterrupt(IRQ_[Ei], SetIntFlag, RISING);
            TriggerState = !TriggerState;	// now HIGH, will interrupt on rising edge
            digitalWrite(TriggerPin[Ej], TriggerState);// trigger irq service, should set IntFlagged to true and be reported by Check4IntFlag().
            detachInterrupt(IRQ_[Ei]);		// free the IRQ pin and detach from interrupt service
            Check4IntFlag();			// report if IRQ flagged
        }
    }

    Serial.println();
    Serial.println("====================================");
}

void loop(void) {
    Check4IntFlag();
}

Does this make a difference...

void setup(void) { // make one pass thorugh IRQ test logic

Serial.begin(38400);
delay(500);
interrupts();
Serial.println("Mega1280 Pins & IRQs-> Pin 2:IRQ0, Pin 3:IRQ1, Pin 18:IRQ5, Pin 19:IRQ4, Pin 20:IRQ3, Pin 21:IRQ2.");
for (Ei=0;Ei<6;Ei++) {
detachInterrupt(IRQ_[Ei]); // first detach all interrupts - clear strays
pinMode(TriggerPin[Ei], OUTPUT); // set trigger pins {46,47,48,49,50,51} to output
pinMode(IRQ_Pin[Ei], INPUT); // set IRQ pins to input
digitalWrite(IRQ_Pin[Ei], HIGH); // turn ON pullup resistors, out 5V @ 20K Ohm on pin
// digitalWrite(IRQ_Pin[Ei], LOW); // turn OFF pullup resistors,out 0v : to use, uncomment and comment out line above
}

for (Ei=0;Ei<6;Ei++) { // for all 6 IRQs and IRQ pins, set a current IRQ and Pin to use in Ej loop
Serial.println(); // print a new line on serial monitor
for (Ej=0;Ej<6;Ej++) { // for all 6 TriggerPins in sequence, attach the interrupt and change state from LOW to HIGH
TriggerState = LOW; // set the trigger pin to low, then attach the interrupt service to the pin.
digitalWrite(TriggerPin[Ej], TriggerState);
IntFlagged = false; // clear flag so Check4IntFlag will fail and nothing reported, then attach interrupt.
EIFR = 0;
attachInterrupt(IRQ_[Ei], SetIntFlag, RISING);
TriggerState = !TriggerState; // now HIGH, will interrupt on rising edge
digitalWrite(TriggerPin[Ej], TriggerState);// trigger irq service, should set IntFlagged to true and be reported by Check4IntFlag().
detachInterrupt(IRQ_[Ei]); // free the IRQ pin and detach from interrupt service
Check4IntFlag(); // report if IRQ flagged
}
}

Serial.println();
Serial.println("====================================");
}

Hi and thanks.

No, adding the EIFR=0; had no effect.

The bug might be in the attachInterrupt code....
As everything is non atomic in the Arduino core, nothing, so it is very very prone to errors.

Sounds like you have floating inputs.

Hi MarkT,

Thanks for taking the time to look at this.

Doesn't this section of the code speak to your notion:
" pinMode(IRQ_Pin[Ei], INPUT); // set IRQ pins to input
digitalWrite(IRQ_Pin[Ei], HIGH); // turn ON pullup resistors, out 5V @ 20K Ohm on pin
"
As that is the only INPUT assertion, and if I understand the notion of the pullup resistors, it's not floating, it's pulled up to +5V. Maybe, the 20K internal resistor is inadequate to sink the current without a ripple and that creates a float. I can test that (again).

I have tried the logic with both pullup and not pullups set, iirc, the output didn't change.

Manifestly, something is causing enough of a voltage ripple to trigger an IRQ. What I have most recently tried is two Mega1280s, one as the trigger server and the other as the IRQ client- that works as documented, with all IRQs triggering once per run, and none triggering from signals to other pins. That reinforces my suspicion that the current that triggers the IRQ is not sourced from a jumper wire to an IRQ pin, but instead is from the digitalwrite of the first trigger somehow changing the ground potential and causing a voltage ripple, or something like it. When using two Mega1280s, the digitalwrites are segregated to the trigger server which has no IRQs set or attached.

Does this only generate INT 4 or do other interrupts also fire...

void setup(void) { // make one pass thorugh IRQ test logic

Serial.begin(38400);
delay(500);
interrupts();
Serial.println("Mega1280 Pins & IRQs-> Pin 2:IRQ0, Pin 3:IRQ1, Pin 18:IRQ5, Pin 19:IRQ4, Pin 20:IRQ3, Pin 21:IRQ2.");
for (Ei=0;Ei<6;Ei++) {
detachInterrupt(IRQ_[Ei]); // first detach all interrupts - clear strays
pinMode(TriggerPin[Ei], OUTPUT); // set trigger pins {46,47,48,49,50,51} to output
pinMode(IRQ_Pin[Ei], INPUT); // set IRQ pins to input
digitalWrite(IRQ_Pin[Ei], HIGH); // turn ON pullup resistors, out 5V @ 20K Ohm on pin
// digitalWrite(IRQ_Pin[Ei], LOW); // turn OFF pullup resistors,out 0v : to use, uncomment and comment out line above
}

for (Ei=0;Ei<6;Ei++) { // for all 6 IRQs and IRQ pins, set a current IRQ and Pin to use in Ej loop
Serial.println(); // print a new line on serial monitor
for (Ej=0;Ej<6;Ej++) { // for all 6 TriggerPins in sequence, attach the interrupt and change state from LOW to HIGH
TriggerState = LOW; // set the trigger pin to low, then attach the interrupt service to the pin.
digitalWrite(TriggerPin[Ej], TriggerState);
IntFlagged = false; // clear flag so Check4IntFlag will fail and nothing reported, then attach interrupt.
attachInterrupt(IRQ_[Ei], SetIntFlag, RISING);
TriggerState = !TriggerState; // now HIGH, will interrupt on rising edge

// digitalWrite(TriggerPin[Ej], TriggerState);// trigger irq service, should set IntFlagged to true and be reported by Check4IntFlag().
digitalWrite(TriggerPin[3], TriggerState);// trigger irq service, should set IntFlagged to true and be reported by Check4IntFlag().

detachInterrupt(IRQ_[Ei]); // free the IRQ pin and detach from interrupt service
Check4IntFlag(); // report if IRQ flagged
}
}

Serial.println();
Serial.println("====================================");
}