Arduino Leonardo MCP23017 and Rotary Encoder

Good moring
I've been working on a joystick setup for a while - for the most part I can get everything to work except the PEC11 Rotary Encoder on the DFRobot MCP23017. The Rotary encoder works fine if attached directly to the Leonardo - but I am struggling to understand how to get it to work on the expansion card.

I began to think its was a hardware issue so I have tried all new hardware, it wasn't that.

So using the 'ioInterrupt' example from the DFRobot_MCP23017 library I am still having issues. As I understand it, with a device attached to both INTA and INTB should prompt a serial print out when an interrupt is detected ? It 's only showing an interrupt on INTB, and without me actually having to rotate the encoder. Even if I remove the wire from INTB so only INTA is connected there is no shown output for INTA.

I know I'm missing something, below the code directly from the expample, any constructive pointers very welcome, many thanks.

/*!
 * @file ioInterrupt.ino
 * @brief IO interrupt, set a pin of a port group(A or B) IO to interrupt mode. When an interrupt occurs on the related port group,
 * @n pin INTA(group A) or INTB(group B) will output a High level.
 * @n INTA and INTB are used to detect if an interrupt occurs on the pin of port eGPA and eGPB respectively; connect pin INTA and INTB 
 * @n to main-controller's external interrupt 0 and 1 respectively.
 * @n Experiment phenomenon: when the signal change of pin INTA or INTB is detected by main-board, the related interrupt service
 * @n function will be executed to print out which pin was interrupted on serial port.
 *
 * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
 * @license     The MIT License (MIT)
 * @author [Arya](xue.peng@dfrobot.com)
 * @version  V1.0
 * @date  2019-07-18
 * @url https://github.com/DFRobot/DFRobot_MCP23017
 */

#include <DFRobot_MCP23017.h>
/*DFRobot_MCP23017 constructor
 *Parameter &wire Wire
 *Parameter addr  I2C address can be selected from 0x20~0x27; the relationship of the DIP switch(A2, A1, A0) and I2C address(0x27) 
 *is shown below: 
  * 0  0  1  0  | 0  A2 A1 A0
    0  0  1  0  | 0  1  1  1    0x27
    0  0  1  0  | 0  1  1  0    0x26
    0  0  1  0  | 0  1  0  1    0x25
    0  0  1  0  | 0  1  0  0    0x24
    0  0  1  0  | 0  0  1  1    0x23
    0  0  1  0  | 0  0  1  0    0x22
    0  0  1  0  | 0  0  0  1    0x21
    0  0  1  0  | 0  0  0  0    0x20
 */
DFRobot_MCP23017 mcp(Wire, /*addr =*/0x27);  //constructor, change the Level of A2, A1, A0 via DIP switch to revise I2C address within 0x20~0x27.
//DFRobot_MCP23017 mcp;//use default parameter, Wire  0x27(default I2C address)

//Connect 2 buttons to IO expansion board, one to a pin of port eGPA(eg: eGPA0), the other to a pin of port eGPB(eg: eGPB0)
//Connect INTA to the external interrupt pin0 of UNO, INTB to external interrupt pin1 of UNO.

bool intFlagA = false;  //INTA interrupt sign
bool intFlagB = false;  //INTB interrupt sign

/*Interrupt service function, prototype void func(int index), index represents the pin which is interrupted*/
void gpa0CB(int index) {
  /*pinDescription function is used to convert a pin into string description
  Parameter pin, the available parameter is shown below:
  eGPA0  eGPA1  eGPA2  eGPA3  eGPA4  eGPA5  eGPA6  eGPA7  eGPA
   0       1      2      3      4      5      6      7
  eGPB0  eGPB1  eGPB2  eGPB3  eGPB4  eGPB5  eGPB6  eGPB7  eGPB
   8       9      10     11     12     13     14     15
  */
  String description = mcp.pinDescription(index);
  Serial.print(description);
  Serial.println(" Interruption occurs!");
}

void gpb7CB(int index) {
  String description = mcp.pinDescription(index);
  Serial.print(description);
  Serial.println(" Interruption occurs!");
}

