Leonardo switchbox, polling vs Interupts

Good evening all, I have a switchbox project that I have been playing with for a while. I thought I had it sorted but I have run into a problem.

Components:
Arduino Leonardo
12 toggle switches - variation; on/off/on ; on/on ; on/off/momentary
4 rotary endocers with center push switch ;
Rotary Encoder + Extras | The Pi Hut
2 DFRobot MCP23017 expansion cards:
Gravity: MCP23017 IIC 16 Digital IO Expansion Module Wiki - DFRobot

The MCP23017 boards are dedicated to the 12 toggle switches, using 24 pins.
The rotary encoders are connected directly to the Leonardo for both rotary and push button functions.

I created the code as two seperate entities, one part for the toggle switches, the other for the rotary encoders. Both seemed to work fine until I wired it all together. The issue I get is that the rotary switches barely register an input. If I unplug the expansion cards, the rotary switches work exactly as I wanted them to.

I done a lot of looking around and I'm guessing, and that's all it is, that the issue is to do with polling. I'm not clear if the card is polling to slow or too fast - either way the encoders are not registering inputs.

So after a bit more digging, and making a huge assumption my wiring and coding is indeed correct, it looks like the best way of dealing with this is to use interrupts? If that is the case, I understand I have the option of either configuring interrupts on the individual MCP pins, or 'globally' on the cards themselves? Am I barking up the right tree?

Though I understand the concept of interrupts, I do not understand the examples of code I have thus far looked at.

My code is long hand, I'm sure there are ways of optimising it, but right now I just want to figure out how to get it all working. So if inclined, and please in pigeon english, can anyone give me a few pointers or suggestions to help me finish this off, many thanks.

#include <Joystick.h>
#include <MD_REncoder.h>
#include <DFRobot_MCP23017.h>

DFRobot_MCP23017 mcp(Wire, 0x27);   //Default address of first MCP 16 pin expansion card
DFRobot_MCP23017 mcp1(Wire, 0x25);  //Default address of second MCP 16 pin expansion card



//#define Collective A0  //define collective lever and analogue pin
//int xAxisRotation_ = 90;
//#define Throttle A1  //define throttle rotation grip ans analogue pin
//int Throttle_ = 0;
#define Collective A5  //define twist grip
int xAxisRotation_ = 90;
#define Throttle  //define throttle
int Throttle_ = 0;


#define Button1 0    // encoder 1 pin A define USB Windows Button number 1 and associated digital pin 0 on the Leonardo
#define Button2 1    //encoder 1 pin B
#define Button3 10   //encoder 1 push button
#define Button4 4    //encoder 2 pin A
#define Button5 5    //encoder 2 pin B
#define Button6 11   //encoder 2 push button
#define Button7 6    //encoder 3 pin A
#define Button8 7    //encoder 3 pin B
#define Button9 12   //encoder 3 push button
#define Button10 8   //encoder 3 push button
#define Button11 9   //encoder 3 push button
#define Button12 13  //encoder 3 push button

#define Button13 mcp.eGPA0  //Button 1 On
#define Button14 mcp.eGPA1  //Button 1 On
#define Button15 mcp.eGPA2  //Button 2 On
#define Button16 mcp.eGPA3  //Button 2 On
#define Button17 mcp.eGPA4  //Button 3 On Off
#define Button18 mcp.eGPA5  //Button 3 Off On
#define Button19 mcp.eGPA6  //Button 4 On Off
#define Button20 mcp.eGPA7  //Button 4 Off On

#define Button21 mcp.eGPB0  //Button 5 Off On
#define Button22 mcp.eGPB1  //Button 5 Off Mo
#define Button23 mcp.eGPB2  //Button 6 Off On
#define Button24 mcp.eGPB3  //Button 6 Off Mo
#define Button25 mcp.eGPB4  //Button 7 Off On
#define Button26 mcp.eGPB5  //Button 7 Off Mo
#define Button27 mcp.eGPB6  //Button 8 Off On
#define Button28 mcp.eGPB7  //Button 8 Off Mo

