Operating System
Windows 11
Arduino IDE version
arduino-cli 1.5.1
Board
Grand Central M4 Express
ArduinoCore version
1.7.17 (bug still present in master)
Sketch as ATTACHED TXT
Minimal repro (short, inline for readability):
// Grand Central M4. D9=PB02, D10=PB22, D11=PB23, D12=PB00.
// Attach RISING ISRs, then generate edges on each pin by toggling the
// pull direction via PORT registers (pinMode after attachInterrupt would
// un-mux the EIC function, so pulls are toggled directly).
const int PINS[4] = {9, 10, 11, 12};
volatile uint32_t irq[4];
void i0(){irq[0]++;} void i1(){irq[1]++;} void i2(){irq[2]++;} void i3(){irq[3]++;}
void (*ISRS[4])() = {i0, i1, i2, i3};
void setup() {
Serial.begin(115200); while(!Serial && millis()<3000){}
for (int i=0;i<4;i++){ pinMode(PINS[i], INPUT_PULLDOWN);
attachInterrupt(digitalPinToInterrupt(PINS[i]), ISRS[i], RISING); }
}
void loop() {
for (int e=0;e<10;e++) for (int i=0;i<4;i++) {
EPortType port = g_APinDescription[PINS[i]].ulPort;
uint32_t pin = g_APinDescription[PINS[i]].ulPin;
PORT->Group[port].PINCFG[pin].bit.PULLEN = 1;
PORT->Group[port].PINCFG[pin].bit.INEN = 1;
PORT->Group[port].OUTCLR.reg = 1ul<<pin; delayMicroseconds(300);
PORT->Group[port].OUTSET.reg = 1ul<<pin; delayMicroseconds(300); // rising edge
}
for (int i=0;i<4;i++){ Serial.print(" D"); Serial.print(PINS[i]);
Serial.print("="); Serial.print(irq[i]); }
Serial.println(); delay(1000);
}
Output on hardware (10 edges/pin/iteration):
D9=0 D10=100 D11=100 D12=100
D9=0 D10=110 D11=110 D12=110
D9 counts 0 forever while digitalRead(9) sees every edge (verified separately). Also reproduced with a real 3.3 V pulse source (hall flow sensor through a BSS138 level shifter) on the pin.
Compiled Log as ATTACHED TXT
Compiles clean with no warnings (arduino-cli, FQBN adafruit:samd:adafruit_grandcentral_m4): "Sketch uses 13788 bytes (1%) of program storage space." The bug is runtime-silent, not a build issue, so no log to attach.
What happened ?
On the Grand Central M4, attachInterrupt(9, isr, RISING) (or any mode) never fires the ISR — silently. digitalRead(9) sees the signal fine, and interrupts on neighboring pins (D10/D11/D12) work perfectly, which makes this very hard to debug in the field (it looks like broken wiring).
Cause is a one-value typo in the variant pin table: D9 (PB02) is declared EXTERNAL_INT_3, but PB02's EIC function is EXTINT[2] per the SAMD51 datasheet. The core therefore arms/enables EIC line 3 while D9's edges arrive on line 2, where no handler or sense config exists.
Found while bench-testing hall flow sensors for an arcade game; confirmed with the minimal self-test sketch below and by rebuilding with the row corrected to EXTERNAL_INT_2 (D9 then counts every edge).
How to reproduce ?
- Flash the sketch above on a Grand Central M4 Express (stock adafruit:samd core, reproduced on 1.7.17; the wrong table entry is still in master).
- Open the serial monitor at 115200.
- Observe: D9's interrupt count stays 0 forever; D10/D11/D12 count every edge.
Root cause: variants/grand_central_m4/variant.cpp lists D9 (PB02) as EXTERNAL_INT_3:
{ PORTB, 2, PIO_DIGITAL, PIN_ATTR_PWM_E, No_ADC_Channel, TC6_CH0, TC6_CH0, EXTERNAL_INT_3 },
Per the SAMD51 datasheet I/O multiplexing table, PB02's peripheral-A function is EXTINT[2], not EXTINT[3]. So attachInterrupt(9, ...) configures/enables EIC line 3 while the pad's edges arrive on line 2 — the ISR can never run. digitalRead(9) works normally, which makes the failure silent.
Suggested fix: change that row to EXTERNAL_INT_2. Verified on hardware: with only that change, D9 catches every edge (self-test above, plus a real hall flow sensor). Note this makes D9 share EIC line 2 with D8 (PB18) — correct per silicon, same situation as other line-sharing pins on this variant (cf. #261); only one of D8/D9 can use attachInterrupt at a time.
Debug Log as ATTACHED TXT
No crash/log — the sketch compiles and runs cleanly; the failure is silent (ISR simply never fires). Serial output demonstrating the bug is included in the sketch section above.
Screenshots
No response
Operating System
Windows 11
Arduino IDE version
arduino-cli 1.5.1
Board
Grand Central M4 Express
ArduinoCore version
1.7.17 (bug still present in master)
Sketch as ATTACHED TXT
Minimal repro (short, inline for readability):
Output on hardware (10 edges/pin/iteration):
D9 counts 0 forever while digitalRead(9) sees every edge (verified separately). Also reproduced with a real 3.3 V pulse source (hall flow sensor through a BSS138 level shifter) on the pin.
Compiled Log as ATTACHED TXT
Compiles clean with no warnings (arduino-cli, FQBN adafruit:samd:adafruit_grandcentral_m4): "Sketch uses 13788 bytes (1%) of program storage space." The bug is runtime-silent, not a build issue, so no log to attach.
What happened ?
On the Grand Central M4,
attachInterrupt(9, isr, RISING)(or any mode) never fires the ISR — silently.digitalRead(9)sees the signal fine, and interrupts on neighboring pins (D10/D11/D12) work perfectly, which makes this very hard to debug in the field (it looks like broken wiring).Cause is a one-value typo in the variant pin table: D9 (PB02) is declared
EXTERNAL_INT_3, but PB02's EIC function is EXTINT[2] per the SAMD51 datasheet. The core therefore arms/enables EIC line 3 while D9's edges arrive on line 2, where no handler or sense config exists.Found while bench-testing hall flow sensors for an arcade game; confirmed with the minimal self-test sketch below and by rebuilding with the row corrected to
EXTERNAL_INT_2(D9 then counts every edge).How to reproduce ?
Root cause:
variants/grand_central_m4/variant.cpplists D9 (PB02) asEXTERNAL_INT_3:Per the SAMD51 datasheet I/O multiplexing table, PB02's peripheral-A function is EXTINT[2], not EXTINT[3]. So
attachInterrupt(9, ...)configures/enables EIC line 3 while the pad's edges arrive on line 2 — the ISR can never run.digitalRead(9)works normally, which makes the failure silent.Suggested fix: change that row to
EXTERNAL_INT_2. Verified on hardware: with only that change, D9 catches every edge (self-test above, plus a real hall flow sensor). Note this makes D9 share EIC line 2 with D8 (PB18) — correct per silicon, same situation as other line-sharing pins on this variant (cf. #261); only one of D8/D9 can use attachInterrupt at a time.Debug Log as ATTACHED TXT
No crash/log — the sketch compiles and runs cleanly; the failure is silent (ISR simply never fires). Serial output demonstrating the bug is included in the sketch section above.
Screenshots
No response