void setup() {
  Serial.begin(115200);
#ifdef ARDUINO_ARCH_MPYTHON
  pinMode(P0, INPUT);  //use mPython external interrupt, connect INTA to pin 0 of mPython.
  pinMode(P1, INPUT);  //use mPython external interrupt, connect INTB to pin 1 of mPython.
#else
  pinMode(2, INPUT);  //use UNO external interrupt 0
  pinMode(3, INPUT);  //use UNO external interrupt 1
#endif

  /*wait for the chip to be initialized completely, and then exit*/
  while (mcp.begin() != 0) {
    Serial.println("Initialization of the chip failed, please confirm that the chip connection is correct!");
    delay(1000);
  }
  /*pinModeInterrupt function is used to set pin to interrupt mode, and the pin will be automatically set to input mode.
  Parameter pin, the available parameter is showm below:
  eGPA0  eGPA1  eGPA2  eGPA3  eGPA4  eGPA5  eGPA6  eGPA7  eGPA
   0       1      2      3      4      5      6      7
  eGPB0  eGPB1  eGPB2  eGPB3  eGPB4  eGPB5  eGPB6  eGPB7  eGPB
   8       9      10     11     12     13     14     15
  Parameter mode, the available parameter is shown below:
  eLowLevel              eHighLevel              eRising                eFalling                  eChangeLevel
  Low-level interrupt    High-level interrupt    Rising edge interrupt  Falling edge interrupt    Double edge interrupts 
  Parameter cb interrupt service function(with parameter)
  Prototype void func(int)
  */
  mcp.pinModeInterrupt(/*pin = */ mcp.eGPA0, /*mode = */ mcp.eHighLevel, /*cb = */ gpa0CB);    //digital pin 0(eGPA0), interrupt in High level. Generate an interrupt when pin 0 is in High level state.INTA output High level.
  mcp.pinModeInterrupt(/*pin = */ mcp.eGPB7, /*mode = */ mcp.eChangeLevel, /*cb = */ gpb7CB);  //digital pin 15(eGPB7), double edge interrupts. Generate an interrupt when the status of Pin 15 changes. INTB output High level.

#ifdef ARDUINO_ARCH_MPYTHON  //
  /* mPython Interrupt Pin vs Interrupt NO
   * -------------------------------------------------------------------------------------
   * |                    |  DigitalPin  |        P0~P20 can be used as external interrupt|
   * |    mPython           |--------------------------------------------------------------|
   * |                    | Interrupt No |  use digitalPinToInterrupt(Pn) to query interrupt number     |
   * |-----------------------------------------------------------------------------------|
   */
  attachInterrupt(digitalPinToInterrupt(P0) /*query Interrupt NO of P0*/, notifyA, RISING);  //Enable the external interrupt of mPython P0; rising edge trigger; connect INTA to P0
  attachInterrupt(digitalPinToInterrupt(P1) /*query Interrupt NO of P1*/, notifyB, RISING);  //Enable the external interrupt of mPython P1; rising edge trigger; connect INTB to P1
#else
  /* Main-board of AVR series    Interrupt Pin vs Interrupt NO
   * ---------------------------------------------------------------------------------------
   * |                                        |  DigitalPin  | 2  | 3  |                   |
   * |    Uno, Nano, Mini, other 328-based    |--------------------------------------------|
   * |                                        | Interrupt No | 0  | 1  |                   |
   * |-------------------------------------------------------------------------------------|
   * |                                        |    Pin       | 2  | 3  | 21 | 20 | 19 | 18 |
   * |               Mega2560                 |--------------------------------------------|
   * |                                        | Interrupt No | 0  | 1  | 2  | 3  | 4  | 5  |
   * |-------------------------------------------------------------------------------------|
   * |                                        |    Pin       | 3  | 2  | 0  | 1  | 7  |    |
   * |    Leonardo, other 32u4-based          |--------------------------------------------|
   * |                                        | Interrupt No | 0  | 1  | 2  | 3  | 4  |    |
   * |--------------------------------------------------------------------------------------
   */
  /* microbit  Interrupt Pin vs Interrupt NO
   * ---------------------------------------------------------------------------------------------------------------
   * |                                                   |  DigitalPin  |    P0~P20 can be used as external interrupt           |
   * |                  microbit                         |---------------------------------------------------------|
   * |(when used as external interrupt, do not need to set it to input mode via pinMode)  | Interrupt No | Interrupt NO is pin value, for instance, the Interrupt NO of P0 is 0, P1 is 1. |
   * |-------------------------------------------------------------------------------------------------------------|
   */
  attachInterrupt(/*Interrupt NO*/ 0, notifyA, RISING);  //Enable external interrupt 0, connect INTA to the main-controller's digital pin: UNO(2),Mega2560(2),Leonardo(3),microbit(P0)
  attachInterrupt(/*Interrupt NO*/ 1, notifyB, RISING);  //Enable external interrupt 1, connect INTB to the main-controller's digital pin: UNO(3),Mega2560(3),Leonardo(2),microbit(P1)
#endif
}
/*Interrupt service function*/
void notifyA() {
  intFlagA = true;
}
void notifyB() {
  intFlagB = true;
}

void loop() {
  if (intFlagA) {
    intFlagA = false;
    /*pollInterrupts function is used to poll if an interrupt occurs on a port group 
    parameter group, the available parameter is shown below: (default value: eGPIOALL):
     eGPIOA        eGPIOB         eGPIOALL
     Port groupA  Port groupB   Port groupA+B
    */
    mcp.pollInterrupts(/*group = */ mcp.eGPIOA);
  }
  if (intFlagB) {
    intFlagB = false;
    mcp.pollInterrupts(/*group = */ mcp.eGPIOB);
  }
}

Please post the technical manual for that bord and proper schematics of the build.

Your circuit is very wrong. All that rotary encoder is doing is changing the I2C address of the MCP23017.

Please look at the data sheet for the MCP23017, and look at the registers inside it. Especially the INTERRUPT CAPTURED REGISTER.

Your understanding is not correct.

What they do is to alert you the fact that something has changed in the chip. This simple thing allows you to simply monitor these pins, so you can go into the chip's registers and look at what has changed.

They do not, of themselves, generate any interrupt. If you write code so that it does then that interrupt code must go into the chip and clear the interrupting pins. Note that both INTA and INTB are what are called open collector signals and so need a common pull up resistor, if connected together.

Thank you Grumpy_Mike - now I have something to focus on. I didn't / don't understand the code, so couldn't understand what was happening. Now I have a lead, so again, much gratitude!

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