// in vim, :set ts=2 sts=2 sw=2 et

// Enable Interrupts

=====================================================================================================
=====================================================================================================
ATmega328 Support
=====================================================================================================
=====================================================================================================

Interrupt pins:
Pin External           Pin  Pin Change       Pin  Pin Change
    Interrupt               Interrupt             Interrupt 
 3 INT1      PD3        0   PCINT16   PD0     A0  PCINT8    PC0
 2 INT0      PD2        1   PCINT17   PD1     A1  PCINT9    PC1
                        2   PCINT18   PD2     A2  PCINT10   PC2
                        3   PCINT19   PD3     A3  PCINT11   PC3
                        4   PCINT20   PD4     A4  PCINT12   PC4
                        5   PCINT21   PD5     A5  PCINT13   PC5
                        6   PCINT22   PD6
                        7   PCINT23   PD7
                        8   PCINT0    PB0
                        9   PCINT1    PB1
                        10  PCINT2    PB2
                        11  PCINT3    PB3
                        12  PCINT4    PB4
                        13  PCINT5    PB5

// The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.

// PIN CHANGE INTERRUPT REGISTER BESTIARY
// ATmega328p and similar (328, 168)
The pin change interrupt PCI2 will trigger if any enabled PCINT[23:16] pin toggles.
The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin toggles.
The pin change interrupt PCI0 will trigger if any enabled PCINT[7:0] pin toggles.
The PCMSK2, PCMSK1 and PCMSK0 Registers control which pins contribute to the pin change interrupts.
Pin change interrupts on PCINT23...0 are detected asynchronously. This implies that these interrupts
can be used for waking the part also from sleep modes other than Idle mode.

// GLOBALLY
SREG:  7   6   5   4   3   2   1   0  (AVR Status Register)
       I -Global Interrupt Enable bit  Set to enable interrupts.
      rw

// PIN CHANGE INTERRUPTS REGISTER BESTIARY
PCICR: 7   6   5   4   3   2   1   0  (When PCIE2 is set and GIE is set, PCI2 is enabled)
                       PCIE2   1   0   Likewise for 1 and 0.
       -   -   -   -   -  rw  rw  rw

PCMSK2:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT23:16
  PCINT23           ...      PCINT16   If PCIE2 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
    PD7  PD6 PD5 PD4 PD3 PD2 PD1 PD0   =PORTD

PCMSK1:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT14:8
       - PCINT14    ...       PCINT8   If PCIE1 in PCICR and this bit is set, it is enabled on that
       r  rw  rw  rw  rw  rw  rw  rw   pin.)
         PC6 PC5 PC4 PC3 PC2 PC1 PC0   =PORTC

PCMSK0:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT7:0
  PCINT7            ...       PCINT0   If PCIE0 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0   =PORTB

// set...
PCIFR: 7   6   5   4   3   2   1   0  (When logic change triggers IRQ, bececomes set. Cleared when
                       PCIF2   1   0   IRQ is executed. PCIF2 == PCIE2, etc.)
       -   -   -   -   -  rw  rw  rw

// EXTERNAL INTERRUPTS REGISTER BESTIARY
For ATmega328p and the like.

INT0=pin2, INT1=pin3

EICRA: 7   6   5   4   3   2   1   0  (External Interrupt Control Register A)
                 ISC  11  10  01  00  Interrupt Sense Control Bits
       -   -   -   -  rw  rw  rw  rw

        ISC11 / ISC10 : INT1    ISC01 / ISC00
          0      0    Low       (similar to ISC11/10)
          0      1    Change
          1      0    Falling
          1      1    Rising

EIMSK:  7   6   5   4   3   2   1   0  (External Interrupt Mask Register)
                              INT1 INT0
        -   -   -   -   -   -  rw  rw   set to 1 to enable this interrupt

// set...
EIFR: INTF1: Bit 1: set when edge/logic chg on INT1 triggers IRQ.  Cleared  when IRQ executed.
      INTF0: Bit 0: set when edge/logic chg on INT0 triggers IRQ.  Cleared  when IRQ executed.


The INT0 and INT1 interrupts can be triggered by a falling or rising edge or a low level. This is
set up as indicated in the specification for the External Interrupt Control Register A – EICRA.
When the INT0 or INT1 interrupts are enabled and are configured as level triggered, the inter-
rupts will trigger as long as the pin is held low.
Low level interrupt on INT0 and INT1 is detected asynchronously. This implies that this interrupt
can be used for waking the part also from sleep modes other than Idle mode. The I/O clock is halted
in all sleep modes except Idle mode.

=============================================================================================

Fri Jan 23 21:51:01 CST 2015
PROBLEM:
I have a "dirty" switch: it bounces a lot when pressed. The bounces can occur on the order of
microseconds apart. So pretend I have turned on a port as an input port, and the pullup resistor
is on. I have enabled a Pin Change Interrupt on the pin. It will trigger on any level change.
So when I press the switch, the signal goes from high to low and the interrupt is triggered.

Notice that for Pin Change Interrupts, the interrupt can take place when any pin on the port is
interrupted. If you have the luxury of knowing ahead of time which pin(s) are interrupting, you
can design fast, custom code that will react to your simple situation. But remember that I am
writing a library: I don't know which pin may be doing the interrupting. So I have to survey the
pins to figure out which one(s) changed, and had triggered the interrupt. Furthermore, there is
an appreciable amount of time that it takes from the moment the triggering event happened to
when I enter the interrupt subroutine (ISR) and have gone through the logic to figure out which
pins did the triggering. ...How much time? That I aim to find out.

Why is this a big deal? Remember my bouncy switch? ...The interrupt triggers, the ISR starts up,
and the first thing I need to do is query the port to see the state of its pins. Well, some time
has elapsed since the triggering event and this query. In the course of that time, it's entirely
possible- and I'm writing this because it's not only possible, but it can happen quite readily-
that the state of the pin changes before I get a chance to sample it. So I get an interrupt but
it looks like a false alarm! The ISR never calls the user's function because none of the user's
interrupt pins appear to have changed.

There is no complete solution to this problem, because of the nature of Pin Change Interrupts.
All you can do is mitigate the situation. I will attempt to do so by capturing the state of the
port as early as possible in the ISR. The question is, how early is that?

I attempt a test: my ISR looks like this; this will turn on and off the Arduino Uno's pin 13 LED:

ISR(PORTC_VECT, ISR_NAKED) {
  uint8_t interruptMask;
  uint8_t ledon, ledoff;

  ledon=0b00100000; ledoff=0b0;

  PORTB=ledoff; // LOW
  PORTB=ledon;         // HIGH
  PORTB=ledoff; // LOW
  PORTB=ledon;         // HIGH
  PORTB=ledoff; // LOW
  (...)
}

The generated assembly code looks like this:

00000292 <__vector_4>:
  ledon=0b00100000; ledoff=0b0;

  PORTB=ledoff; // LOW
     292:       15 b8           out     0x05, r1        ; 5
  PORTB=ledon;         // HIGH
     294:       80 e2           ldi     r24, 0x20       ; 32
     296:       85 b9           out     0x05, r24       ; 5
  PORTB=ledoff; // LOW
     298:       15 b8           out     0x05, r1        ; 5
  PORTB=ledon;         // HIGH
     29a:       85 b9           out     0x05, r24       ; 5
  PORTB=ledoff; // LOW
     29c:       15 b8           out     0x05, r1        ; 5

Notice a little optimization here: r1 is defined to always contain 0, so we don't even have to load
a value from memory. 0 is an important number! This makes the initial command very quick, and by using
an oscilloscope we can see just how quickly the chip reacts after receiving the signal.
see just how fast 


***** MACRO vs. INLINE the ISR frontend **************************
The code compiles to very similar assembler. However, the inline is better looking C code.
Refer to the "testing0" branch for comparison.

I will use the INLINE method in the production code.
***** MACRO vs. INLINE the ISR frontend **************************

A lot of the basic Pin and Port definitions are in /usr/avr/include/avr/iom328p.h

================== ================== ================== ================== ==================

=====================================================================================================
=====================================================================================================
Leonardo Support LEONARDO
=====================================================================================================
=====================================================================================================

// Map SPI port to 'new' pins D14..D17
static const uint8_t SS   = 17;
static const uint8_t MOSI = 16;
static const uint8_t MISO = 14;
static const uint8_t SCK  = 15;
// A0 starts at 18


Interrupt pins:
Pin	External          	Pin	Pin Change
        Interrupt                       Interrupt
 3	INT0  PD0		8	PCINT4     PB4
 2	INT1  PD1		9	PCINT5     PB5
 0	INT2  PD2		10	PCINT6     PB6
 1	INT3  PD3		11	PCINT7     PB7
 7	INT6  PE6		SCK/15	PCINT1     PB1
				MOSI/16	PCINT2     PB2
				MISO/14	PCINT3     PB3
				SS/17	PCINT0     PB0 (on 3rd party boards)

on ICSP:
SCK/15: PCINT1 (PB1)
MOSI/16: PCINT2 (PB2)
MISO/14: PCINT3 (PB3)

PCINT0 (PB0) is RXLED and is not exposed as a pin on the Leonardo board.

External Interrupts ------------------------------------------------------------------------------

...it is recommended to first disable INTn by clearing its Interrupt Enable bit in the
EIMSK Register. Then, the ISCn bit can be changed. Finally, the INTn interrupt flag should be
cleared by writing a logical one to its Interrupt Flag bit (INTFn) in the EIFR Register before the
interrupt is re-enabled.

EICRA: 7   6   5   4   3   2   1   0  (External Interrupt Control Register A)
 ISC: 31  30  21  20  11  10  01  00  Interrupt Sense Control Bits
      rw  rw  rw  rw  rw  rw  rw  rw

EICRB: 7   6   5   4   3   2   1   0  (External Interrupt Control Register A)
 ISC:  -   -  61  60   -   -   -   -  Interrupt Sense Control Bits
      rw  rw  rw  rw  rw  rw  rw  rw

        ISCx1 / ISCx0 : INTx
          0      0    Low
          0      1    Change
          1      0    Falling
          1      1    Rising