#define Button29 mcp1.eGPA0  //Button 1 On Off
#define Button30 mcp1.eGPA1  //Button 1 Off On
#define Button31 mcp1.eGPA2  //Button 2 On Off
#define Button32 mcp1.eGPB0  //Button 2 Off On
#define Button33 mcp1.eGPA4  //Button 3 On Off
#define Button34 mcp1.eGPA5  //Button 3 Off On
#define Button35 mcp1.eGPA6  //Button 4 On Off
#define Button36 mcp1.eGPA7  //Button 4 Off On


MD_REncoder ROTARY1 = MD_REncoder(0, 1);  //define which pins the A and B pins of the encoder are attached to
MD_REncoder ROTARY2 = MD_REncoder(4, 5);
MD_REncoder ROTARY3 = MD_REncoder(6, 7);
MD_REncoder ROTARY4 = MD_REncoder(8, 9);

int lastButton1State = 0;  // pin state variable value
int lastButton2State = 0;
int lastButton3State = 0;
int lastButton4State = 0;
int lastButton5State = 0;
int lastButton6State = 0;
int lastButton7State = 0;
int lastButton8State = 0;
int lastButton9State = 0;
int lastButton10State = 0;
int lastButton11State = 0;
int lastButton12State = 0;
int lastButton13State = 0;
int lastButton14State = 0;
int lastButton15State = 0;
int lastButton16State = 0;
int lastButton17State = 0;
int lastButton18State = 0;
int lastButton19State = 0;
int lastButton20State = 0;
int lastButton21State = 0;
int lastButton22State = 0;
int lastButton23State = 0;
int lastButton24State = 0;
int lastButton25State = 0;
int lastButton26State = 0;
int lastButton27State = 0;
int lastButton28State = 0;
int lastButton29State = 0;
int lastButton30State = 0;
int lastButton31State = 0;
int lastButton32State = 0;
int lastButton33State = 0;
int lastButton34State = 0;
int lastButton35State = 0;
int lastButton36State = 0;




Joystick_ Joystick(0x04, JOYSTICK_TYPE_JOYSTICK,  //define joystick type

                   36, 0,  // Button Count, Hat Switch Count

                   false, false, false,  // X and Y, Z Axis

                   true, false, false,  //  Rx, Ry, or Rz

                   false, true,  //  rudder, throttle

                   false, false, false);  // accelerator, brake, or steering

const bool initAutoSendState = true;



void setup() {
  Joystick.begin();  //begin joystick interface
  ROTARY1.begin();   //begin specific rotary 1 instance
  ROTARY2.begin();   //begin specific rotary 2 instance
  ROTARY3.begin();   //begin specific rotary 3 instance
  ROTARY4.begin();   //begin specific rotary 3 instance
  mcp.begin();       //begin expansion card interface
  mcp1.begin();


  pinMode(Button1, INPUT_PULLUP);  //set pin to use internal pullup resistor
  pinMode(Button2, INPUT_PULLUP);
  pinMode(Button3, INPUT_PULLUP);
  pinMode(Button4, INPUT_PULLUP);
  pinMode(Button5, INPUT_PULLUP);
  pinMode(Button6, INPUT_PULLUP);
  pinMode(Button7, INPUT_PULLUP);
  pinMode(Button8, INPUT_PULLUP);
  pinMode(Button9, INPUT_PULLUP);
  pinMode(Button10, INPUT_PULLUP);
  pinMode(Button11, INPUT_PULLUP);
  pinMode(Button12, INPUT_PULLUP);


  mcp.pinMode(mcp.eGPA0, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPA1, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPA2, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPA3, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPA4, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPA5, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPA6, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPA7, INPUT_PULLUP);

  mcp.pinMode(mcp.eGPB0, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPB1, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPB2, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPB3, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPB4, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPB5, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPB6, INPUT_PULLUP);
  mcp.pinMode(mcp.eGPB7, INPUT_PULLUP);

  mcp1.pinMode(mcp1.eGPA0, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPA1, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPA2, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPA3, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPA4, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPA5, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPA6, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPA7, INPUT_PULLUP);

  mcp1.pinMode(mcp1.eGPB0, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPB1, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPB2, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPB3, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPB4, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPB5, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPB6, INPUT_PULLUP);
  mcp1.pinMode(mcp1.eGPB7, INPUT_PULLUP);





  Serial.begin(57600);
}

