Why is this RISING interrupt repeatedly triggering? I've set up an ISR to trigger on the RISING edge of pin #2, but I find that if pin 2 is held high, the ISR triggers repeatedly.

Here's a trace of the voltage measured right at the pin:



I can see a little bit of noise, but it shouldn't be enough to trigger multiple pulses. I've tried both INPUT and INPUT_PULLUP modes for the pin; behavior is the same.

constexpr byte kClockPin = 2;
constexpr byte kReadWritePin = 3;
constexpr byte kLedPin = 13;
constexpr int kNumAddressPins = 16;
constexpr byte kAddressPins[] = {/* MSB */52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22};
constexpr int kNumDataPins = 8;
constexpr byte kDataPins[] = {/* MSB */45, 43, 41, 39, 37, 35, 33, 31};

volatile bool dirty = false;
volatile uint8_t data = 0;
volatile uint16_t address = 0;
volatile bool read = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(kClockPin, INPUT_PULLUP);
  pinMode(kReadWritePin, INPUT);
  for (byte pin : kAddressPins) {
    pinMode(pin, INPUT);
  }
  for (byte pin : kDataPins) {
    pinMode(pin, INPUT);
  }
  pinMode(kLedPin, OUTPUT);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(kClockPin), OnClock, RISING);
}

void loop() {
  // digitalWrite(kLedPin, digitalRead(kClockPin));
  if (!dirty) return;
  char output[15];
  sprintf(output, "%04x %c %02x", address, read ? 'r' : 'w', data);
  Serial.println(output);
  dirty = false;
  // digitalWrite(kLedPin, digitalRead(kClockPin));
}

void OnClock() {
  read = digitalRead(kReadWritePin);
  data = 0;
  for (byte pin : kDataPins) {
    data = (data &lt;&lt; 1) + (digitalRead(pin) ? 1 : 0);
  }
  address = 0;
  for (byte pin : kAddressPins) {
    address = (address &lt;&lt; 1) + (digitalRead(pin) ? 1 : 0);
  }
  dirty = true;
}
Turns out the short answer is that I'm still not great at using an oscilloscope.

Longer version is that the noise was very visible at smaller time scales. A filter capacitor had come disconnected from the breadboard in a way that was hard to see, and that was causing a whole bunch of noise. Replacing it fixed the problem.