I believe I have found a bug with the external interrupts of the due. I was trying to use 8 interrupts simultaneously for 4 encoders but I could never get all of them to work. Eventually I got them to work by trying different pins for each channel until they all worked.
Perhaps there is an error in the compiler?
Using pins 23,24,45,43,31,33,37,35 works. But I couldn't get any simpler sequential sets of pins to work together. Sometime only one channel would be picked up by the interrupt and sometimes only half of the encoder resolution would be returned.
I haven't used the Due yet, but judging by the datasheet interrupts can get complex (see page 57).
There are interrupt levels and priorities. If your code to handle an interrupt takes too long, then it is possible another interrupt would be missed.
It is extremely unlikely there is an error in the compiler. Possibly one in the libraries, which would still be in their early stages. Possibly one in your code, or not so much an error as a design problem.
#define VELOCITY_SAMPLE_TIME 10 //sample time (ms) between velocity checks
#define ENCODER_COUNTS 250
#include "Encoder.h"
unsigned long VelocityTimeStamp=0;
Encoder encoderFL(27, 29);
Encoder encoderFR(45, 43);
Encoder encoderRL(31, 33);
Encoder encoderRR(41, 39);
void setup()
{
 Serial.begin(9600);
Â
 encoderFL.initilise();
 encoderFR.initilise();
 encoderRL.initilise();
 encoderRR.initilise();
 //Attach Interupts to both pins for each encoder(for full resolution)
 attachInterrupt(encoderFL.pin_a,doEncoderFL,CHANGE);
 attachInterrupt(encoderFL.pin_b,doEncoderFL,CHANGE);
 attachInterrupt(encoderFR.pin_a,doEncoderFR,CHANGE);
 attachInterrupt(encoderFR.pin_b,doEncoderFR,CHANGE);
 attachInterrupt(encoderRL.pin_a,doEncoderRL,CHANGE);
 attachInterrupt(encoderRL.pin_b,doEncoderRL,CHANGE);
 attachInterrupt(encoderRR.pin_a,doEncoderRR,CHANGE);
 attachInterrupt(encoderRR.pin_b,doEncoderRR,CHANGE);
}
void loop()
{
 updateVelocity();
 //ENCODER DEBUG
 Serial.print(encoderFL.getPosition(),DEC);
 Serial.print(" ");
 Serial.print(encoderFR.getPosition(),DEC);
 Serial.print(" ");
 Serial.print(encoderRL.getPosition(),DEC);
 Serial.print(" ");
 Serial.print(encoderRR.getPosition(),DEC);
 Serial.print(" ---- ");
 Serial.print(encoderFL.getVelocity(),DEC);
 Serial.print(" ");
 Serial.print(encoderFR.getVelocity(),DEC);
 Serial.print(" ");
 Serial.print(encoderRL.getVelocity(),DEC);
 Serial.print(" ");
 Serial.print(encoderRR.getVelocity(),DEC);
 Serial.println();
}
//Wrapper Functions to call correct encoder object method on interupt
void doEncoderFL(){
 encoderFL.doCount();
}
void doEncoderFR(){
 encoderFR.doCount();
}
void doEncoderRL(){
 encoderRL.doCount();
}
void doEncoderRR(){
 encoderRR.doCount();
}
//Function to calculate velocity of encoders once every VELOCITY_SAMPLE_TIME
void updateVelocity(){
 if(VelocityTimeStamp+VELOCITY_SAMPLE_TIME<millis()){
  encoderFL.calculateVelocity();
  encoderFR.calculateVelocity();
  encoderRL.calculateVelocity();
  encoderRR.calculateVelocity();
  VelocityTimeStamp=millis();
 }
}
#ifndef __ENCODER_H__
#define __ENCODER_H__
#include "Arduino.h"
//This class is designed to manage the encoders
//Four instances of this class are created: one for each encoder
//The methods in this class are called by interupts (attached in the setup function of the main program)
//There is a wrapper function called 'doEncoder' in the main function designed to call the correct encoder method
//this function is required as interupts cannot call object methods directly (unless static there is no pointer)
class Encoder {
public:
 int pin_a;
 int pin_b;
 // constructor : sets pins as inputs and turns on pullup resistors
 Encoder(int A, int B){
  // Set pin a and b to be input
  Evelocity=0;
  Eposition=0;
  EpositionCache=0;
  pin_a=A;
  pin_b=B;
 };
 void initilise(){
  pinMode(pin_a, INPUT);
  pinMode(pin_b, INPUT);
  // Turn on pullup resistors
  digitalWrite(pin_a, HIGH); Â
  digitalWrite(pin_b, HIGH);Â
 }
Â
 void doCount(){
  //Serial.println("Doing Count");
  State = (digitalRead(pin_a)<<1)|digitalRead(pin_b);
  switch(State)
  {
   case 0:
    if(PreviousState==1)Eposition++;
    else Eposition--;
   break;
   case 1:
    if(PreviousState==3)Eposition++;
    else Eposition--;
   break;
   case 2:
    if(PreviousState==0)Eposition++;
    else Eposition--;
   break;
   case 3:
    if(PreviousState==2)Eposition++;
    else Eposition--;
   break;
  }
  PreviousState=State;
 }
 // returns current position
 long int getPosition () {
  return Eposition;
 };
 float getVelocity () {
  return Evelocity;
 };
 void calculateVelocity(){
  Evelocity = (float(Eposition-EpositionCache)/float(millis()-TimeStamp))*1000/(ENCODER_COUNTS*4);
  TimeStamp = millis();
  EpositionCache=Eposition;
 }
 // set the position value
 void setPosition ( const long int p) {
  Eposition = p;
 };
private:
 float Evelocity;
 unsigned long TimeStamp;
 long int EpositionCache;
 volatile long int Eposition;
Â
 byte State;
Â
 byte PreviousState;
};
#endif // __ENCODER_H__
The time spent doing those debugging prints (which probably use interrupts) might be affecting it. Try adding a test to only do those once a second or so.
I have also been having tons of problems running interrupts on the Due. Here's what I was trying to do: have a bunch of intterupts attached to a handful of switches. If any of them are switched (CHANGE), then toggle the Led HIGH->LOW and vice versa. In theory this should be super simple, but it was misbehaving badly. For example, sometimes it would miss if I switched one of the pins, flicker the LED when I wasn't doing anything. In some cases, I would hit one switch, and the Led would blink once or a few times.
I think the problem lies in the volatile int definition. I don't have a clear understanding of volatile ints, but getting rid of all the volatiles made everything work just fine. If using interrupts on something that is truly fast, like an encoder, the use of volatiles might actually be important. Try it, it might work.
@RocketManArduino
Any chance you could post your code please, for folks to ponder? And have you tried reducing it to the bare minimum that misbehaves? Also, pin debounce is a real must with switch input, as noted by djjoshuad.
From what you said:
I don't have a clear understanding of volatile ints, but getting rid of all the volatiles made everything work just fine
it sounds to me like a coding issue. The 'volatile' just tells the compiler not to assume that the variable's value is constant, i.e. don't over-optimize it.
"Interrupt on change" is a deceptive feature, it makes it look like sampling digital inputs is quick and simple. In general, you must debounce all signals coming into the CPU, this applies particularly if you are sampling a mechanical switch. Even many solid state devices can generate a slow rise time signal, and with a small amount of noise which tends to be always present in digital circuits, can trigger multiple times around the logic high threshold.
The "interrupt on change" really means "something is happening". That something could be a spurious glitch due to noise, or it could be real a change of state. To tell the difference, one method is to start a timer when the signal changes. A short time, say 10ms, after the signal has stopped changing, test if the new state is different to the old state. Only then act on the new state if it has changed.
Sometimes a good way to check interrupt routines is something like (pseudo code):
volatile int Count;
int LastCount;
ISR()
{
  Count++;
}
setup()
{
  Count = 0;
  LastCount = 0;
}
loop()
{
  if (Count > LastCount)
  {
    Serial.println(Count, DEC);   // maybe print the time as well?
    LastCount = Count;
  }
}
Any debug prints etc. in the interrupt routines will cetainly affect the timing and confuse things.