EIMSK:  7   6   5   4   3   2   1   0  (External Interrupt Mask Register)
            n           n   n   n   n
        -  rw   -   -  rw  rw  rw  rw   set to 1 to enable this interrupt

n= INTn number

External Interrupt Flag Register is set to 1 when a signal generates an IRQ.
Cleared upon entering the ISR. Can be cleared by writing a 1 to it.
EIFR:   7   6   5   4   3   2   1   0  (External Interrupt Flag Register)
            n           n   n   n   n
        -  rw   -   -  rw  rw  rw  rw

n= INTn number


Pin Change Interrupts ---------------------------------------------------------------------------
// PIN CHANGE INTERRUPTS REGISTER BESTIARY
PCICR: 7   6   5   4   3   2   1   0  (When PCIE0 is set and GIE is set, PCI0 is enabled)
                               PCIE0
       -   -   -   -   -   -   -  rw

// set...
PCIFR: 7   6   5   4   3   2   1   0  (When logic change triggers IRQ, bececomes set. Cleared when
                               PCIF0   IRQ is executed. PCIF0 == PCIE0.)
       -   -   -   -   -   -   -  rw   Can be cleared by writing 1 to it.

PCMSK0:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT7:0
  PCINT7            ...       PCINT0   If PCIE0 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0   =PORTB

=====================================================================================================
=====================================================================================================
ATmega2560 Support
=====================================================================================================
=====================================================================================================

External Interrupts ------------------------------------------------------------------------------
The following External Interrupts are available on the Arduino:
Arduino           
  Pin*  PORT INT  ATmega2560 pin
  21     PD0  0     43
  20     PD1  1     44
  19     PD2  2     45
  18     PD3  3	    46
   2     PE4  4      6
   3     PE5  5      7
 n/c     PE6  6	     8  (fake pin 75)
 n/c     PE7  7	     9  (fake pin 76)

...it is recommended to first disable INTn by clearing its Interrupt Enable bit in the
EIMSK Register. Then, the ISCn bit can be changed. Finally, the INTn interrupt flag should be
cleared by writing a logical one to its Interrupt Flag bit (INTFn) in the EIFR Register before the
interrupt is re-enabled.

EICRA: 7   6   5   4   3   2   1   0  (External Interrupt Control Register A)
 ISC: 31  30  21  20  11  10  01  00  Interrupt Sense Control Bits
      rw  rw  rw  rw  rw  rw  rw  rw

EICRB: 7   6   5   4   3   2   1   0  (External Interrupt Control Register B)
 ISC: 71  70  61  60  51  50  41  40  Interrupt Sense Control Bits
      rw  rw  rw  rw  rw  rw  rw  rw  NOTE: NO CONNECTION for INT6 and INT7 on ATmega2560**

        ISCx1 / ISCx0 : INTx
          0      0    Low
          0      1    Change
          1      0    Falling
          1      1    Rising

EIMSK:  7   6   5   4   3   2   1   0  (External Interrupt Mask Register)
        n   n   n   n   n   n   n   n  NOTE:  NO CONNECTION FOR  INT6 and INT7 on ATmega2560**
       rw  rw  rw  rw  rw  rw  rw  rw
n= INTn number

External Interrupt Flag Register is set to 1 when a signal generates an IRQ.
Cleared upon entering the ISR. Can be cleared by writing a 1 to it.
EIFR:   7   6   5   4   3   2   1   0  (External Interrupt Flag Register)
        n   n   n   n   n   n   n   n  NOTE:  NO CONNECTION FOR  INT6 and INT7 on ATmega2560**
       rw  rw  rw  rw  rw  rw  rw  rw
n= INTn number

** But that doesn't mean they wouldn't make an excellent resource for software interrupts! ;-) )

Pin Change Interrupts ---------------------------------------------------------------------------

ATMEGA2560 Pin Change Interrupts
Arduino              Arduino              Arduino
  Pin*  PORT PCINT     Pin   PORT PCINT     Pin   PORT PCINT
  A8     PK0  16       10     PB4   4       SS     PB0   0
  A9     PK1  17       11     PB5   5       SCK    PB1   1
 A10     PK2  18       12     PB6   6       MOSI   PB2   2
 A11     PK3  19       13     PB7   7       MISO   PB3   3
 A12     PK4  20       14     PJ1  10
 A13     PK5  21       15     PJ0   9
 A14     PK6  22        0     PE0   8 - this one is a little odd.*
 A15     PK7  23
...indeed, the ATmega2560 chip supports many more Pin Change Interrupt pins but
they are unavailable on the Arduino, unless you want to solder teeny tiny wires.
(However, that doesn't mean they wouldn't make an excellent resource for software interrupts! :-) )

* Note: Arduino Pin 0 is PE0 (PCINT8), which is RX0. Also, it is the only other
pin on another port on PCI1. This would make it very costly to integrate with
the library's code and thus is not supported by this library.  It is the same
pin the Arduino uses to upload sketches, and it is connected to the FT232RL
USB-to-Serial chip (ATmega16U2 on the R3).