void loop() {


  //Scan Rotaries
  uint8_t ROTARY1_IN = ROTARY1.read();

  //send a button push when rotary is deteceted - Button 1 = Clockwise, Button2 = Counter_clockwise
  if (ROTARY1_IN) {
    if (ROTARY1_IN == DIR_CW) {
      Joystick.setButton(0, 1);  // Turn Button 1 on, wait 150ms, then turn off
      delay(100);
      Joystick.setButton(0, 0);
    }
    if (ROTARY1_IN == DIR_CCW) {
      Joystick.setButton(1, 1);  // Turn Button 2 on, wait 150ms, then turn off
      delay(100);
      Joystick.setButton(1, 0);
    }
  }

  uint8_t ROTARY2_IN = ROTARY2.read();

  //send a button push when rotary is deteceted - Button 1 = Clockwise, Button2 = Counter_clockwise
  if (ROTARY2_IN) {
    if (ROTARY2_IN == DIR_CW) {
      Joystick.setButton(3, 1);  // Turn Button 1 on, wait 150ms, then turn off
      delay(100);
      Joystick.setButton(3, 0);
    }
    if (ROTARY2_IN == DIR_CCW) {
      Joystick.setButton(4, 1);  // Turn Button 2 on, wait 150ms, then turn off
      delay(100);
      Joystick.setButton(4, 0);
    }
  }

  uint8_t ROTARY3_IN = ROTARY3.read();

  //send a button push when rotary is deteceted - Button 1 = Clockwise, Button2 = Counter_clockwise
  if (ROTARY3_IN) {
    if (ROTARY3_IN == DIR_CW) {
      Joystick.setButton(6, 1);  // Turn Button 1 on, wait 150ms, then turn off
      delay(100);
      Joystick.setButton(6, 0);
    }
    if (ROTARY3_IN == DIR_CCW) {
      Joystick.setButton(7, 1);  // Turn Button 2 on, wait 150ms, then turn off
      delay(100);
      Joystick.setButton(7, 0);
    }
  }

  uint8_t ROTARY4_IN = ROTARY4.read();

  //send a button push when rotary is deteceted - Button 1 = Clockwise, Button2 = Counter_clockwise
  if (ROTARY4_IN) {
    if (ROTARY4_IN == DIR_CW) {
      Joystick.setButton(9, 1);  // Turn Button 1 on, wait 150ms, then turn off
      delay(100);
      Joystick.setButton(9, 0);
    }
    if (ROTARY4_IN == DIR_CCW) {
      Joystick.setButton(10, 1);  // Turn Button 2 on, wait 150ms, then turn off
      delay(100);
      Joystick.setButton(10, 0);
    }
  }


  Throttle_ = (analogRead(A0) - analogRead(A1)) / 04;  //set collective parameteers
  Throttle_ = map(Throttle_, 0, 255, 255, 0);
  Joystick.setThrottle(Throttle_);
  Joystick.setThrottleRange(0, 255);

  xAxisRotation_ = analogRead(A5);  //set throttle parameters
  xAxisRotation_ = map(xAxisRotation_, 0, 1023, 0, 255);
  Joystick.setRxAxis(xAxisRotation_);




  int currentButton3State = !digitalRead(Button3);
  if (currentButton3State != lastButton3State) {
    Joystick.setButton(2, currentButton3State);
    lastButton3State = currentButton3State;
  }
  int currentButton6State = !digitalRead(Button6);
  if (currentButton6State != lastButton6State) {
    Joystick.setButton(5, currentButton6State);
    lastButton6State = currentButton6State;
  }
  int currentButton9State = !digitalRead(Button9);
  if (currentButton9State != lastButton9State) {
    Joystick.setButton(8, currentButton9State);
    lastButton9State = currentButton9State;
  }
  int currentButton12State = !digitalRead(Button12);
  if (currentButton12State != lastButton12State) {
    Joystick.setButton(11, currentButton12State);
    lastButton12State = currentButton12State;
  }
  int currentButton13State = !mcp.digitalRead(Button13);
  if (currentButton13State != lastButton13State) {
    Joystick.setButton(12, currentButton13State);
    lastButton13State = currentButton13State;
  }
  int currentButton14State = !mcp.digitalRead(Button14);
  if (currentButton14State != lastButton14State) {
    Joystick.setButton(13, currentButton14State);
    lastButton14State = currentButton14State;
  }
  int currentButton15State = !mcp.digitalRead(Button15);
  if (currentButton15State != lastButton15State) {
    Joystick.setButton(14, currentButton15State);
    lastButton15State = currentButton15State;
  }
  int currentButton16State = !mcp.digitalRead(Button16);
  if (currentButton16State != lastButton16State) {
    Joystick.setButton(15, currentButton16State);
    lastButton16State = currentButton16State;
  }
  int currentButton17State = !mcp.digitalRead(Button17);
  if (currentButton17State != lastButton17State) {
    Joystick.setButton(16, currentButton17State);
    lastButton17State = currentButton17State;
  }
  int currentButton18State = !mcp.digitalRead(Button18);
  if (currentButton18State != lastButton18State) {
    Joystick.setButton(17, currentButton18State);
    lastButton18State = currentButton18State;
  }
  int currentButton19State = !mcp.digitalRead(Button19);
  if (currentButton19State != lastButton19State) {
    Joystick.setButton(18, currentButton19State);
    lastButton19State = currentButton19State;
  }
  int currentButton20State = !mcp.digitalRead(Button20);
  if (currentButton20State != lastButton20State) {
    Joystick.setButton(19, currentButton20State);
    lastButton20State = currentButton20State;
  }
  int currentButton21State = !mcp.digitalRead(Button21);
  if (currentButton21State != lastButton21State) {
    Joystick.setButton(20, currentButton21State);
    lastButton21State = currentButton21State;
  }
  int currentButton22State = !mcp.digitalRead(Button22);
  if (currentButton22State != lastButton22State) {
    Joystick.setButton(21, currentButton22State);
    lastButton22State = currentButton22State;
  }
  int currentButton23State = !mcp.digitalRead(Button23);
  if (currentButton23State != lastButton23State) {
    Joystick.setButton(22, currentButton23State);
    lastButton23State = currentButton23State;
  }
  int currentButton24State = !mcp.digitalRead(Button24);
  if (currentButton24State != lastButton24State) {
    Joystick.setButton(23, currentButton24State);
    lastButton24State = currentButton24State;
  }
  int currentButton25State = !mcp.digitalRead(Button25);
  if (currentButton25State != lastButton25State) {
    Joystick.setButton(24, currentButton25State);
    lastButton25State = currentButton25State;
  }
  int currentButton26State = !mcp.digitalRead(Button26);
  if (currentButton26State != lastButton26State) {
    Joystick.setButton(25, currentButton26State);
    lastButton26State = currentButton26State;
  }
  int currentButton27State = !mcp.digitalRead(Button27);
  if (currentButton27State != lastButton27State) {
    Joystick.setButton(26, currentButton27State);
    lastButton27State = currentButton27State;
  }
  int currentButton28State = !mcp.digitalRead(Button28);
  if (currentButton28State != lastButton28State) {
    Joystick.setButton(27, currentButton28State);
    lastButton28State = currentButton28State;
  }
  int currentButton29State = !mcp1.digitalRead(Button29);
  if (currentButton29State != lastButton29State) {
    Joystick.setButton(28, currentButton29State);
    lastButton29State = currentButton29State;
  }
  int currentButton30State = !mcp1.digitalRead(Button30);
  if (currentButton30State != lastButton30State) {
    Joystick.setButton(29, currentButton30State);
    lastButton30State = currentButton30State;
  }
  int currentButton31State = !mcp1.digitalRead(Button31);
  if (currentButton31State != lastButton31State) {
    Joystick.setButton(30, currentButton31State);
    lastButton31State = currentButton31State;
  }
  int currentButton32State = !mcp1.digitalRead(Button32);
  if (currentButton32State != lastButton32State) {
    Joystick.setButton(31, currentButton32State);
    lastButton32State = currentButton32State;
  }
  int currentButton33State = !mcp1.digitalRead(Button33);
  if (currentButton33State != lastButton33State) {
    Joystick.setButton(32, currentButton33State);
    lastButton33State = currentButton33State;
  }
  int currentButton34State = !mcp1.digitalRead(Button34);
  if (currentButton34State != lastButton34State) {
    Joystick.setButton(33, currentButton34State);
    lastButton34State = currentButton34State;
  }
  int currentButton35State = !mcp1.digitalRead(Button35);
  if (currentButton35State != lastButton35State) {
    Joystick.setButton(34, currentButton35State);
    lastButton35State = currentButton35State;
  }
  int currentButton36State = !mcp1.digitalRead(Button36);
  if (currentButton36State != lastButton36State) {
    Joystick.setButton(35, currentButton36State);
    lastButton36State = currentButton36State;
  }
}

