MCP23017 interrupt-on-change GPINTEN question

According to the datasheet for GPINTENA (0x04) and GPINTB (0x05):
"3.5.3 INTERRUPT-ON-CHANGE CONTROL REGISTER:
If a bit is set, the corresponding pin is enabled for interrupt-on-change. The DEFVAL and INTCON registers must also be configured if any pins are enabled for interrupt-on-change".

However, in below program registers 0x04 and 0x05 are not written to, hence default values 0x00 remain in place.

And yet when pushing the buttons, the LED's change state following interrupt detection.

How can this be explained in light of what the datasheet reads?

Source: Leon van der Horst - Microcontrollers

// http://www.leonvanderhorst.nl/MCP23017.htm#Project2

/* --------------------------------------------------------------------------------------------------------------------
 * | S.M.G. IJmond - I/O Controller met 8x Output (A) en 8x Input (B) met I2C Communicatie                                    |
 * |                                                                                                                  |
 * | LAATSE UPDATE: Zondag 26 feb 2017                                                                                |
 * | VERSIE: 0.4_Petzorg                                                                                              |
 * |                                                                                                                  |
 * |                                                                                                                  |
 * |   Aansluitingen  MCP23017                                                                                        |
 * |                                                                                                                  |       
 * |   Pin 9  = Vdd  = 5V                                                                                             |
 * |   Pin 10 = Vss  = Gnd                                                                                            |
 * |                                                                                                                  |                                                                                   |
 * |   Pin 12 = SCL  = Arduino A5 (4.7K weerstand naar 5V)                                                            |
 * |   Pin 13 = SDA  = Arduino A4 (4.7K weerstand naar 5V)                                                            |
 * |                                                                                                                  |
 * |   Pin 15 = A0    = 0 = Gnd, 1 = 5V                                                                               |
 * |   Pin 16 = A1    = 0 = Gnd, 1 = 5V                                                                               |
 * |   Pin 17 = A2    = 0 = Gnd, 1 = 5V                                                                               |
 * |                                                                                                                  |
 * |   pin 18 = reset = 5V, eventueel via 10k weerstand                                                               |
 * |                                                                                                                  |
 * |   Pin 21 = GPA0  = 1e groep van 8 I/O poorten, bit0                                                              | 
 * |   Pin 22 = GPA1  = 1e groep van 8 I/O poorten, bit1                                                              | 
 * |   Pin 23 = GPA2  = 1e groep van 8 I/O poorten, bit2                                                              | 
 * |   Pin 24 = GPA3  = 1e groep van 8 I/O poorten, bit3                                                              | 
 * |   Pin 25 = GPA4  = 1e groep van 8 I/O poorten, bit4                                                              | 
 * |   Pin 26 = GPA5  = 1e groep van 8 I/O poorten, bit5                                                              | 
 * |   Pin 27 = GPA6  = 1e groep van 8 I/O poorten, bit6                                                              | 
 * |   Pin 28 = GPA7  = 1e groep van 8 I/O poorten, bit7                                                              | 
 * |                                                                                                                  |
 * |   Pin 8  = GPB0  = 2e groep van 8 I/O poorten, bit0                                                              | 
 * |   Pin 7  = GPB1  = 2e groep van 8 I/O poorten, bit1                                                              | 
 * |   Pin 6  = GPB2  = 2e groep van 8 I/O poorten, bit2                                                              | 
 * |   Pin 5  = GPB3  = 2e groep van 8 I/O poorten, bit3                                                              | 
 * |   Pin 4  = GPB4  = 2e groep van 8 I/O poorten, bit4                                                              | 
 * |   Pin 3  = GPB5  = 2e groep van 8 I/O poorten, bit5                                                              | 
 * |   Pin 2  = GPB6  = 2e groep van 8 I/O poorten, bit6                                                              | 
 * |   Pin 1  = GPB7  = 2e groep van 8 I/O poorten, bit7                                                              | 
 * |                                                                                                                  |
 * |                                                                                                                  |
 * |   Decimale, hexadecimale, binaire waarden t.b.v. omrekenen:                                                      |
 * |   ---------------------------------------------------------                                                      |
 * |       Dec            Hex                Bit                                                                      | 
 * |      ------        ------             --------                                                                   |
 * |        0              0                 0000                                                                     | 
 * |        1              1                 0001                                                                     | 
 * |        2              2                 0010                                                                     |
 * |        3              3                 0011                                                                     |
 * |        4              4                 0100                                                                     | 
 * |        5              5                 0101                                                                     |
 * |        6              6                 0110                                                                     | 
 * |        7              7                 0111                                                                     | 
 * |        8              8                 1000                                                                     |
 * |        9              9                 1001                                                                     | 
 * |       10              A                 1010                                                                     |
 * |       11              B                 1011                                                                     |
 * |       12              C                 1100                                                                     | 
 * |       13              D                 1101                                                                     | 
 * |       14              E                 1110                                                                     |
 * |       15              F                 1111                                                                     | 
 * |                                                                                                                  |
 * | Binair lezen van rechts naar links, hexadecimaal van links naar rechts, decimaal van links naar rechts.          |
 * |                                                                                                                  |
 * |    128     64     32     16     8      4      2      1                                                           |
 * |    bit7   bit6   bit5   bit4   bit3   bit2   bit1   bit0                                                         |
 * |                                                                                                                  |
 * |                        A2  A1  A0                                                                                |
 * |    0   0   1   0   0   X   X   X = minimaal 32                                                                   |
 * |    0   0   1   0   0   0   0   0 = 32 = 0x20 = B00100000                                                         |
 * |    0   0   1   0   0   0   0   1 = 33 = 0x21 = B00100001                                                         |
 * |    0   0   1   0   0   0   1   0 = 34 = 0x22 = B00100010                                                         |
 * |    0   0   1   0   0   0   1   1 = 35 = 0x23 = B00100011                                                         |
 * |    0   0   1   0   0   1   0   0 = 36 = 0x24 = B00100100                                                         |
 * |    0   0   1   0   0   1   0   1 = 37 = 0x25 = B00100101                                                         |
 * |    0   0   1   0   0   1   1   0 = 38 = 0x26 = B00100110                                                         |
 * |    0   0   1   0   0   1   1   1 = 39 = 0x27 = B00100111                                                         |
 * |                                                                                                                  |
 * |    0   1   0   0   0   0   0   0 = 0x40 = 64 (= 4 x 16)                                                          |
 * |                                                                                                                  |
 * |    Rekenvoorbeelden:                                                                                             |
 * |    0x2F = 2x16^1 + 15x16^0                                                                                       |
 * |    B0100 = 0x2^0 + 0x2^1 + 1x2^2 + 0x2^3                                                                         |
 * |                                                                                                                  |
 * --------------------------------------------------------------------------------------------------------------------
*/

                     
#include <Wire.h>             // Wire library t.b.v. I²C  
// MCP23017 registers (everything except direction defaults to 0)

