0

Metro M0 Express: Some External Interrupts Not Triggering
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Metro M0 Express: Some External Interrupts Not Triggering

by juggler2000 on Thu Oct 25, 2018 12:06 am

Per this thread, I was steered to the M0 Express as a good platform for working with many (20+) hardware interrupts. viewtopic.php?f=31&t=128661

I do like the board, but am having an odd issue. Some of the pins will not trip the interrupt. I know all the digital pins (including analogs which double as digital) are labeled as interrupt-friendly, and it seems the general advice is to avoid Pin 13 (for all Arduinos) since it's tied to the board's LED, but otherwise I can't find info indicating problem pins.

My larger system has four DC motors controlled by an Adafruit Motor Shield V2.3, with voltage jumper set to 3.3V to work with the Metro M0 Express. Each motor has Hall Effect encoder pairs, and am closing a position loop at low speed (<200 RPM). This often works fine, but also often one or more of the encoder signals seems to stop registering. The inconsistent behavior is particularly maddening. I should also mention that I tried swapping out the Metro board, Motor Shield, motor/encoder, wires, and still have the phantom problems.

I'm using Paul Stoffregen's encoder library, version 1.4.1. In digging into the encoder library [line 210 in below], I see a warning that Zero-based boards don't work properly. It's not clear if this is still a problem, or what the particular problem was/is.
https://github.com/PaulStoffregen/Encod ... upt_pins.h
https://www.pjrc.com/teensy/td_libs_Encoder.html

I'm trying to recreate my issue with a simple system. I've stripped out most of it. What remains is the Metro M0 Express, Hall Effect sensor powered by the board's 3.3V pin (within spec of the sensor), and two output signals from the Hall sensor fed to digital pins 6 & 7. The Motor Shield is gone, and the motor is not powered (I'm just manually spinning the encoder). Voltage level looks good.

I don't normally "poll" the encoder pins manually (in case that makes any difference), as the library takes care of that upon interrupt. But I'm doing that here to help with debugging.
Code: Select all | TOGGLE FULL SIZE
#include <Encoder.h>

Encoder myEnc_1(0, 1);//  <=====  If I comment this out and below [line 61] "Count_E1 = myEnc_1.read(); "then it works.
Encoder myEnc_2(2, 3);
Encoder myEnc_3(4, 5);
Encoder myEnc_4(6, 7);
// skipping 9,10 since used for servos
Encoder myEnc_5(8, 11);
//Encoder myEnc_6(12, 13);
// library suggests skipping 13 since tied to board LED, but trying it here anyway
//Encoder myEnc_7(14, 15); //AKA analog pins A0, A1
//Encoder myEnc_8(16, 17);//AKA analog pins A2, A3
// skipping pins A4,A5 since Motor Shield V2.3 ties these to SCL,SDA

int Count_E1 = 0;
int Count_E2 = 0;
int Count_E3 = 0;
int Count_E4 = 0;
int Count_E5 = 0;
int Count_E6 = 0;
int Count_E7 = 0;
int Count_E8 = 0;

int D0 =0;
int D1 =0;
int D2 =0;
int D3 =0;
int D4 =0;
int D5 =0;
int D6 =0;
int D7 =0;
int D8 =0;
int D9 =0;
int D10=0;
int D11=0;
int D12=0;
int D13=0;

void setup() {
  // Attach a servo to pin #10
//  servo1.attach(10);
//  servo2.attach(9);
//  AFMS.begin(200);
  Serial.begin(115200);
  Serial.setTimeout(50);
//
//  myMotorB2A->setSpeed(150);
//  myMotorB2A->run(RELEASE);
//
//  myMotorB4A->setSpeed(150);
//  myMotorB4A->run(RELEASE);
//
//  myMotorB2B->setSpeed(150);
//  myMotorB2B->run(RELEASE);
//
//  myMotorB4B->setSpeed(150);
//  myMotorB4B->run(RELEASE);
}