I don’t think you get extra credit for more typing, but it’s good practice .

You should create a struct for a single button, then an array of that struct

You will shrink your code size by a factor of twenty, and make it easier to read and debug.

Start there..

Can I ask why you are using those MCP23017 chips? You have enough pins on the Leonardo without them. The toggle switches, along with the encoder pushbuttons, could be wired as a 4x4 matrix requiring 8 Leonardo pins. You would need to wire a small diode in series with each toggle switch.

Your code is exceedingly long and repetitive. You need to learn to use arrays. Any variables with numbers 1,2,3... in their names should be an array.

Just use an Arduino Due, then you have enough I/O pins.

thank you I will investigate

The MCP Option just seemed an easier solution givein my limited knowledge. Ansd yes the code is long, once I have it all working as I want, I will then focus on learning how to optimise.

I think the problem is caused by the code being so poorly optimised. The library you are using to read the expander chips is a big part of the problem. It allows only a single pin to be read at a time. Each read involves communication between the Arduino and the expander chip, which is a relatively slow process.

As a quick fix, try adding

Wire.setClock(400000);

to setup().

If more improvement is needed, then look for an alternative library for the expander chips which allows all 16 pins to be read in a single command. This will reduce the slow communications between the Arduino and the expander chips by 16x.

Thank you I'll look at that - can I ask is there a particular library that you think would be better suited? Many thanks for the input.