static const uint8_t SS   = 53;
static const uint8_t MOSI = 51;
static const uint8_t MISO = 50;
static const uint8_t SCK  = 52;
static const uint8_t A8 = 62;
static const uint8_t A9 = 63;
static const uint8_t A10 = 64;
static const uint8_t A11 = 65;
static const uint8_t A12 = 66;
static const uint8_t A13 = 67;
static const uint8_t A14 = 68;
static const uint8_t A15 = 69;



// PIN CHANGE INTERRUPTS REGISTER BESTIARY for the ATmega2560

PCICR: 7   6   5   4   3   2   1   0  (When PCIE2 is set and GIE is set, PCI2 is enabled)
                       PCIE2   1   0   Likewise for 1 and 0.
       -   -   -   -   -  rw  rw  rw

// set...
PCIFR: 7   6   5   4   3   2   1   0  (When logic change triggers IRQ, bececomes set. Cleared when
                       PCIF2   1   0   IRQ is executed. PCIF2 == PCIE2, etc.)
       -   -   -   -   -  rw  rw  rw

PCMSK2:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT23:16
  PCINT23           ...      PCINT16   If PCIE2 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PK7 PK6 PK5 PK4 PK3 PK2 PK1 PK0   =PORTK
       +   +   +   +   +   +   +   +   + == available on the Arduino board.

PCMSK1:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT15:8
  PCINT15           ...       PCINT8   If PCIE1 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PJ6 PJ5 PJ4 PJ3 PJ2 PJ1 PJ0 PE0   =PORTJ/E Note pin PE0 is the Arduino's RX pin for programming.
                           +   +   +   

PCMSK0:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled o2560n PCINT7:0
  PCINT7            ...       PCINT0   If PCIE0 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0   =PORTB
       +   +   +   +   +   +   +   +

=====================================================================================================
=====================================================================================================
ATmega644 / 1284 Support (MIGHTY1284 used as a reference, NOT Sanguino)
=====================================================================================================
=====================================================================================================
// Sanguino, Mosquino uino bobino bonanafannafofino, me my momino...
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)

// Here I use the mighty-1284p pinout from https://maniacbug.wordpress.com/2011/11/27/arduino-on-atmega1284p-4/
                    +---\/---+
          (D 0) PB0 |1     40| PA0 (AI 0 / D24)
          (D 1) PB1 |2     39| PA1 (AI 1 / D25)
     INT2 (D 2) PB2 |3     38| PA2 (AI 2 / D26)
      PWM (D 3) PB3 |4     37| PA3 (AI 3 / D27)
 PWM   SS (D 4) PB4 |5     36| PA4 (AI 4 / D28)
     MOSI (D 5) PB5 |6     35| PA5 (AI 5 / D29)
 PWM MISO (D 6) PB6 |7     34| PA6 (AI 6 / D30)
 PWM  SCK (D 7) PB7 |8     33| PA7 (AI 7 / D31)
                RST |9     32| AREF
                VCC |10    31| GND
                GND |11    30| AVCC
              XTAL2 |12    29| PC7 (D 23)
              XTAL1 |13    28| PC6 (D 22)
      RX0 (D 8) PD0 |14    27| PC5 (D 21) TDI
      TX0 (D 9) PD1 |15    26| PC4 (D 20) TDO
INT0 RX1 (D 10) PD2 |16    25| PC3 (D 19) TMS
INT1 TX1 (D 11) PD3 |17    24| PC2 (D 18) TCK
     PWM (D 12) PD4 |18    23| PC1 (D 17) SDA
     PWM (D 13) PD5 |19    22| PC0 (D 16) SDL
     PWM (D 14) PD6 |20    21| PD7 (D 15) PWM
                    +--------+

External Interrupts ------------------------------------------------------------------------------
The following External Interrupts are available on the Sanguino:
Sanguino           
  Pin*  PORT INT  ATmega644/1284 pin
   2    PB2   2      3
  10    PD2   0     16
  11    PD3   1     17

The following Pin Change Interrupts are available on the ATmega1284p:
Mighty                                 Mighty           
  Pin*  PORT PCINT ATmega644/1284 pin    Pin*  PORT PCINT ATmega644/1284 pin
   0     PB0   8         1                15    PD7  31        21
   1     PB1   9         2                16    PC0  16        22
   2     PB2   2         3                17    PC1  17        23
   3     PB3  11         4                18    PC2  18        24
   4     PB4  12         5                19    PC3  19        25
   5     PB5  13         6                20    PC4  20        26
   6     PB6  14         7                21    PC5  21        27
   7     PB7  15         8                22    PC6  22        28
   8     PD0  24        14                23    PC7  23        29
   9     PD1  25        15             31/A7    PA7   7        33
  10     PD2  26        16             30/A6    PA6   6        34
  11     PD3  27        17             29/A5    PA5   5        35
  12     PD4  28        18             28/A4    PA4   4        36
  13     PD5  29        19             27/A3    PA3   3        37
  14     PD6  30        20             26/A2    PA2   2        38
                                       25/A1    PA1   1        39
                                       24/A0    PA0   0        40

EICRA: 7   6   5   4   3   2   1   0  (External Interrupt Control Register A)
 ISC:  -   -  21  20  11  10  01  00  Interrupt Sense Control Bits (ISCxx)
       r   r  rw  rw  rw  rw  rw  rw

