Adafruit MCP23XXX Interrupt: How to detect falling edge only?

Hello,

I've used the for the MCP23XXX interrupts fount here: Adafruit-MCP23017-Arduino-Library/mcp23xxx_interrupt.ino at master · adafruit/Adafruit-MCP23017-Arduino-Library · GitHub

I'd like to be able to detect a switch pressed on the falling edge only and haven't found out how to do it. I assumed it would be some configuration of setupInterrupts() and setupInterruptPin being set to CHANGE and/or LOW, but switching those around haven't worked.

Edit: Instead all I'm getting is that the pin is constantly reading as LOW for the duration of the time that the switch is pressed. The message "Interrupt detected on pin: 1" appears at the rate of the delay in the loop.

The closest thing that I found was this page which uses a depreciated version of the Adafruit MCP23017 library, so it isn't useful to me: https://www.best-microcontroller-projects.com/mcp23017.html

How do I configure the MCP23XXX interrupts so that it only detects a state change on the falling edge? Thanks!

Post the code.

Could your switch be bouncing?

a7

I don't believe it's bouncing, as the "Interrupt detected on pin: N" repeats at the rate of the delay so long as I have the switch pressed LOW. A bounce would just happen several times the moment the switch is pressed, but not held, if I understand correctly.


   
// 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   // MCP23XXX pin used for interrupt

#define INT_PIN 7      // 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);
  //while (!Serial);
  Serial.println("MCP23xxx Interrupt Test!");

  // uncomment appropriate mcp.begin
  if (!mcp.begin_I2C()) {
  //if (!mcp.begin_SPI(CS_PIN)) {
    Serial.println("Error.");
    while (1);
  }

  // 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());
    delay(250); // debounce
  }
}

OK, sry.

What Arduino board are you using?

Can you hand draw a schematic diagram of how you have everything hooked up?

No need to use fancy software, just paper and pencil, show all the connections take a celly and post it here.

Google how to make a schematic and look at a few, no need to make a career out of it, just label the parts and show where you wires go.

a7

no problem!

I'm using an stm32f401ccu black pill board so understandable if you can't help me with that.

here's the schematic either way. there weren't any specific circuit instructions with the adafruit examples but i figured to err on the side of caution by using the 4.7k resistors for the SDA and SCL lines, as well as the 10k for the reset pin to 3.3v.

(Despite the firm instruction to always use 4.7k resistors for i2c lines, a majority of the circuits you'll see if you Google "mcp23017 arduino" do not use them. not sure why)

the 100nf cap to ground for the interrupt pin was actually a relic from me trying to use the non-adafruit MCP23017 library from the Arduino page which does detect falling edge, but i don't understand how the code works at all. regardless, there is no difference when using the Adafruit code whether the cap is there or not. Least as far as i can tell.

OK, caught your post before heading to the beach.

I'm in overhead, but that's OK, I use the MCP23017 and never learnt about the interrupts… good opportunity.

Nice diagram, but it doesn't look like it matches the posted code?

In the diagram you are looking at pin 19, which would be INTB, but your switch is on 22, which is GPA1. Before going deep in the data sheet, that might be an issue.

In the code, you've nominated BUTON_PIN (1), is that correct?

Sorry if all that has been checked, double checked and then… checked again.

Have you tried very simple usage test of the MCP23017 hooked up to the microprocessor, no interrupt stuff, just the simplest of examples? as a check on the I2C stuff.

Also it looks a bit pesky setting up the control conditions.

Most curious is that did you say you have this working an another microprocessor board OK?

The loop you have, if it is just repeating, reflects that the input pin you are watching is constant. I finally got that there is ISR on the microprocessor, you just watching what the MCP23017.

The good news is that it does seem to present the average bear with some problems, meaning there's a crap ton of google stuff to comb through, always hate to throw it back to google but in the few minutes I have just now it seems like that might be worth doing.

L8R

a7

1 Like

Such use of the MCP23017 of mine that I found was very primitive.

I think step by step from the ground up is necessary. Since I did use a library, I basically have no clue about the device.

In the research I have done just now, the data sheet and this

https://www.gammon.com.au/forum/?id=10945

look like the best places to focus. I like Nick Gammon's stuff across the board, here he does use the wire library but otherwise goes to ground on the MCP23017 which I think is worth doing.

Your question about the edge is the for me so far the very most confusing thing about the chip.

Traveling along with you now, I am useless here just yet no holding your breath... I no longer eat data sheets for brekkie. :expressionless:

a7

1 Like

MIght be as simple as:

Configure interrupts as pin change.  When an interrupt comes in on a pin of interest acknowledge and decode.  If pin is read low it was a falling edge, do stuff.  If pin is high it was a rising edge, ignore.  This discounts the possibility of switch bounce.  You may need to condition the inputs to eliminate that.

Looking at the datasheet for the MCP23x17 device, it doesn't support interrupts on a specific edge (ie. rising or falling). The nearest it has is Interrupt on Change (para 3.6.2 of the datasheet):

If enabled, the MCP23X17 generates an interrupt if a mismatch condition exists between the current port value and the previous port value.

The workaround is to do as @dougp suggests to decide which edge has been detected by the MCP23x17.

1 Like

First off, I want to thank you for all your help and I hope you had a great beach trip!

This example flat out doesn't work for me (I do trust Nick Gammon though!). I changed my configuration to the schematic outlined in his post (which meant removing the 4.7k pullup resistors and the 10k for RESET, then putting a jumper between RESET and +3.3v, as well as removing the cap from the interrupt pin). The only thing that happens is that the Interrupt is triggered only when my hand is near the board (parasitic capacitance?), not when any switch is pressed! I get this reading which doesn't reflect the pins I'm using:

Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
. 1 1 . 1 1 . . . 1 1 . 1 1 . . 

I tried the following as well

with this configuration:

//RELEVANT SETUP CODE:
  pinMode(INT_PIN, INPUT);

  mcp.setupInterrupts(true, false, CHANGE);

  mcp.pinMode(BUTTON_PIN, INPUT_PULLUP);

  mcp.setupInterruptPin(BUTTON_PIN, CHANGE);

//RELEVANT LOOP CODE
  if (!digitalRead(INT_PIN))
  {
    Serial.print("INT PIN: ");
    Serial.println(digitalRead(INT_PIN));

    if (digitalRead(BUTTON_PIN) == LOW)
    {
      Serial.print("BUTTON PIN: ");
      Serial.println(digitalRead(BUTTON_PIN));
      Serial.print("Interrupt detected on pin: ");
      Serial.println(mcp.getLastInterruptPin());
      delay(250); // debounce
    }
  }

This seems to ignore the part where I want it to only print when a change is detected and the pin is low. Both interrupts read as low no matter what point in the press it is. This is what comes out of the serial monitor:

INT PIN: 0
BUTTON PIN: 0
Interrupt detected on pin: 1
INT PIN: 0
BUTTON PIN: 0
Interrupt detected on pin: 1

This reflects one LOW (press), and one HIGH (release). Note that the state is always 0 on INT PIN and BUTTON PIN.

Ha, no idea why I'm having so much trouble but it's been 4 days of head scratching!

What ever you bang your head on next, it will make no sense to do until and unless this is resolved.

If you are using the internal pull-up affordance of the MCP23017 there must be something dodgy about your wiring or other physical circumstances.

I suggest a careful examination of all you wiring, keep distances short, suspect your power supply or those leather shoes on the wool carpet &c.

I might go so far as to firmly pull up the inputs on the MCP23017 with 10K or so resistors… I am old fashioned, I know, but I always usually don’t like to use any internal pull-up, at the expense of some space and a few real resistors.

You could configure all of the i/o pins as outputs except one, or one on each branch A and B, and just do the things I suggest on those.

Or mask (I think you can) all bits but 1 or 2 so they cannot inform the interrupt signal.

Life gives and takes. This day here no sane person is at the beach. :expressionless:

a7

I needed this reminder, thank you.

HA! This did so much to help! Albeit in a roundabout way. I went back and examined the MCP23017 library (not the Adafruit one) which was the one library that did work, but I didn't use because I didn't understand that the bit masking used in the example code affected a byte which contains each pin on that port. It makes a lot more sense now.

The crucial thing for me to learn was that INTCAPA/INTCAPB need to be read and compared to the current state of the port. When the INTCAP register is read, it clears the interrupts. This was necessary in order to determine that it was the falling edge.

The library is also helping me understand how the registers work a lot better. As you suggested, I'll be going back through the other example and it will make more sense now when trying to access the chip directly without the library!

Thanks again!

Referring to your schematic, a .1µf cap from Vcc to GND on the MCP23017 is not shown.

Thank you for the decoupling reminder :slight_smile:

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