#define IODIRA   0x00   // IO direction  (0 = output, 1 = input (Default))
#define IODIRB   0x01
#define IOPOLA   0x02   // IO polarity   (0 = normal, 1 = inverse)
#define IOPOLB   0x03
#define GPINTENA 0x04   // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05   //
#define DEFVALA  0x06   // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB  0x07
#define INTCONA  0x08   // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB  0x09
#define IOCON    0x0A   // Interne Configuratie: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
                        // Als bank=0 dan IC in 16 bits mode registers zijn gekoppeld bank=0 dan in 8 bits mode en registers zijn losstaand
                        // Als mirror =0 dan interupts zijn onafhankelijk van elkaar en anders zijn ze gekoppeld (beide moeten hoog zijn) lees pag 24 apps
                        // Als seqop = 0 dan geen doortellen van interne adressering
                        // Als disslw =0 dan functie verandering van de slew rate van de sda pin. Lees functie/moment van sda pin. 
                        // Als haeven =0 dan hardware adres in of uitschakeling. bij nul dan a1 a2 a3 =0 en anders is het adres gelijk aan de pin instelling.
                        // Als odr =0 dan opendrain geeft de mogelijk uitgangen te koppelen. inpol wordt dan genegeerd.
                        // Als intpol =0 dan interupt polarity is de instellingen van de interupt pins. 0 of 1.
//#define IOCON 0x0B  // same as 0x0A is exact gelijk aan icon 0A en hoeft niet ingesteld te worden, neemt alles over van icon 0A.
#define GPPUA    0x0C   // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB    0x0D
#define INFTFA   0x0E   // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB   0x0F
#define INTCAPA  0x10   // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB  0x11
#define GPIOA    0x12   // Port value. Write to change, read to obtain value
#define GPIOB    0x13
#define OLLATA   0x14   // Output latch. Write to latch output.
#define OLLATB   0x15

#define I2Cadres  0x20       //  8 uitgangen op A en 8 ingangen op B

//--------------------------------------------------------------------- SETUP ---------------------------------------------------------------------------

