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();
}