Using interrupts on MCP23S08 to read an encoder

Hello,

I want to read multiple encoders using Arduino, so I have decided to use the SPI MCP23S08 IO expander to do so. I can generate an interrupt on one of the pins such as GPIO0 but I don’t know how to write the “Interrupt Service Routine” so that when an interrupt occurs on that pin, I run a function. The following code shows my pin configuration. Should I use “attachinterrupt” command? I don’t want to use the interrupt pins on the Arduino, that is why I don’t know if I should use “attachinterrupt” command or not?

#include <SPI.h>

#define IODIR 0x00
#define IPOL 0x01
#define GPINTEN 0x02
#define DEFVAL 0x03
#define INTCON 0x04
#define IOCON 0x05
#define GPPU 0x06
#define INTF 0x07
#define INTCAP 0x08
#define GPIO 0x09
#define OLAT 0x0A

const int chipSelect = 10;

void setup() {
  // initialize SPI:
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV16);

  pinMode(chipSelect, OUTPUT);
  pinMode(led, OUTPUT);

  // set the chipSelect as an output:
  digitalWrite(chipSelect, HIGH);
  digitalWrite(led, LOW);


  sendCommand(IODIR, 0x0F); //00001111 first 4 are inputs

  sendCommand(GPINTEN, 0x01);  //GPIO0 is set for interrupt on change
  sendCommand(DEFVAL, 0x00);  //Default value is 0
  sendCommand(INTCON, 0x01);  //GPIO0 is compared with Default value for interrupt
  sendCommand(GPIO, 0x00);

    
  Serial.begin(9600);

}


void sendCommand(int address, int data) {
  digitalWrite(chipSelect, LOW);
  delay(1);

  // SPI addressing 0x40 with A0 and A1 set to ground and R/W bit set to output
  SPI.transfer(0x40);
  SPI.transfer(address);
  SPI.transfer(data);
  delay(1);

  // take the chipSelect pin high to de-select the chip:
  digitalWrite(chipSelect, HIGH);
}

byte getCommand(int address) {

  byte result = 0;
  digitalWrite(chipSelect, LOW);
  delay(1);
  // SPI addressing 0x40 with A0 and A1 set to ground and R/W bit set to read
  SPI.transfer(0x41);
  SPI.transfer(address);
  result = SPI.transfer(0);
  delay(1);

  // take the chipSelect pin high to de-select the chip:
  digitalWrite(chipSelect, HIGH);

  return result;
}

void loop() {
  

}

Here’s the code I use to read encoders with the 16-bit I2C version of that chip. It shouldn’t be too hard to make it use SPI and read only 8 bits.
MCP23017Encoders.hpp

The advantage of SPI over I2C is that you can use it from within an ISR. Be sure to use SPI transactions, though.

You have to use the LOW interrupt mode, and you have to enable interrupt safely using the template argument, as shown in the example:
MCP23017-Encoders-Interrupts.ino

Pieter