Arduino Due Interrupt Sensitivity with Stepper Motors

The short version:

Does anyone know what the threshold is for low to high and high to low transition when an interrupt pin is set up in CHANGE mode?

Long version:

I'm currently trying to run two stepper motors with encoder feedback on them, but I'm getting faulty interrupts whenever the motors are running. I'm using the interrupts to keep track of the encoders.
At the moment I've concentrated my efforts on getting only one motor with feedback working.
I've read other topics on this issues and have tried both external and internal pull up resistors on my encoder pins. I've grounded the chassis of both the motor and power supply with Earth ground.
I'm using Gecko Stepper drivers to drive my motors with 3.5Amps in Series configuration.
There are caps placed on my breadboard across 3.3V and Gnd.
I am able to successfully run the encoders with the motors being off with the code below. Only when the motors are on do I get issues with the interrupts!
I'm running the encoders in quadrature, only using channels A and B.

I measured the signals that are occurring on the interrupt pins and they're below 100mV. I know that a high to low transition signal needs to go from gnd to approximately 3.3V. I've attached images of this from my scope.

My code:

 // pins to which Encoder is hooked up to
 int encoderPinA = 5;
 int encoderPinB = 4;
 
 // variables used to keep track of the encoder position
 long encoderCount = 0; // keeps track of the number of times the encoder turns
 int encoderCountPrev = 1; // saves old value of encoder
 
 boolean dirFlag = HIGH; // boolena value used to change direction of setpper
 int stepPin = 52; // pin used to initiate a step
 int directionPin = 50; // pin used to change direction
 int enablePin = 48; // pin used to enable mtr controller
 
 void setup()
 {
   // setting up interrupt
    pinMode(encoderPinA, INPUT);
    pinMode(encoderPinB, INPUT);
    digitalWrite(encoderPinA, HIGH); // pull up resistors enabled
    digitalWrite(encoderPinB, HIGH);
    attachInterrupt(5, doOnA, CHANGE); // calling doOnX isr
    attachInterrupt(4, doOnB, CHANGE);
   
    pinMode(enablePin, OUTPUT);
    pinMode(directionPin, OUTPUT);
    pinMode(stepPin, OUTPUT);
    
    digitalWrite(enablePin, LOW);
    digitalWrite(directionPin, dirFlag);
    
    Serial.begin(115200);
 }
 
 void loop()
 { 
   for(int i =0; i < 200; i++)
   {
    takeAStep();
    delay(10);  
   }
   dirFlag = !dirFlag;
   digitalWrite(directionPin, dirFlag);
   
  if(encoderCountPrev != encoderCount)
  {
   Serial.print("Encoder value = "); // cake topping
   Serial.println(encoderCount, DEC); // print out the new value of the encoder count
   encoderCountPrev = encoderCount; // save the current value into the old M
  }
 }
 
 
 // performs this operation when A changes state on the encoder
void doOnA()
 {
  if (REG_PIOC_PDSR & (1 << 25)) {  // look for a low-to-high on channel A
    if (!(REG_PIOC_PDSR & (1 << 26))) { // check channel B to see which way encoder is turning
      encoderCount++;
    } 
    else {
      encoderCount--;
    }
  }
  else {                                     // must be a high-to-low edge on channel A
    if (REG_PIOC_PDSR & (1 << 26)) { // check channel B to see which way encoder is turning  
      encoderCount++;
    } 
    else {
      encoderCount--;
    }
  } 
 }
 
 //perform this operation when B changes state on the encoder
 void doOnB()
 {
  if (REG_PIOC_PDSR & (1 << 26)) {   // look for a low-to-high on channel B
    if (REG_PIOC_PDSR & (1 << 25)) { // check channel A to see which way encoder is turning
      encoderCount++;
    } 
    else {
      encoderCount--;
    }
  }
  else {                                    // must be a high-to-low edge on on channel B
    if (!(REG_PIOC_PDSR & (1 << 25))) { // check channel B to see which way encoder is turning
      encoderCount++;
    } 
    else {
      encoderCount--;
    }
  }
 }
 
 void takeAStep()
 {
   REG_PIOB_SODR = 0x1 << 21; //set the pin high
   delay(1);
//     delayMicroseconds(5);
   REG_PIOB_CODR = 0x1 << 21; //set the pin low
 }

