MCP23017 Interrupt Reset Issues

Status
Not open for further replies.

APutz

Member
In my project I have an MCP23017 connected via i2c to a teensy 3.2 that is also wired up to receive interrupts from the mcp to pins 8 and 2 on the teensy. As per the (Adafruit library )library I have both banks of 8 i/o pins setup with separate interrupts so i can tell which bank the change occurred in. On both interrupt lines i have wired an LED so I can monitor the activity. Sometimes the interrupt signal coming from the mcp works. I can see the LEDs trigger and then quickly reset when the teensy handles the interrupt. Sometimes this is not the case and the interrupt from the mcp never resets the interrupt pin as indicated by the LED still being on. I am somewhat new to Working with interrupts and setting registers so sorry if this is an obvious question. When I power cycle the teensy and mcp the interrupt on the mcp usually wont reset. It isnt until I load another project onto the teensy that it sometimes resets the flag. Once I reprogram the teensy with this code, everything seems to work fine until I hit a button thats attached to the mcp and triggers an interrupt, which it sets its int pin high, only to never been registered by the teensy, and therefor wont reset? Am I missing something? seems like this should be pretty straight forward. Thanks!

#include <Adafruit_MCP23017.h>
#include <Adafruit_LiquidCrystal.h>
#include <Wire.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define led0 9
#define led1 11
#define led2 13
#define led3 15

#define button0 8
#define button1 10
#define button2 12
#define button3 14

#define knob0 2
#define knob1 3
#define knob2 6
#define knob3 7

#define encAPin 0
#define encBPin 1
#define encButton 2

#define intAPin 8
#define intBPin 2

void ledUpdate();
void intAHandler();
void intBHandler();

Adafruit_MCP23017 mcp;
Adafruit_LiquidCrystal lcd(0);

volatile int intACount = 0;
volatile int intBCount = 0;

void setup() {

pinMode(intAPin, INPUT);
pinMode(intBPin, INPUT);

mcp.begin(1);
mcp.pinMode(led0, OUTPUT);
mcp.pinMode(led1, OUTPUT);
mcp.pinMode(led2, OUTPUT);
mcp.pinMode(led3, OUTPUT);

mcp.pinMode(encAPin, INPUT);
mcp.pinMode(encBPin, INPUT);
mcp.pinMode(encButton, INPUT);

mcp.digitalWrite(led0, LOW);
mcp.digitalWrite(led1, LOW);
mcp.digitalWrite(led2, LOW);
mcp.digitalWrite(led3, LOW);

mcp.setupInterrupts(false,false,HIGH);
mcp.setupInterruptPin(button0,CHANGE);
mcp.setupInterruptPin(button1,CHANGE);
mcp.setupInterruptPin(button2,CHANGE);
mcp.setupInterruptPin(button3,CHANGE);

mcp.setupInterruptPin(encAPin,CHANGE);
mcp.setupInterruptPin(encBPin,CHANGE);
mcp.setupInterruptPin(encButton,CHANGE);

attachInterrupt(intAPin, intAHandler, HIGH);
attachInterrupt(intBPin, intBHandler, HIGH);

lcd.begin(16, 2);
lcd.clear();
lcd.setBacklight(HIGH);
lcd.print("CLEAR");
delay(1000);
lcd.clear();

}

void loop() {

ledUpdate();

lcd.setCursor(0,0);
lcd.print(digitalRead(intAPin));
lcd.setCursor(1,0);
lcd.print(digitalRead(intBPin));

lcd.setCursor(8,0);
lcd.print(mcp.digitalRead(encAPin));
lcd.print(mcp.digitalRead(encBPin));
lcd.print(mcp.digitalRead(encButton));

lcd.setCursor(0,1);
lcd.print(intACount);
lcd.setCursor(8,1);
lcd.print(intBCount);

}


//////////////////////////////////////////////////////////////////////


void ledUpdate(){

if(mcp.digitalRead(button0) == HIGH){
mcp.digitalWrite(led0, HIGH);
}

if(mcp.digitalRead(button0) == LOW){
mcp.digitalWrite(led0, LOW);
}

if(mcp.digitalRead(button1) == HIGH){
mcp.digitalWrite(led1, HIGH);
}

if(mcp.digitalRead(button1) == LOW){
mcp.digitalWrite(led1, LOW);
}

if(mcp.digitalRead(button2) == HIGH){
mcp.digitalWrite(led2, HIGH);
}

if(mcp.digitalRead(button2) == LOW){
mcp.digitalWrite(led2, LOW);
}

if(mcp.digitalRead(button3) == HIGH){
mcp.digitalWrite(led3, HIGH);
}

if(mcp.digitalRead(button3) == LOW){
mcp.digitalWrite(led3, LOW);
}

}

void intAHandler(){

cli();
intACount++;
sei()
}

void intBHandler(){

cli();
intBCount++;
sei();
}
 
