Skip to content

Grand Central M4: D9 (PB02) has wrong EXTERNAL_INT in variant.cpp — attachInterrupt(9) never fires #394

Description

@Mr-Champagne-TCM

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 ?

  1. 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).
  2. Open the serial monitor at 115200.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions