Not sure if this is the best way to re-open this one.
I am using trying out the MCP23017 with I2C comms to a Photon before building it into a product. I thought I would write the driver library myself and saw there were a few examples around.
The basic stuff - mcp.digitalWrite() and mcp.digitalRead() and map.pinMode() all works fine and reliably. I thought I would explore the interrupt features on the MCP23017.
I have a test rig with a button on one pin of each port and use an led output to signal which port pin has been taken HIGH.
I don’t have any capacitor on these switches to debounce.
What I have noticed is the following:
- The first time in after a power down and power on it works nicely for a while then freezes - does not respond to button presses, during this time I can receive errors from the handler (when it read the interrupt pin the value was not HIGH).
- A reset of the Photon will not clear the problem- it will go through the setup and then does not respond to button presses
I am on 0.6.0 RC2 and I have inserted and removed
SYSTEM_THREAD(ENABLED) this doesn’t seem to make a difference.
I have tried to ensure that there is very little in the interrupt handler function - this just sets a
volatile boolean with the main checks being done outside of the interrupt handler. I am wondering whether the issue is interrupt related should I put the I2C back into the interrupt handler. I wasn’t clear from the above what the advice was and whether this is now different with 0.6.0? Any Ideas?
//using the interrupt functionality
volatile boolean isAwokenByInterrupt = false;
// Two pins on the MCP (Ports A/B where some buttons have been setup
// Buttons connect the pin to ground, and pins are pulled up to 5V when button pressed
byte mcpPinA = 7;
byte mcpPinB = 8;
int flashes = 0;
while (!Serial.available()) Particle.process();
Serial.println("MCP23017 Interrupt Test V6");
// Mirror INTA and INTB, so that only one line is required between MCP and Photon for interrupt
// The INTA/B will not be Floating, INTs will be signaled with a LOW (active LOW)
mcp.pinMode(mcpPinA, INPUT); // interrupt will trigger when the pin is taken to 5V by a pushbutton
//mcp.pullUp(7, HIGH); // turn on a 100K pullup internally if button pulls pin to GND
mcp.setupInterruptPin(mcpPinA,RISING); //FALLING if pulled to GND or RISING if pulled to 5V
mcp.pinMode(mcpPinB, INPUT); // interrupt will trigger when the pin is taken to 5V by a pushbutton
//mcp.pullUp(8, HIGH); // turn on a 100K pullup internally if button pulls pin to GND
mcp.setupInterruptPin(mcpPinB,RISING); //FALLING if pulled to GND or RISING if pulled to 5V
mcp.pinMode(0, OUTPUT); // use the 0 LED as debugging
Serial.println("MCP23017 Interrupt Test - Setup completed");
flashes = 0;
Serial.println("Waiting in Loop for interrupt");
Serial.printlnf("Awoken by Interrupt A: %i B: %i", mcp.digitalRead(mcpPinA), mcp.digitalRead(mcpPinB));
if (flashes > 0) //flash LED pin 0
// The int handler will just signal that the int has happened
// This will avoid resource clash issues on separate thread
isAwokenByInterrupt = true;
// Get more information from the MCP from the INT
// We will flash the led 1 (A) or 2 (B) times depending on the PIN that triggered the Interrupt
// 3 and 4 flashes are supposed to be impossible conditions... just for debugging.
flashes = 4;
// we have to wait for the interrupt condition to finish - i.e. until all inputs are LOW
// an action is required to clear the INT flag, and allow it to trigger again.
while(!(mcp.digitalRead(mcpPinB) == LOW && mcp.digitalRead(mcpPinA) == LOW));
// and clean INT signal