void loop() {
  Count_E1 = myEnc_1.read(); //  <=====  If I comment this out and above [line 3] "Encoder myEnc_1(0, 1);" then it works.
  Count_E2 = myEnc_2.read();
  Count_E3 = myEnc_3.read();
  Count_E4 = myEnc_4.read();
//  Count_E5 = myEnc_5.read();
//  Count_E6 = myEnc_6.read();
//  Count_E7 = myEnc_7.read();
//  Count_E8 = myEnc_8.read();

D0 = digitalRead(0);
D1 = digitalRead(1);
D2 = digitalRead(2);
D3 = digitalRead(3);
D4 = digitalRead(4);
D5 = digitalRead(5);
D6 = digitalRead(6);
D7 = digitalRead(7);
D8 = digitalRead(8);
D9= digitalRead(9);
D10= digitalRead(10);
D11= digitalRead(11);
D12= digitalRead(12);
D13 = digitalRead(13);


//  Serial.print("E1: ");
//  Serial.print( Count_E1);
//  Serial.print(",E2: ");
//  Serial.print( Count_E2);
//  Serial.print(",E3: ");
//  Serial.print( Count_E3);
//  Serial.print(",E4: ");
  Serial.print( Count_E4);
//
//    Serial.print("E5: ");
//  Serial.print( Count_E5);
//  Serial.print(",E6: ");
//  Serial.print( Count_E6);
//  Serial.print(",E7: ");
//  Serial.print( Count_E7);
//  Serial.print(",E8: ");
//  Serial.print( Count_E8);

//    Serial.print("; D0: ");
//  Serial.print( D0);
//  Serial.print(",D1: ");
//  Serial.print( D1);
//  Serial.print(",D2: ");
//  Serial.print( D2);
//  Serial.print(",D3: ");
//  Serial.print( D3);
//  Serial.print(",D4: ");
//  Serial.print( D4);
//
//    Serial.print("D5: ");
//  Serial.print( D5);
  Serial.print(",");
  Serial.print( D6);
  Serial.print(", ");
  Serial.print( D7);
//  Serial.print(",D8: ");
//  Serial.print( D8);
// 
//Serial.print("D9: ");
//  Serial.print( D9);
//  Serial.print(",D10: ");
//  Serial.print( D10);
//  Serial.print(",D11: ");
//  Serial.print( D11);
//  Serial.print(",D12: ");
//  Serial.print( D12);
//    Serial.print(",D13: ");
//  Serial.println( D13);
Serial.println(""); 
  delay(10);

}

This is the serial monitor dump. These variables are Encoder count (Count_E4) , Pin6 value (D6) and Pin7 value (D7). I manually annotated below where the encoder pin changes state, but it seems the interrupt routine didn't update the encoder count. I confirmed that the encoder signal actually changes via multimeter.

14:05:03.156 -> 19,1, 0
14:05:03.156 -> 19,1, 0
14:05:03.156 -> 19,1, 0
19,1, 0
14:05:03.191 -> 19,1, 0
14:05:03.191 -> 19,1, 0
19,1, 0
14:05:03.226 -> 20,0, 0
14:05:03.226 -> 20,0, 0
14:05:03.226 -> 20,0, 0
20,0, 0
14:05:03.261 -> 20,0, 0
14:05:03.261 -> 20,0, 0
20,0, 0
14:05:03.296 -> 20,0, 1 <--- Pin 7 went high, but encoder count did not increment.
14:05:03.296 -> 20,0, 1
14:05:03.296 -> 20,0, 1
20,0, 1
14:05:03.331 -> 20,0, 1
14:05:03.331 -> 20,0, 1
20,0, 1
14:05:03.366 -> 20,0, 1
14:05:03.366 -> 20,0, 1
14:05:03.366 -> 20,0, 1
20,0, 1
14:05:03.401 -> 20,0, 1
14:05:03.401 -> 22,1, 1 <--- Now pin 6 toggled, and the encoder counter "caught up" but incremented by two. Confusing. It's as though it only observed going from 0,0 to 1,1, and not the intermediate 0,1.
22,1, 1
14:05:03.436 -> 22,1, 1
14:05:03.436 -> 22,1, 1

I know the Due had an issue regarding interrupts, where the internal pull-up resistors were much higher than normal (100K I think). I couldn't find documentation on the value of the Metro M0 Express values, but my quick check manually adding a 1K pull-up to 3.3v didn't seem to solve my problems.

Page 1 of the SAM D21G data sheet indicates there are 16 external interrupts. Page 28 has the table of pins mapping to external interrupts, and there are a lot of shared EICs. Of course, the M0 Express doesn't utilize all of the pins, but I couldn't find that mapping.
http://ww1.microchip.com/downloads/en/D ... 01882D.pdf

I'm including the full code (which produced the above output) in case you have any extra insights. I did note that if I remove the encoder definition that references pins 0 & 1 (MyEnc_1), then I don't get this particular issue, even though that encoder info is not related to the output I'm using (myEnd_4). I see that these can also be used as a Serial output, but per prior reply comments above are not tied to the USB serial which is the only one I'm using. Turning off another Encoder definition instead did not cause it to work, so perhaps there is some issue with these particular pins.

This thread for the M4 mentions that it may not be possible to have a pair of pins defined (such as for a quadrature encoder) that use the same External Interrupt Controller, then they may not both be able to trip it -- unclear to me what the conclusion is on that thread. viewtopic.php?f=63&t=134385&p=667257&hilit=interrupt+external#p667257