void setup()
{ 
  Wire.begin();  // start Wire library als master. Volgens de documenten blijkt dat adres 0x00 een z.g. broadcast adres is wat elk ic dan kan ontvangen.
  Serial.begin(9600);
   
  Wire.beginTransmission(I2Cadres);                          // I²C Adres chip
  Wire.write(IOCON);                                         // IOCON register  
  Wire.write(0x20);                                          // Disable sequential addresses
  Wire.endTransmission();

// output op A  
  Wire.beginTransmission(I2Cadres);
  Wire.write(IODIRA);                                        // IODIRA register
  Wire.write(0x00);                                          // Allemaal 0, allemaal uitgangen
  Wire.endTransmission();
     
// input op B   
  Wire.beginTransmission(I2Cadres);
  Wire.write(IODIRB);                                        // IODIRB register
  Wire.write(0xFF);                                          // Allemaal 1, allemaal ingangen
  Wire.endTransmission();
 
  Wire.beginTransmission(I2Cadres);
  Wire.write(GPPUB);                                         //pull up weerstanden inschakelen
  Wire.write(0xFF);                                          // voor alle B ingangen
  Wire.endTransmission();
}

//--------------------------------------------------------------------- VOID ---------------------------------------------------------------------------


// Poort A
void turnOnLED()
{
  Wire.beginTransmission(I2Cadres);
  Wire.write(GPIOA);                                         // GPIOA = 1e groep van 8 I/O poorten.
  Wire.write(B00111100);
  Wire.endTransmission();
}

void turnOffLED()
{
  Wire.beginTransmission(I2Cadres);
  Wire.write(GPIOA);                                        // GPIOA = 1e groep van 8 I/O poorten.
  Wire.write(B11000011);
  Wire.endTransmission();
}

// Poort B
void ontvang()
{
   Wire.requestFrom(I2Cadres,GPIOB);   
       int x = Wire.read();                                // ontvang byte als getal 
    Serial.print("Schakelaar data van MCP23017 is ");
    Serial.print(x);                                       // toon de byte 
    int(y) = x;
    // om de bits uit te lezen
    Serial.print(" - Byte ");    
      if (x>=128) {
        Serial.print("1");
        x=x-128;
      }else{
        Serial.print("0");
      }
       if (x>=64) {
        Serial.print("1");
        x=x-64;
      }else{
        Serial.print("0");
      }
       if (x>=32) {
        Serial.print("1");
        x=x-32;
      }else{
        Serial.print("0");
      }
       if (x>=16) {
        Serial.print("1");
        x=x-16;
      }else{
        Serial.print("0");
      }
       if (x>=8) {
        Serial.print("1");
        x=x-8;
      }else{
        Serial.print("0");
      }
       if (x>=4) {
        Serial.print("1");
        x=x-4;
      }else{
        Serial.print("0");
      }
       if (x>=2) {
        Serial.print("1");
        x=x-2;
      }else{
        Serial.print("0");
      }
       if (x>=1) {
        Serial.println("1");
        x=x-1;
      }else{
        Serial.println("0");
      }
                                                         // einde bits tonen in Y moet het getal staan
}


//--------------------------------------------------------------------- VOID LOOP ---------------------------------------------------------------------------

void loop()
{
  turnOnLED();
//  turnOnLEDB();
  ontvang();
  delay(100);                                            // tijdsduur leds aan

//  turnOffLEDB();
  delay(100);

//  turnOnLEDB();
  delay(100);

  turnOffLED();
//  turnOffLEDB(); 
  ontvang();
  delay(100);                                            // tijdsduur leds uit
  
   delay(100);                                           // tijdsduur leds aan
//  turnOnLEDB();

  delay(100);
//  turnOffLEDB();
  delay(100);

  
}

Yes decoupling caps are present.
Default is 0x00, hence, for registers GPINTA and GPINTB interrupt-on-change is not active.
So these registers must explicitely be written with 0xff in order for any interrupt output to occur.

If above register bits are set then interrupt outputs do happen every time a change is detected, if the INTCON register remains at default (0x00) values.

So the mere fact of writing 0xff to the GPINTEN registers will cause interrupt-on-change to occur.

Why was this not done in the program in OP? Because that program is wrong as I discovered after posting. Registers 0x04 and 0x05 must be written with 0xff for any interrupt to occur.

How are you detecting that the MCP23017 has generated an interrupt in response to a button press ?
Your schematic shows that the interrupt pins INTA(19) and (INTB)20 are unconnected.

You are correct; the schematic is wrong as well.

And also you don't need those pull down resistors if you enable the internal pull up resistors. You can even preserve the logic level on press if you use the register to invert the input values.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.