Mega2560 different output to Uno (interrupt, pinout)

The program reads the number of clicks (4096 clicks = 1 revolution) from a rotary encoder. Channel A is connected to pin 2 (interrupt 0), and B to pin 3 (interrupt 1). The program works 100% correct when running on a Uno (Will print the correct number of ticks and revolutions), however when running on a Mega2560 the output is a lot different.

When running on a Mega2560, the number of clicks has been multiplied by around 512, and they don't decrease when the encoder is reversed (as the Uno does).

Not sure what's going on here? I've tried different pins and interrupts but it's not making sense to me at the moment.

#define c_LeftEncoderInterruptA 0
#define c_LeftEncoderInterruptB 1
#define c_LeftEncoderPinA 2
#define c_LeftEncoderPinB 3

//declare quatrature encoder variables
volatile bool _LeftEncoderASet;
volatile bool _LeftEncoderBSet;
volatile bool _LeftEncoderAPrev;
volatile bool _LeftEncoderBPrev;
volatile long int _LeftEncoderTicks = 0;

int i = 0; //iterator

void setup() {

  Serial.begin(9600);

  //Setup Encoder
  pinMode(c_LeftEncoderPinA, INPUT);     // sets pin A as input
  digitalWrite(c_LeftEncoderPinA, LOW);  // turn on pullup resistors
  pinMode(c_LeftEncoderPinB, INPUT);     // sets pin B as input
  digitalWrite(c_LeftEncoderPinB, LOW);  // turn on pullup resistors
  attachInterrupt(c_LeftEncoderInterruptA, HandleLeftMotorInterruptA, CHANGE);
  attachInterrupt(c_LeftEncoderInterruptB, HandleLeftMotorInterruptB, CHANGE);

}

void loop() {  
  checkMovement(); //check movement of encoder
}

void checkMovement()
{
  rev = _LeftEncoderTicks/4096; //get the current amount of revolutions

  Serial.print("LeftEncoderTicks: ");
  Serial.print(_LeftEncoderTicks);
  Serial.println();
}

// Interrupt service routines for the left motor's quadrature encoder
void HandleLeftMotorInterruptA(){
  _LeftEncoderBSet = digitalReadFast(c_LeftEncoderPinB);
  _LeftEncoderASet = digitalReadFast(c_LeftEncoderPinA);
  
  _LeftEncoderTicks+=ParseEncoder();
  
  _LeftEncoderAPrev = _LeftEncoderASet;
  _LeftEncoderBPrev = _LeftEncoderBSet;
}

// Interrupt service routines for the left motor's quadrature encoder
void HandleLeftMotorInterruptB(){
  // Test transition;
  _LeftEncoderBSet = digitalReadFast(c_LeftEncoderPinB);
  _LeftEncoderASet = digitalReadFast(c_LeftEncoderPinA);
  
  _LeftEncoderTicks+=ParseEncoder();
  
  _LeftEncoderAPrev = _LeftEncoderASet;
  _LeftEncoderBPrev = _LeftEncoderBSet;
}

int ParseEncoder(){
  if(_LeftEncoderAPrev && _LeftEncoderBPrev){
    if(!_LeftEncoderASet && _LeftEncoderBSet) return 1;
    if(_LeftEncoderASet && !_LeftEncoderBSet) return -1;
  }else if(!_LeftEncoderAPrev && _LeftEncoderBPrev){
    if(!_LeftEncoderASet && !_LeftEncoderBSet) return 1;
    if(_LeftEncoderASet && _LeftEncoderBSet) return -1;
  }else if(!_LeftEncoderAPrev && !_LeftEncoderBPrev){
    if(_LeftEncoderASet && !_LeftEncoderBSet) return 1;
    if(!_LeftEncoderASet && _LeftEncoderBSet) return -1;
  }else if(_LeftEncoderAPrev && !_LeftEncoderBPrev){
    if(_LeftEncoderASet && _LeftEncoderBSet) return 1;
    if(!_LeftEncoderASet && !_LeftEncoderBSet) return -1;
  }
}

}

It's almost like the second interrupt isn't working at all, because when I disable it and run it on the Uno, I get the exact output as on the Mega.

You seem to be using digitalReadFast(). I don't know if that is a standard Arduino feature. Maybe it does not work as expected on a Mega ?

...R

Robin2: You seem to be using digitalReadFast(). I don't know if that is a standard Arduino feature. Maybe it does not work as expected on a Mega ?

...R

It's not, it's a separate library. Any reason why it wouldn't work the same?

This does not do what the comment says.

digitalWrite(c_LeftEncoderPinA, LOW);  // turn on pullup resistors

You can enable pullups using pinMode():

pinMode(c_LeftEncoderPinA, INPUT_PULLUP);

oqibidipo: This does not do what the comment says.

digitalWrite(c_LeftEncoderPinA, LOW);  // turn on pullup resistors

You can enable pullups using pinMode():

pinMode(c_LeftEncoderPinA, INPUT_PULLUP);

Okay, I changed it and I'm still getting the same issue.

To illustrate what I mean, here is some output when connected to the Uno: The clicks are exactly as they should be, and I can reverse (decrease).

And then the Mega2560: Much larger numbers, and can't decrease.

Okay, so it looks like the problem was digitalReadFast(); I changed it to digitalRead() and it worked fine. doesn't look like there's any performance drop off but i'm guessing there is.

alisikone: Okay, so it looks like the problem was digitalReadFast(); I changed it to digitalRead() and it worked fine. doesn't look like there's any performance drop off but i'm guessing there is.

One of the reasons digitalRead() is slow is because it is designed to work with all flavours of Arduino.

The documentation for the digitalReadFast() library might indicate its limitations. Perhaps you can post a link to it.

The code in your Original Post does not have a #include for that library.

...R