Interrupt numbering mismatch: MEGA 2560

I am working with "Another Frequency Counter" program in Nick Gammon's excellent notes on Timers and Counters (Gammon Forum : Electronics : Microprocessors : Timers and counters). This is the example that works by counting the interval between rising edges. I tested on my UNO first and it worked just fine. But in trying to convert it to run on a MEGA 2560 I came across what appears to me to be an Interrupt numbering mismatch between those used in the Arduino AttachInterrupt / DetachInterrupt commands and the ATMEL numbering for the MEGA 2560.

According to the Arduino reference the Mega2560 mapping is:
int.0 pin 2
int.1 pin 3
int.2 pin 21
int.3 pin 20
int.4 pin 19
int.5 pin 18

So I decided to use int.5 on pin D18 but then I noticed that maps to pin 46 on the MEGA2560 chip ("PD3/TXD1/INT3")
This suggests that if I use AttachInterrupt(5,isr,rising) with the signal coming into D18 I am actually using MEGA interrupt 3 and Timer/Counter 3 !

Checking the MEGA2560 pin mapping http://arduino.cc/en/Hacking/PinMapping2560 further suggests the true mapping is:

Arduino MEGA2560
int.0 pin 2 interrupt/counter 4
int.1 pin 3 interrupt/counter 5
int.2 pin 21 interrupt/counter 0
int.3 pin 20 interrupt/counter 1
int.4 pin 19 interrupt/counter 2
int.5 pin 18 interrupt/counter 3

Am I interpreting this correctly?

Interestingly when I convert Nick Gammons example from interrupt 0 to interrupt 5 with the signal on D18 it does read the frequency correct, but only on the first reading. I have yet to try using Attachinterrupt(5...) and timer/counter 3, but will do so if my understanding above proves correct

thanks

Since posting I adapted my code to use timer/counter 3, interrupt 3 and Attach/DetachInterrupt 5, and it works perfectly on my MEGA2560. So my listing of the numbering mismatch above seems to be correct.

If anyone is interested, here is the code:

#define CJ_ID "Wavelength2560 version:C"

/* Frequency counter using Timer 3 to work out the interval  (i.e wavelength) 
by counting between two consecutive rising interrupts (leading edge) on pin D18 (int3). 

Based on Nick Gammon's similar program for Atmel 328P processor, here:
http://www.gammon.com.au/forum/?id=11504

Adapted for MEGA2560 by Chris Jennings, 8 May 2014.

Timer 3 is a high-precision 16-bit timer. By using no prescaler the timer counts
every clock cycle (62.5nS at 16 MHz). We deduce the frequency by multiplying the
counts between the leading edges by 62.5.

An advantage of this method is the quick calculation. e.g. at 10kHz the period
is 1/10000sec (100µS) so we  get our result in just 100µS.

Note: Beware the mismatch in interrupt numbers used on MEGA2560 versus the Arduino
Attach/DetachInterrupt commands, as follows:

  Arduino             MEGA2560
int.0	pin D2   interrupt/counter 4
int.1	pin D3   interrupt/counter 5
int.2	pin D21  interrupt/counter 0
int.3	pin D20  interrupt/counter 1
int.4	pin D19  interrupt/counter 2
int.5	pin D18  interrupt/counter 3 (THIS IS WHAT IS USED BELOW) */

volatile boolean first;
volatile boolean triggered;
volatile unsigned long overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;

void isr () {                      // here on rising edge
  unsigned int counter = TCNT3;    // quickly save it
  if (triggered) return;           // wait until we noticed last one
  if (first) {
    startTime = (overflowCount << 16) + counter;
    first = false;
    return;  
    }
  finishTime = (overflowCount << 16) + counter;
  triggered = true;
  detachInterrupt(5);               // interrupt 3 off
  }

ISR (TIMER3_OVF_vect) {overflowCount++;}// timer overflows (every 65536 counts)

void prepareForInterrupts (){      // get ready for next time
  EIFR = bit (INTF3);              // clear flag for interrupt 3
  first = true;
  triggered = false;               // re-arm for next time
  attachInterrupt(5, isr, RISING); // initialise interrupt 3 
  }

void setup () {
  Serial.begin(115200); Serial.println(CJ_ID);
  Serial.println("Calculate frequency on pin D18 from wavelength");
  TCCR3A = 0;                      // reset Timer 3
  TCCR3B = 0;
  TIMSK3 = bit (TOIE3);            // Timer 3 - enable interrupt on overflow 
  TCNT3 = 0;                       // zero it
  overflowCount = 0;  
  TCCR3B =  bit (CS30);            // start Timer 3, no prescaling
  prepareForInterrupts ();         // set up for interrupts
  }

void loop (){
  if (!triggered) return;
  unsigned long elapsedTime = finishTime - startTime;
  float freq = F_CPU / float (elapsedTime);  // each tick is 62.5 nS at 16 MHz
  Serial.print ("Counts: "); Serial.print (elapsedTime); 
  Serial.print ("  Freq: "); Serial.print (freq); Serial.println ("Hz. ");
  delay (500);
  prepareForInterrupts ();   
  }

I know this is an ancient topic, about a historic issue, but if anyone has an explanation for this INT reassignment on the Atmega2560 then please point me in the right direction.

Thank you Kindly.

k7michal:
I know this is an ancient topic, about a historic issue, but if anyone has an explanation for this INT reassignment on the Atmega2560 then please point me in the right direction.

Just as the Arduino pin numbers do not necessarily match the ATmega pin numbers, the Arduino external interrupt numbers don't necessarily match the ATmega external interrupt numbers. Like many numbering systems, they evolve as needed to fit new circumstances.

thank you.

In particular, the AVR has "External Interrupt numbers" that it labels INT0, INT1, and so on. These don't match up with bit0 or bit1 of any port, and are scattered across multiple ports on MEGA2560.
The original design of attachInterrupt() uses the AVR designation (0 for INT0, etc) This was probably a mistake (they should have mapped the arduino pin numbers internally (although having attachInterrupt(2,...) be legal when (0,...) wasn't isn't exactly intuitive, either.)

Things got worse on MEGA, where the Arduino pins were arranged by function rather than port number, so all the serial ports are together, all the PWMs together. But the AVR ports and the interrupts are pretty scattered.

The standard now is to use:

attachInterrupt(digitalPinToInterrupt(pin), isrfunc, mode);

Where "digitalPinToInterrupt(pin)" is a relatively "new" feature. ("pin" is the Arduino pin number. But you have to make sure that it's capable of causing an interrupt!)

Make sure you have one of these,

Mega2560 Pinout.pdf (510 KB)