Last edited:
did you tie the reset pin of the mcp23017 high? alot of people forget that. i dont use interrupts with my 5x mcp23017 and 8xmcp23s17's, im polling them fine 24/7. alot less wires and alot less code as well.
 
Sorry, hopefully some one who uses these may have a more complete answer. I did a quick look at the pdf file up on Adafruit (section 1.7.5) and it made me wonder if maybe, once you get an interrupt, you need to read something to reset the interrupt, like either the GPIO pin or the INTCAP?
 
Well I was hoping to differentiate between a long (hold) and a short press in my design. I am sure there is a better way of doing it, but this was my first theory of how to differentiate the two. You believe this will cause problems?

I have substituted CHANGE for HIGH in my code with no change to the problem. When I load this code my mcp's interrupts function as intended.

#include <Adafruit_MCP23017.h>
#include <Adafruit_LiquidCrystal.h>
#include <Wire.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define led0 9
#define led1 11
#define led2 13
#define led3 15

#define button0 8
#define button1 10
#define button2 12
#define button3 14

#define knob0 2
#define knob1 3
#define knob2 6
#define knob3 7

#define encAPin 0
#define encBPin 1
#define encButton 2

#define intAPin 8
#define intBPin 2

void ledUpdate();

Adafruit_MCP23017 mcp;
Adafruit_LiquidCrystal lcd(0);

void setup() {

pinMode(intAPin, INPUT);
pinMode(intBPin, INPUT);

mcp.begin(1);
mcp.pinMode(led0, OUTPUT);
mcp.pinMode(led1, OUTPUT);
mcp.pinMode(led2, OUTPUT);
mcp.pinMode(led3, OUTPUT);

mcp.pinMode(encAPin, INPUT);
mcp.pinMode(encBPin, INPUT);
mcp.pinMode(encButton, INPUT);

mcp.digitalWrite(led0, LOW);
mcp.digitalWrite(led1, LOW);
mcp.digitalWrite(led2, LOW);
mcp.digitalWrite(led3, LOW);

mcp.setupInterrupts(false,false,HIGH);
mcp.setupInterruptPin(button0,HIGH);
mcp.setupInterruptPin(button1,HIGH);
mcp.setupInterruptPin(button2,HIGH);
mcp.setupInterruptPin(button3,HIGH);

mcp.setupInterruptPin(encAPin,LOW);
mcp.setupInterruptPin(encBPin,LOW);
mcp.setupInterruptPin(encButton,HIGH);

lcd.begin(16, 2);
lcd.clear();
lcd.setBacklight(HIGH);
lcd.print("MCP23017_ISR_Test");
delay(1000);
lcd.clear();

}

void loop() {

ledUpdate();

lcd.setCursor(0,0);
lcd.print(digitalRead(intAPin));
lcd.setCursor(1,0);
lcd.print(digitalRead(intBPin));

lcd.setCursor(8,0);
lcd.print(mcp.digitalRead(encAPin));
lcd.print(mcp.digitalRead(encBPin));
lcd.print(mcp.digitalRead(encButton));

}


//////////////////////////////////////////////////////////////////////


void ledUpdate(){

if(mcp.digitalRead(button0) == HIGH){
mcp.digitalWrite(led0, HIGH);
}

if(mcp.digitalRead(button0) == LOW){
mcp.digitalWrite(led0, LOW);
}

if(mcp.digitalRead(button1) == HIGH){
mcp.digitalWrite(led1, HIGH);
}

if(mcp.digitalRead(button1) == LOW){
mcp.digitalWrite(led1, LOW);
}

if(mcp.digitalRead(button2) == HIGH){
mcp.digitalWrite(led2, HIGH);
}

if(mcp.digitalRead(button2) == LOW){
mcp.digitalWrite(led2, LOW);
}

if(mcp.digitalRead(button3) == HIGH){
mcp.digitalWrite(led3, HIGH);
}

if(mcp.digitalRead(button3) == LOW){
mcp.digitalWrite(led3, LOW);
}

}
 
Yes, I tied reset to HIGH.

KURT, Yes I agree, It definitely feel like the flag isnt being reset once its triggered by the mcp. and since my variable intACount isnt ever increasing from the ISR i am guessing the teensy never realizes the interrupt was ever activated, let alone reset after my variable was incremented.
 
you need to look at the mcp23017 datasheet, Kurt is right and the interrupt register is one of issues people face as you need to read the registers for it to clear, and potentially have to edit the IOCON registers properly.
 
That was the feeling I was getting. I am relatively new to understanding registers and am not entirely sure how to write to one. I understand how they function and just need an example in code if someone could help? It looks like there is already a function writeRegister in the library. Maybe that needs to be made public? How do you think the library is editing the registers incorrectly?
 
thats something that should be asked on adafruit's forum, however, for a port expander, you can also read/write the registers without a library as well using Wire.
 
Hello APutz.
I would appreciate if you update what you find here.
I know doing a .readGPIOAB() clears the mcp interrupt and is what I've been doing.
 
Status
Not open for further replies.
Back
Top