You could try the Adafruit library

It has a readGPIOAB() which will read all 16 pins in a single command.

Thank you so very much, I will investigate!!

Thank you for the pointer - I did look at the Adafruit, used the example sketch for interrupts and it doesn't work.

So I have no working reference to bolster my understanding. when I look at other libray's they have stuff for making buttons works, that I can do with the DFRobot library, interrupts is a different kettle of fish.

So this is the code - at this point I have only one toggle switch connected. If I use the straight button example it works fine, so guessing this is to do with how interrupts are configured - feeling defeated as I can't find a definitve source, or how too.

// NOTE: This is a simple example that only reads the INTA or INTB pin
//       state. No actual interrupts are used on the host microcontroller.
//       MCP23XXX supports the following interrupt modes:
//           * CHANGE - interrupt occurs if pin changes to opposite state
//           * LOW - interrupt occurs while pin state is LOW
//           * HIGH - interrupt occurs while pin state is HIGH

// ok to include only the one needed
// both included here to make things simple for example
#include <Adafruit_MCP23X08.h>
#include <Adafruit_MCP23X17.h>

#define BUTTON_PIN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)  // MCP23XXX pin used for interrupt

#define INT_PIN 2  // microcontroller pin attached to INTA/B

// only used for SPI
//#define CS_PIN 6

// uncomment appropriate line
//Adafruit_MCP23X08 mcp;
Adafruit_MCP23X17 mcp;

void setup() {
  Serial.begin(9600);
  Serial.println("MCP23xxx Interrupt Test!");
  mcp.begin_I2C(0x27);
  {
    Serial.println("Error.");
  }

  // configure MCU pin that will read INTA/B state
  pinMode(INT_PIN, INPUT);

  // OPTIONAL - call this to override defaults
  // mirror INTA/B so only one wire required
  // active drive so INTA/B will not be floating
  // INTA/B will be signaled with a LOW
  mcp.setupInterrupts(true, false, LOW);

  // configure button pin for input with pull up
  mcp.pinMode(BUTTON_PIN, INPUT_PULLUP);

  // enable interrupt on button_pin
  mcp.setupInterruptPin(BUTTON_PIN, LOW);

  Serial.println("Looping...");
}