Some of the things that are running through my mind with this issue:

  1. EMF from motors is interacting with the digital pins, but would a 100mV signal trigger interrupts, when set up in CHANGE mode?
  2. It can't be the noise from the connection between the Arduino Due and the Gecko stepper drivers as the drivers are opto-isolated and the encoders work fine with motors powered down, but stepper driver being on.
  3. The breadboard is picking up the electromagnetic noise, since it is so close to the motors, but a 100mV signal causing faulty interrupt trigger?!

Anyways, any ideas on what could be going on?

20140623_223106[1].jpg

GND noise

GndWithMtrRunning[1].jpg

Hand Drawn schematic

Schematic[1].jpg

3dmax:
The short version:

Does anyone know what the threshold is for low to high and high to low transition when an interrupt pin is set up in CHANGE mode?

Yes, the datasheet knows. The Due has pins of varying types, some are schmitt-trigger,
some are not.

For a digital signal you should not be putting an analog voltage onto it in the first place
though, you perhaps need proper signal conditioning on your encoder signals.

  1. cables should be screened, screen connected to Arduino ground only.
  2. Keep encoder cable well away from motor wiring.
  3. low-pass filter the encoder outputs with RC circuit, time constant of about 5us
    perhaps (1k and 4.7nF)
  4. then schmitt-trigger to clean up the output of the filter, use 74HC14 hex inverter
    chip for this.
  5. Make sure you are not passing motor ground currents through the Due.

The spikes that are triggering the interrupts only need to be about 1ns long
on the Due if I remember rightly - this is why a low-pass filter will make a difference
and why you can't see what's happening.

Make sure you have decoupling in all the right places.

Interference is often from the currents, not voltages, so if you don't
connect motor to driver you won't see any effect as there is no current.

Thanks MarkT

Using the filter and the schmitt trigger makes sense. I'll give it a go.

Out of curiosity, is there a difference with shielding wires with Earth Ground from an outlet and the Ground supply of the micro controller?
I feel that the arduino's ground wire and board inductance would cause unwanted noise on the ground versus using the earth ground where I'm not using it as a reference for any other voltage. Then again it shouldn't be a lot of current that needs to be dissipated through those grounding wires.

Also most of the pins on the Due have Schmitt triggers on them except:
2. PIOA: Schmitt Trigger on all, except PA0, PA9, PA26, PA29, PA30, PA31
3. PIOB: Schmitt Trigger on all, except PB14 and PB22
4. PIOC: Schmitt Trigger on all, except PC2 to PC9, PC15 to PC24
5. PIOD: Schmitt Trigger on all, except PD10 to PD30
6. PIOE: Schmitt Trigger on all, except PE0 to PE4, PE15, PE17, PE19, PE21, PE23, PE25, PE29
7. PIOF: Schmitt Trigger on all PIOs
Page 13 of the datasheet

3dmax:
Thanks MarkT

Using the filter and the schmitt trigger makes sense. I'll give it a go.

Out of curiosity, is there a difference with shielding wires with Earth Ground from an outlet and the Ground supply of the micro controller?
I feel that the arduino's ground wire and board inductance would cause unwanted noise on the ground versus using the earth ground where I'm not using it as a reference for any other voltage. Then again it shouldn't be a lot of current that needs to be dissipated through those grounding wires.

Mains earth is full of noise induced from the mains wiring, a no-no for small signals.

You want the ground that is the actual reference ground for signal in question, so that
induced common-mode noise doesn't affect the differential signal. Its vital no ground
currents flow hence the shield needs to be connected to Arduino ground at the Arduino
and not connected to anything else.

Fault voltages in mains earth can be fairly high(*) BTW, but only till a fuse blows - so mains
earth is safe for humans but not for semiconductors.

(*) higher than half the mains voltage - typically earth wires are thinner than live and
neutral as they don't carry sustained current, only fault currents for a few ms while
the fuse wire vaporises.