Any thoughts or suggestions would be much appreciated! :)

juggler2000
 
Posts: 13
Joined: Fri Dec 29, 2017 1:32 pm

Re: Metro M0 Express: Some External Interrupts Not Triggerin

by adafruit2 on Sun Oct 28, 2018 12:05 pm

all the interrupts are defined in the variant. there's only one you can use per pin, and yeah some are shared
https://github.com/adafruit/ArduinoCore ... ariant.cpp
i dont *think* we have any typos?

it looks like also something may have changed when we did our latest upstream merge.
https://github.com/adafruit/ArduinoCore-samd/issues/62
you could try an earlier BSP if that's the issue!

adafruit2
Site Admin
 
Posts: 17487
Joined: Fri Mar 11, 2005 7:36 pm

Re: Metro M0 Express: Some External Interrupts Not Triggerin

by juggler2000 on Sun Oct 28, 2018 7:19 pm

Thanks for your reply!

In my above example, I'm using pins 6 & 7, which according to your first link each map to different external interrupts (EXTERNAL_INT_6,EXTERNAL_INT_7, respectively).

Doesn't this mean they should trip separate interrupts independently, causing no confusion for the Encoder library? It's odd to me that the pins themselves indeed toggle (per my serial dump above showing the Digital pin values increment) , but the interrupt routine seems to not receive the call. Weird, right?

The only other pins that use those same external interrupts (Ext_Int_6,_7) are pins 24-27, and I'm not using any of those. Admittedly, I don't understand the implications of pins sharing ISRs. I would think that if any pin causes a trip on that ISR, the encoder routine would find the vals of all the pins that share that ISR to ensure it knows who actually changed. I've looked at that library some, but it's mostly Greek to me.

juggler2000
 
Posts: 13
Joined: Fri Dec 29, 2017 1:32 pm

Re: Metro M0 Express: Some External Interrupts Not Triggerin

by real_dean on Mon Nov 05, 2018 2:33 pm

I have fixed some things with interrupt handling on M0 boards. You can try updating to Adafruit SAMD core v.1.2.6 when you see it become available in the arduino boards manager. This may solve your problem.

real_dean
 
Posts: 14
Joined: Mon Jun 30, 2014 11:20 am

Re: Metro M0 Express: Some External Interrupts Not Triggerin

by juggler2000 on Mon Nov 05, 2018 5:40 pm

Thanks, real_dean! I really appreciate you letting me know about your update. I'll be on the lookout for that.

juggler2000
 
Posts: 13
Joined: Fri Dec 29, 2017 1:32 pm

Re: Metro M0 Express: Some External Interrupts Not Triggerin

by adafruit2 on Wed Nov 07, 2018 11:40 am

this is probably fixed in 1.2.6
https://github.com/adafruit/ArduinoCore-samd/issues/62
please try!

adafruit2
Site Admin
 
Posts: 17487
Joined: Fri Mar 11, 2005 7:36 pm

Re: Metro M0 Express: Some External Interrupts Not Triggerin

by juggler2000 on Thu Nov 08, 2018 1:05 pm

It mostly works, thanks!

Per above, I test this in pairs of pins for quadrature encoder. The changes to the library appear to have most of the pins working, but not quite all.

D0-3, 6-13 all work perfectly.
D4,5 seem to jump counts like before. If I move the slowly, then the counter increments as it should. If I go "fast" (still by hand), then it will jump up and down, as though the interrupt routine is not working.

D14,15 (aka A0,A1) work perfectly.
D16,17 (aka A2,A3) don't work at all. The counter never increments, event though my Digital pin status print statements show they are changing. I thought this must be my own code bug, but couldn't find it if so.

Is there any reason the hardware SPI pins (28-30) would not be part of the fix? 28,29 show the same "jumpy" behavior as D4,5 except maybe more. In a prior thread, those pins were noted as fine for use with interrupts. viewtopic.php?f=31&t=128661

Here's more verbose code -- same as before, but for all the pins mentioned.

Code: Select all | TOGGLE FULL SIZE
#include <Encoder.h>

Encoder myEnc_1(0, 1);// 
Encoder myEnc_2(2, 3);
Encoder myEnc_3(4, 5);
Encoder myEnc_4(6, 7);

Encoder myEnc_5(8, 9);
Encoder myEnc_6(10, 11);
Encoder myEnc_7(12, 13);
// library suggests skipping 13 since tied to board LED, but trying it here anyway
Encoder myEnc_8(14, 15); //AKA analog pins A0, A1
Encoder myEnc_9(16, 17); //AKA analog pins A2, A3

Encoder myEnc_10(28, 29);
// skipping pins A4,A5 since Motor Shield V2.3 ties these to SCL,SDA