void loop() {
  if (!digitalRead(INT_PIN)) {
    Serial.print("Interrupt detected on pin: ");
    Serial.println(mcp.getLastInterruptPin());
    Serial.print("Pin states at time of interrupt: 0b");
    Serial.println(mcp.getCapturedInterrupt(), 2);
    delay(250);  // debounce
    // NOTE: If using DEFVAL, INT clears only if interrupt
    // condition does not exist.
    // See Fig 1-7 in datasheet.
    mcp.clearInterrupts();  // clear
  }
}

I have also tried changing the 'low' statement to 'change' with no difference as well as configuing the INT_PIN 2 to pullup.

You're welcome. Did my suggestion work? I guess not, because you decided to try something else. Maybe if you post the code where you tried my suggestion, I can help.

Hello PaulRB, sorry for the delay - been tied up at work......anyhow, I have been playing with the Adafruit library you suggested.....It's been a journey just trying to find examples I can backward engineer to get any understanding.

Finally stumbled across a sketch that at least gives me an output which I have tidied up slightly, but I'm not sure I completely understand whats going on in the last 'print' aspect of the sketch.

I had originally set the mcp.setupInterrupts and mcp.setupInterruptPin both to 'CHANGE' as I'm using toggle switches - on / on and on/off/on. When set to that the output I get is this as I toggle the switch:

Pin states at time of interrupt: 0b1111111011111110
Interrupt detected on pin: 255
Pin states at time of interrupt: 0b1111111011111110
Interrupt detected on pin: 255
Pin states at time of interrupt: 0b1111111011111101
Interrupt detected on pin: 255
Pin states at time of interrupt: 0b1111111011111101

Pin 255, ?
If I then set set the mcp.setupInterrupts and mcp.setupInterruptPin to LOW it will actually define the pin number:

Interrupt detected on pin: 0
Pin states at time of interrupt: 0b1111111111111110
Interrupt detected on pin: 0
Pin states at time of interrupt: 0b1111111111111110
Interrupt detected on pin: 1
Pin states at time of interrupt: 0b1111111111111101
Interrupt detected on pin: 1
Pin states at time of interrupt: 0b1111111111111101

So it seems that interrupts are working - now I need to figure out how to interface that to the joystick.h sketch. So if I wanted to be notified only when the switch state changes do I need to use 'buttonstate'?

Many thanks

#include <Adafruit_MCP23X17.h>


//#define BUTTON_PIN { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, } ??????
#define BUTTON_PIN0 0
#define BUTTON_PIN1 1
#define BUTTON_PIN2 2
#define BUTTON_PIN3 3
#define BUTTON_PIN4 4
#define BUTTON_PIN5 5
#define BUTTON_PIN6 6
#define BUTTON_PIN7 7
#define BUTTON_PIN8 8
#define BUTTON_PIN9 9
#define BUTTON_PIN10 10
#define BUTTON_PIN11 11
#define BUTTON_PIN12 12
#define BUTTON_PIN13 13
#define BUTTON_PIN14 14
#define BUTTON_PIN15 15

#define INT_PIN 3  // Arduino Leonardo pin attached to INTA/B

Adafruit_MCP23X17 mcp;

void setup() {
  Serial.begin(9600);
  mcp.begin_I2C(0x27);
  {
  }
  pinMode(INT_PIN, INPUT_PULLUP);  //Arduino Leonardo


  mcp.setupInterrupts(true, false, LOW);


  for (int i = 0; i < 16; i++) {
    mcp.pinMode(i, INPUT_PULLUP);
  }
  for (int i = 0; i < 16; i++) {
    mcp.setupInterruptPin(i, LOW);
  }
}
void loop() {


  digitalRead(INT_PIN);
  {
    Serial.print("Interrupt detected on pin: ");
    Serial.println(mcp.getLastInterruptPin());
    Serial.print("Pin states at time of interrupt: 0b");
    Serial.println(mcp.getCapturedInterrupt(), 2);
    //Serial.println(mcp.getCapturedInterrupt());
    delay(1000);  // debounce

    mcp.clearInterrupts();
  }
}

I'm not familiar with these interrupt functions you are trying to use. I'm not sure what advantage you see in them.

I tried to suggest a solution to the problem in your original post, but you seem to have gone off on a tangent, and are making things more complex as a result.

If you can't get this interrupts idea to work and want to try my original suggestion, let me know. To call my attention to the topic, put @ in front of my name so I get a notification. Like this: @downloadkid

@PaulRB ok, tangent YES, lots of rabbit holes as I was trying how to figure out what to do with the mcp.readGPIOAB command which led me back down the interrupt route.....

I can't seem to find an example sketch. So tried many different 'guesses', all failing. I think it comes down to what to do with the information once all of the pins have been read. in my limited understanding the flow is read the pins, see which one has changed and print out which button has changed. Does this come down to the buttonstate again?

All I get is a print out of button 1 , then 2, then 1......

This is as far as I have got:

ty#include <Adafruit_MCP23X17.h>
Adafruit_MCP23X17 mcp;

//#define BUTTON_PIN { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }  // MCP23XXX pin button is attached to
#define BUTTON_PIN1 0
#define BUTTON_PIN2 1

void setup() {
  Serial.begin(9600);
  mcp.begin_I2C(0x27);

  for (int i = 0; i < 16; i++) {
    mcp.pinMode(i, INPUT_PULLUP);
  }
}

void loop() {

  //mcp.digitalRead(mcp.readGPIOAB());
  mcp.readGPIOAB();
  if (!mcp.digitalRead(BUTTON_PIN1))
    ;
  Serial.println("Button 1!");
  delay(1000);

 if (!mcp.digitalRead(BUTTON_PIN2));
  Serial.println("Button 2!");
  delay(1000);
}pe or paste code here

Ok, let me show you the next step

#include <Adafruit_MCP23X17.h>
Adafruit_MCP23X17 mcp;

void setup() {
  Serial.begin(115200);
  mcp.begin_I2C(0x27);

  for (byte p = 0; p < 16; p++) {
    mcp.pinMode(p, INPUT_PULLUP);
  }
}

void loop() {

  uint16_t pins = mcp.readGPIOAB();

  for (byte p = 0; p < 16; p++) {
    Serial.print(bitRead(pins, p));
  }
  Serial.println();

  delay(20);
}

uint16_t pins = mcp.readGPIOAB();

If you are going to use periodic readings to see what inputs have changed, you will want to investigate using the XOR (^) operator with the previous and present value of the pins variable.

For both MCP chips:

#include <Adafruit_MCP23X17.h>
Adafruit_MCP23X17 mcp1;
Adafruit_MCP23X17 mcp2;

void setup() {
  Serial.begin(115200);
  mcp1.begin_I2C(0x27);
  mcp2.begin_I2C(0x25);

  for (byte p = 0; p < 16; p++) {
    mcp1.pinMode(p, INPUT_PULLUP);
    mcp2.pinMode(p, INPUT_PULLUP);
  }
}

void loop() {

  uint16_t pins1 = mcp1.readGPIOAB();
  uint16_t pins2 = mcp2.readGPIOAB();

  uint32_t pins = pins1 << 16 | pins2;

  for (byte p = 0; p < 32; p++) {
    Serial.print(bitRead(pins, p));
  }
  Serial.println();

  delay(20);
}

Checking for changes:

#include <Adafruit_MCP23X17.h>
Adafruit_MCP23X17 mcp1;
Adafruit_MCP23X17 mcp2;

void setup() {
  Serial.begin(115200);
  mcp1.begin_I2C(0x27);
  mcp2.begin_I2C(0x25);

  for (byte p = 0; p < 16; p++) {
    mcp1.pinMode(p, INPUT_PULLUP);
    mcp2.pinMode(p, INPUT_PULLUP);
  }
}

void loop() {

  uint16_t pins1 = mcp1.readGPIOAB();
  uint16_t pins2 = mcp2.readGPIOAB();

  uint32_t pins = pins1 << 16 | pins2;
  static uint32_t prevPins;

  if (pins != prevPins) {

    for (byte p = 0; p < 32; p++) {
      Serial.print(bitRead(pins, p));
    }
    Serial.println();

    prevPins = pins;
  }

  delay(20);
}

...bless you.....something to focus on and play with!!