An MCP23017 interrupt can disappear before firmware records its cause. The device clears a port interrupt when software reads that port’s INTCAP or GPIO register, so the safe service order is to read INTF first, then read the captured input state.
Featured image: Adafruit.
This article follows Microchip data sheet DS20001952 and uses the default BANK=0 register map. Library names vary, but the register behavior does not.
Configure what counts as a change
Set the relevant bit in GPINTEN to enable interrupt-on-change for an input. INTCON chooses the comparison rule: a zero bit compares the input with its previous value; a one bit compares it with the corresponding DEFVAL bit. The second form is useful when one level is normal and only the opposite level should assert an interrupt.
Keep IODIR configured for input and apply GPPU when the switch or open-collector signal needs the MCP23017’s internal pull-up. Electrical conditioning still matters: a floating input can create valid-looking but unwanted changes.

Service the interrupt without erasing the cause
In BANK=0, INTFA and INTFB are at 0x0E and 0x0F. INTCAPA and INTCAPB follow at 0x10 and 0x11; GPIOA and GPIOB are at 0x12 and 0x13.
- Read the appropriate INTF register and save its bit mask.
- Read INTCAP for the same port to obtain the pin states captured when the event occurred.
- Process only the bits set in the saved INTF mask.
- If the interrupt line is still active, repeat the sequence; another change may have arrived while the first event was being handled.
Reading GPIO instead of INTCAP also clears the interrupt, but GPIO reports the current level rather than the latched level at the interrupt boundary. That distinction matters when a short pulse ends before the I2C transaction begins.

Combine interrupt pins deliberately
IOCON.MIRROR makes INTA and INTB act as one combined interrupt indication. That can save a host pin, but firmware must inspect both ports to identify the source. IOCON.ODR changes the outputs to open-drain; when ODR is set, it overrides INTPOL. Open-drain operation is the appropriate choice when multiple devices share a pulled-up interrupt line.
Do not treat INTCAP as a queue. It is a capture register, not an event log. If several transitions occur faster than the host can service and clear the condition, software may know that a pin caused an interrupt without reconstructing every edge. A counter or high-rate encoder belongs on hardware designed to count pulses, not behind a slow polling path over I2C.
If the host cannot complete register reads reliably, fix the bus first; TVG’s I2C stuck-low recovery sequence separates bus recovery from interrupt logic.