int Count_E1 = 0;
int Count_E2 = 0;
int Count_E3 = 0;
int Count_E4 = 0;
int Count_E5 = 0;
int Count_E6 = 0;
int Count_E7 = 0;
int Count_E8 = 0;
int Count_E9 = 0;
int Count_E10 = 0;

int D0 = 0;
int D1 = 0;
int D2 = 0;
int D3 = 0;
int D4 = 0;
int D5 = 0;
int D6 = 0;
int D7 = 0;
int D8 = 0;
int D9 = 0;
int D10 = 0;
int D11 = 0;
int D12 = 0;
int D13 = 0;

int D14 = 0;
int D15 = 0;
int D16 = 0;
int D17 = 0;


int D28 = 0;
int D29 = 0;

void setup() {

  Serial.begin(115200);
  Serial.setTimeout(50);

}

void loop() {
  Count_E1 = myEnc_1.read();
  Count_E2 = myEnc_2.read();
  Count_E3 = myEnc_3.read();
  Count_E4 = myEnc_4.read();
  Count_E5 = myEnc_5.read();
  Count_E6 = myEnc_6.read();
  Count_E7 = myEnc_7.read();
  Count_E8 = myEnc_8.read();
  Count_E9 = myEnc_9.read();
  Count_E10 = myEnc_10.read();

  D0 = digitalRead(0);
  D1 = digitalRead(1);
  D2 = digitalRead(2);
  D3 = digitalRead(3);
  D4 = digitalRead(4);
  D5 = digitalRead(5);
  D6 = digitalRead(6);
  D7 = digitalRead(7);
  D8 = digitalRead(8);
  D9 = digitalRead(9);
  D10 = digitalRead(10);
  D11 = digitalRead(11);
  D12 = digitalRead(12);
  D13 = digitalRead(13);

  D14 = digitalRead(14);
  D15 = digitalRead(15);
  D16 = digitalRead(16);
  D17 = digitalRead(17);

  D28 = digitalRead(28);
  D29 = digitalRead(29);


  Serial.print("E1:");
  Serial.print( Count_E1);
  Serial.print(",E2:");
  Serial.print( Count_E2);
  Serial.print(",E3:");
  Serial.print( Count_E3);
  Serial.print(",E4:");
  Serial.print( Count_E4);

  Serial.print(",E5:");
  Serial.print( Count_E5);
  Serial.print(",E6:");
  Serial.print( Count_E6);
  Serial.print(",E7:");
  Serial.print( Count_E7);
  Serial.print(",E8:");
  Serial.print( Count_E8);
  Serial.print(",E9:");
  Serial.print( Count_E9);
  Serial.print(",E10:");
  Serial.print( Count_E10);


  Serial.print(",D0:");
  Serial.print( D0);
  Serial.print(",D1:");
  Serial.print( D1);
  Serial.print(",D2:");
  Serial.print( D2);

  Serial.print("D3: ");
  Serial.print( D3);
  Serial.print(",D4:");
  Serial.print( D4);
  Serial.print(",D5:");
  Serial.print( D5);
  Serial.print(",D6:");

  Serial.print( D6);
  Serial.print(",D7:");
  Serial.print( D7);
  Serial.print(",D8: ");
  Serial.print( D8);

  Serial.print("D9:");
  Serial.print( D9);
  Serial.print(",D10:");
  Serial.print( D10);
  Serial.print(",D11:");
  Serial.print( D11);
  Serial.print(",D12:");
  Serial.print( D12);
  Serial.print(",D13:");
  Serial.print( D13);

  Serial.print(",D14:");
  Serial.print( D14);
  Serial.print(",D15:");
  Serial.print( D15);
  Serial.print(",D16:");
  Serial.print( D16);
  Serial.print(",D17:");
  Serial.print( D17);



  Serial.print(",D28:");
  Serial.print( D28);
  Serial.print(",D29:");
  Serial.print( D29);
  Serial.println("");
  delay(10);

}

juggler2000
 
Posts: 13
Joined: Fri Dec 29, 2017 1:32 pm

Re: Metro M0 Express: Some External Interrupts Not Triggerin

by real_dean on Mon Nov 12, 2018 1:49 pm

Hey so unfortunately the processor only has 17 interrupt channels ( 16 regular and one Non-Maskable Interrupt (NMI) ). It looks like you're trying to use 20 interrupts.
While all those pins can be used for an interrupt, some share interrupt channels so not all can be used for interrupts simultaneously.
You can cross-reference the last element in each of the pin objects in this table (https://github.com/adafruit/ArduinoCore ... ariant.cpp) to find out which channels are being double-booked.

real_dean
 
Posts: 14
Joined: Mon Jun 30, 2014 11:20 am

Please be positive and constructive with your questions and comments.