EIMSK:  7   6   5   4   3   2   1   0  (External Interrupt Mask Register)
        -   -   -   -   -   n   n   n  NOTE:  NO CONNECTION FOR  INT6 and INT7 on ATmega2560**
        r   r   r   r   r  rw  rw  rw
n= INTn number

EIFR: External Interrupt Flag Register is set to 1 when a signal generates an IRQ.
Cleared upon entering the ISR. Can be cleared by writing a 1 to it.
EIFR:   7   6   5   4   3   2   1   0  (External Interrupt Flag Register)
        -   -   -   -   -   n   n   n  NOTE:  NO CONNECTION FOR  INT6 and INT7 on ATmega2560**
       rw   r   r   r  rw  rw  rw  rw
n= INTn number

PCICR: 7   6   5   4   3   2   1   0  (When PCIE2 is set and GIE is set, PCI2 is enabled)
                   PCIE3   2   1   0   Likewise for 1 and 0.
       r   r   r   r  rw  rw  rw  rw

PCIFR: 7   6   5   4   3   2   1   0  (When logic change triggers IRQ, becomes set. Cleared when
                   PCIF3   2   1   0   IRQ is executed. PCIF2 == PCIE2, etc.)
       r   r   r   r  rw  rw  rw  rw

0x73
PCMSK3:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT23:16
  PCINT31           ...      PCINT24   If PCIE2 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0   =PORTD
      15  14  13  12  11  10  09  08   -->Sanguino Pins, DIP40 package

0x6D
PCMSK2:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT23:16
  PCINT23           ...      PCINT16   If PCIE2 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0   =PORTC
      23  22  21  20  19  18  17  16   -->Sanguino Pins, DIP40 package

PCMSK1:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT15:8
  PCINT15           ...       PCINT8   If PCIE1 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0   =PORTB
       7   6   5   4   3   2   1   0   -->Sanguino Pins, DIP40 package

PCMSK0:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled o2560n PCINT7:0
  PCINT7            ...       PCINT0   If PCIE0 in PCICR and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0   =PORTB
      24  25  26  27  28 29   30  31   -->Sanguino Pins, DIP40 package
 

=====================================================================================================
=====================================================================================================
ATtiny 24/44/84 support ATTINY24
=====================================================================================================
=====================================================================================================
Only the 44/84 are supported.

Support for this chip is based on David Mellis' work at https://github.com/damellis/attiny
This is an ATmega that comes in a 14-pin configuration. There are two ports, A and B. PCint pins are
configured on both ports. The following is the pinout, and shows the Arduino pin numbering scheme: 
// ATtiny24/44/84 / ARDUINO
//
//                           +-\/-+
//                     VCC  1|    |14  GND
//             (D 10)  PB0  2|    |13  PA0  (D  0) == AREF
//             (D  9)  PB1  3|    |12  PA1  (D  1) 
//                     PB3  4|    |11  PA2  (D  2) 
//  PWM  INT0  (D  8)  PB2  5|    |10  PA3  (D  3) 
//  PWM        (D  7)  PA7  6|    |9   PA4  (D  4) 
//  PWM        (D  6)  PA6  7|    |8   PA5  (D  5)        PWM
//                           +----+

gcc CPU designations are as follows:
__AVR_ATtiny24__  __AVR_ATtiny24A__  __AVR_ATtiny44__  __AVR_ATtiny44A__
__AVR_ATtiny84__  __AVR_ATtiny84A__

The following External Interrupts are available on the ATtiny24/44/84:
Arduino(tiny)
  Pin*  PORT INT  ATtiny44/84 pin
   8    PB2   0      5

The following Pin Change Interrupts are available on the ATmega24/44/84:
Arduino(tiny)                          Arduino(tiny)
  Pin*  PORT PCINT ATmega24/44/84 pin    Pin*  PORT PCINT ATmega24/44/84 pin
   0     PA0   0        13                 5    PA5   5         8
   1     PA1   1        12                 6    PA6   6         7
   2     PA2   2        11                 7    PA7   7         6
   3     PA3   3        10                 8    PB2  10         5
   4     PA4   4         9                 9    PB1   9         3
                                          10    PB0   8         2
                                   "fake" 11    PB3  11         4

Interrupt registers are different on the Tiny series. Interrupts are set by MCUCR, GIMSK, GIFR, PCMSK0, and PCMSK1.

EXTERNAL INTERRUPTS
-------------------
MCUCR:
 ISC:  -   -   -   -   -   -  01  00  Interrupt Sense Control Bits (ISCxx)
       rw  rw rw  rw  rw  rw  rw  rw
                           ISC01  00

INT0 "is activated if the SREG I-flag and the MCUCR mask is set" (but see GIMSK, below).
ISC01      ISC00
  0          0     INT0 interrupted on LOW level
  1          1     INT0 interrupted on CHANGE
  0          0     INT0 interrupted on FALLING
  1          1     INT0 interrupted on RISING

GIMSK:
When INT0 == 1  and SREG I-flag set, External Interrupt enabled.
When PCIE1 == 1 and SREG I-flag set, pin change Interrupt PCINT11:8 enabled.
When PCIE0 == 1 and SREG I-flag set, pin change Interrupt PCINT7:0 enabled.
       -   INT0  PCIE0  -   -   -   -
              PCIE1
       rw  rw  rw  rw  rw  rw  rw  rw
      --------------------------------


GIFR:  7   6   5   4   3   2   1   0  (When logic change triggers IRQ, becomes set. Cleared when
         INTF0   PCIF0   2   1   0     IRQ is executed. INTF0 == INT0, etc.)
       -     PCIF1     -   -   -   -   INT0 is always cleared when INT0 is a LOW interrupt
       r   rw  rw  rw  r   r   r   r

PCMSK1:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT15:8
                 PCINT11 ...  PCINT8   If PCIE1 in GIMSK and this bit is set, it is enabled on that
       r   r   r   r  rw  rw  rw  rw   pin.)
       -   -   -   - PB3 PB2 PB1 PB0   =PORTB
       -   -   -   -   4   5   3   2   -->ATtiny 24/44/84 Pins, DIP14 package
       -   -   -   -  11*  8   9  10   -->Arduino Pins, DIP14 package. * - "Fake" Arduino pin.

PCMSK0:7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT7:0
  PCINT7            ...       PCINT0   If PCIE0 in GIMSK and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
     PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0   =PORTA
       7   6   5   4   3   2   1   1   -->ATtiny 24/44/84 Pins, DIP14 package
       6   7   8   9  10  11  12  13   -->Arduino Pins, DIP14 package. * - "Fake" Arduino pin.

=====================================================================================================
=====================================================================================================
ATtiny 25/45/85 support ATTINY25
=====================================================================================================
=====================================================================================================
Only the ATtiny 45/85 are supported.
Support for this chip is based on David Mellis' work at https://github.com/damellis/attiny
This is an ATmega that comes in an 8-pin configuration. There is a single port, B.

gcc CPU designations are as follows:
__AVR_ATtiny25__  __AVR_ATtiny45__  __AVR_ATtiny85__

The following is the pinout, and shows the Arduino pin numbering scheme:
// ATtiny25/45/85 / ARDUINO
//
//             +-\/-+
// (D 5) PB5  1|    |8  Vcc
// (D 3) PB3  2|    |7  PB2 (D 2) (INT0)   (== Gemma B2)
// (D 4) PB4  3|    |6  PB1 (D 1)          (== Gemma B1)
//       GND  4|    |5  PB0 (D 0)          (== Gemma B0)
//             +----+

The following External Interrupts are available on the ATtiny25/45/85:
Arduino(tiny)
  Pin*  PORT INT  ATtiny25/45/85 pin
   2    PB2   0      7

The following Pin Change Interrupts are available on the ATmega25/45/85:
Arduino(tiny)                          Arduino(tiny)
  Pin*  PORT PCINT ATmega25/45/85 pin    Pin*  PORT PCINT ATmega25/45/85 pin
   0     PB0   0        5                  3    PB3   3         2
   1     PB1   1        6                  4    PB4   4         3
   2     PB2   2        7                  5    PB5   5         1

Interrupt registers are different on the Tiny series. Interrupts are set by MCUCR, GIMSK, GIFR, PCMSK0, and PCMSK1.


MCUCR:
 ISC:  -   -   -   -   -   -  01  00  Interrupt Sense Control Bits (ISCxx)
       rw  rw rw  rw  rw  rw  rw  rw
                           ISC01  00

INT0 "is activated if the SREG I-flag and the MCUCR mask is set" (but see GIMSK, below).
ISC01      ISC00
  0          0     INT0 interrupted on LOW level
  1          1     INT0 interrupted on CHANGE
  0          0     INT0 interrupted on FALLING
  1          1     INT0 interrupted on RISING

GIMSK:
When INT0 == 1 and SREG I-flag set, External Interrupt enabled.
When PCIE == 1 and SREG I-flag set, pin change Interrupt PCINT5:0 enabled.
       -   INT0    -   -   -   -   -
              PCIE
       r   rw  rw  r   r   r   r   r 
      --------------------------------


GIFR:  7   6   5   4   3   2   1   0  (When logic change triggers IRQ, becomes set. Cleared when
         INT0                        IRQ is executed. INT0 == INT0, etc.)
       -     PCIE  -  -   -   -   -   INT0 is always cleared when INT0 is a LOW interrupt
       r   rw  rw  r  r   r   r   r

PCMSK :7   6   5   4   3   2   1   0  (Selects whether pin change interrupt is enabled on PCINT7:0
             PCINT5  ...      PCINT0   If PCIE0 in GIMSK and this bit is set, it is enabled on that
      rw  rw  rw  rw  rw  rw  rw  rw   pin.)
       -   - PB5 PB4 PB3 PB2 PB1 PB0   =PORTB
               1   3   2   7   6   5   -->ATtiny 25/45/85 Pins, DIP8 package


=================================================================================================================
From http://www.atmel.com/Images/doc8468.pdf:

External interrupts can be sensed and registered either synchronously or asynchronously. Synchronous sensing
requires I/O clock whereas asynchronous sensing does not requires I/O clock. This implies that the interrupts
that are detected asynchronously can be used for waking the device from sleep modes other than idle
mode because the I/O clock is halted in all sleep modes except idle mode.  The sense configuration for
external interrupts and pin change interrupts for Atmel ATmega2560 is given in Table 2-2. For device
specific sense configuration, please refer to the respective datasheet.

Table 2-2.  External interrupts sense configuration.
Program address	Interrupt source	Sensing
$0002		INT0			Asynchronous (Edges and level)
$0004		INT1			Asynchronous (Edges and level)
$0006		INT2			Asynchronous (Edges and level)
$0008		INT3			Asynchronous (Edges and level)
$000A		INT4			Synchronous (Edges and level)
$000C		INT5			Synchronous (Edges and level)
$000E		INT6 			Synchronous (Edges and level)
$0010		INT7			Synchronous (Edges and level)
$0012		PCINT0			Asynchronous
$0014		PCINT1			Asynchronous
$0016		PCINT2			Asynchronous
From Table 2-2, all the pin change interrupts are detected asynchronously.

...
The interrupt execution response for all the enabled AVR interrupts is four/five clock cycle’s minimum.
This four/five clock cycles depends on the program counter width. If the program counter width is not
more than two bytes, then the interrupt response time will be four clock cycles minimum and if the
program counter width is more than two bytes, then the interrupt response time will be minimum five
clock cycles.  These four/five clock cycles include:
1. Two/Three cycles for pushing the Program Counter (PC) value into the stack.
2. One cycle for updating the stack pointer.
3. One cycle for clearing the Global interrupt enable (I) bit.
If an interrupt occurs when the MCU is in sleep mode, the interrupt execution response time is increased
by five clock cycles. This increase comes in addition to the start-up time from the selected sleep mode.
This start up time is the time it will take to start the clock source. 

=====================================================================================================
ARDUINO CPU BESTIARY
=====================================================================================================
See /usr/avr/include/avr/io.h for the actual #defines for the different CPUs.
The CPUs are converted to the #defined macros (eg., __AVR_ATmega169__) by the compiler from
the source file "avr-mcus.def". See
https://github.com/gcc-mirror/gcc/blob/master/gcc/config/avr/avr-mcus.def

$ grep mcu /usr/share/arduino/hardware/arduino/boards.txt
uno.build.mcu=atmega328p
atmega328.build.mcu=atmega328p
diecimila.build.mcu=atmega168
nano328.build.mcu=atmega328p
nano.build.mcu=atmega168
mega2560.build.mcu=atmega2560
mega.build.mcu=atmega1280
leonardo.build.mcu=atmega32u4
esplora.build.mcu=atmega32u4
micro.build.mcu=atmega32u4
mini328.build.mcu=atmega328p
mini.build.mcu=atmega168
ethernet.build.mcu=atmega328p
fio.build.mcu=atmega328p
bt328.build.mcu=atmega328p
bt.build.mcu=atmega168
LilyPadUSB.build.mcu=atmega32u4
lilypad328.build.mcu=atmega328p
lilypad.build.mcu=atmega168
pro5v328.build.mcu=atmega328p
pro5v.build.mcu=atmega168
pro328.build.mcu=atmega328p
pro.build.mcu=atmega168
atmega168.build.mcu=atmega168
atmega8.build.mcu=atmega8
robotControl.build.mcu=atmega32u4
robotMotor.build.mcu=atmega32u4

ISR Register handling

Tested the following code to ensure that all registers would be pushed/popped correctly, even
if I was using NAKED_ISR. Note that I did not run code, I merely eyeballed the output to ensure
it was doing what I expected:

volatile uint8_t storage0;
volatile uint8_t storage1;
volatile uint8_t storage2;
volatile uint8_t storage3;
volatile uint8_t storage4;
volatile uint8_t storage5;
volatile uint8_t storage6;
volatile uint8_t storage7;
volatile uint8_t storage8;
volatile uint8_t storage9;
volatile uint8_t storage10;
volatile uint8_t storage11;
volatile uint8_t storage12;
volatile uint8_t storage13;
volatile uint8_t storage14;
volatile uint8_t storage15;
volatile uint8_t storage16;
volatile uint8_t storage17;
volatile uint8_t storage18;
volatile uint8_t storage19;

void test_ISR(uint8_t current) {

  uint8_t local0=storage0;
  uint8_t local1=storage1;
  uint8_t local2=storage2;
  uint8_t local3=storage3;
  uint8_t local4=storage4;
  uint8_t local5=storage5;
  uint8_t local6=storage6;
  uint8_t local7=storage7;
  uint8_t local8=storage8;
  uint8_t local9=storage9;
  uint8_t local10=storage10;
  uint8_t local11=storage11;
  uint8_t local12=storage12;
  uint8_t local13=storage13;
  uint8_t local14=storage14;
  uint8_t local15=storage15;
  uint8_t local16=storage16;
  uint8_t local17=storage17;
  uint8_t local18=storage18;
  uint8_t local19=storage19;

  local0+=current;
  local1+=current;
  local2+=current;
  local3+=current;
  local4+=current;
  local5+=current;
  local6+=current;
  local7+=current;
  local8+=current;
  local9+=current;
  local10+=current;
  local11+=current;
  local12+=current;
  local13+=current;
  local14+=current;
  local15+=current;
  local16+=current;
  local17+=current;
  local18+=current;
  local19+=current;

  storage0=local0;
  storage1=local1;
  storage2=local2;
  storage3=local3;
  storage4=local4;
  storage5=local5;
  storage6=local6;
  storage7=local7;
  storage8=local8;
  storage9=local9;
  storage10=local10;
  storage11=local11;
  storage12=local12;
  storage13=local13;
  storage14=local14;
  storage15=local15;
  storage16=local16;
  storage17=local17;
  storage18=local18;
  storage19=local19;
}

ISR(PORTD_VECT, ISR_NAKED) {
  register uint8_t current asm("r18");
  EI_ASM_PREFIX(PIND);

  test_ISR(current);

  EI_ASM_SUFFIX;
}

MISCELLANEOUS:
STORING FUNCTION POINTERS IN PROGMEM:
http://stackoverflow.com/questions/28261595/put-progmem-function-pointer-array-into-another-progmem-array


Calling the function pointers by checking each pin's bitmask individually:

  if (interruptMask & _BV(0)) functionPointerB0();	Cycles
     8b8:       c0 ff           sbrs    r28, 0		1 if move on, 2 if skip (to 8bc)
     8ba:       05 c0           rjmp    .+10            2 (move on)
     8bc:       e0 91 60 02     lds     r30, 0x0260	2
     8c0:       f0 91 61 02     lds     r31, 0x0261	2
     8c4:       19 95           eicall			4
     8c6:    (move on)					TOTAL: 10 if matches, 3 if not
							== 21 cycles till get to last function call,
							then 10 cycles to execute it: 31 cycles

							If an interrupt on third pin:
							2 x 3 (not matched) + 10 == 16, plus
							4 x 3 (not matched) = 28 total.

Calling the function pointers referred to in an array, using while loop:

     8c6:       d0 e0           ldi     r29, 0x00       ; 0 this is the "i" variable

  while (1) {
    if (interruptMask & 0x01) {
     8c8:       c0 ff           sbrs    r28, 0		1 if it's not set, 2 if skip 
     8ca:       0a c0           rjmp    .+20            2 (move on to try next bit at 0x8e0)
      (*functionPointerArray[i])();
     8cc:       ed 2f           mov     r30, r29	1 (it's set, execute the function)
     8ce:       f0 e0           ldi     r31, 0x00       1 ; loads 0
     8d0:       ee 0f           add     r30, r30	1
     8d2:       ff 1f           adc     r31, r31	1
     8d4:       e7 57           subi    r30, 0x77       1 ; 119
     8d6:       fd 4f           sbci    r31, 0xFD       1 ; 253
     8d8:       01 90           ld      r0, Z+		1 load from data memory
     8da:       f0 81           ld      r31, Z		1
     8dc:       e0 2d           mov     r30, r0		1
     8de:       19 95           eicall			4
    }
    interruptMask=interruptMask >> 1;
     8e0:       c6 95           lsr     r28		1
    if (interruptMask == 0) goto exitISR;
     8e2:       11 f0           breq    .+4             1 if not zero, 2 if zero (jumps out...) ; 0x8e8 <__vector_9+0x86>
    i++;
     8e4:       df 5f           subi    r29, 0xFF       1 ; 255
     8e6:       f0 cf           rjmp    .-32            2 ; 0x8c8 <__vector_9+0x66>

							TOTAL: 14 if matches, 9 if not
							== 63 cycles to get to last function call,
							then 14 cycles to execute it: 77 cycles

							If an interrupt on third pin:
							2 x 7 (not matched) == 14 + 14 == 28 total.
							Then a couple of cycles to get out.


===========================================================================================================
Space Optimizations
===========================================================================================================
Compile Simple.ino, using pin 10, compile for ATmega2560:
Program:    6402 bytes (2.4% Full)
(.text + .data + .bootloader)

Data:        859 bytes (10.5% Full)
(.data + .bss + .noinit)


Compile Simple.ino, using pin 10, define EI_NOTEXTERNAL:
Program:    5328 bytes (2.0% Full)
(.text + .data + .bootloader)

Data:        843 bytes (10.3% Full)
(.data + .bss + .noinit)

Compile Simple.ino, using pin 10, define EI_NOTPORTJ:
Program:    5006 bytes (1.9% Full)
(.text + .data + .bootloader)

Data:        825 bytes (10.1% Full)
(.data + .bss + .noinit)

Compile Simple.ino, using pin 10, define EI_NOTPORTJ EI_NOTPORTK:
Program:    4686 bytes (1.8% Full)
(.text + .data + .bootloader)

Data:        806 bytes (9.8% Full)
(.data + .bss + .noinit)


Compile Simple.ino, using pin 10, define EI_NOTPORTJ EI_NOTPORTK EI_NOTEXTERNAL:
Program:    4674 bytes (1.8% Full)
(.text + .data + .bootloader)

Data:        806 bytes (9.8% Full)
(.data + .bss + .noinit)

