I/O Expander

I/O Expander


In this page, we will talk about the MCP23008 I/O Expander IC. This IC is used to expand the available number of I/O pins. It also has a number of features that allow us to configure how pins, when set to input, react and otherwise behave.


Figure 1. MCP23008 pinout.

  • SCL: This pin is the clock line for I2C.
  • SDA: This pin is the data line for I2C.
  • A2, A1, A0: These pins are used to configure the last three bits of the device's slave address. This allows 8 different MCP23008 ICs to exist on the same network without conflict.
  • RESET: This pin resets the MCP23008 by setting the registers back to their defaults.
  • INT: This pin is used to signal that the I/O expander has had an interrupt triggered by one of its input pins.
  • VSS: This pin should be connected to ground.
  • GP 0-7: These pins are the general purpose I/O pins. They can be configured to be input or output.
  • VDD: This pin should be connected to the voltage supply.


Most of these registers have a one-to-one mapping of bit position to GP pin. So unless mentioned otherwise, assume that bit position 0 effects GP0, bit 1 effects GP1, and so on.

  • IODIR: This register sets the direction of the GP pins to either input or output.
  • IPOL: This register sets whether or not the logic state of the input pin is the same or opposite of the logic of that pin. In other words, if the input pin is HIGH and the corresponding bit in IPOL is 1, reading that pin will give you LOW, since it is the opposite of HIGH.
  • GPINTEN: This register enables or disables interrupt-on-change events for the pins. So if a pin is set as input and its logic level changes from LOW to HIGH or from HIGH to LOW, an interrupt is triggered (what happens when an interrupt is triggered and how to clear it is covered below).
  • DEFVAL: This register, when GPINTEN and INTCON are configured correctly, will trigger an interrupt whenever the input pin is the opposite value of DEFVAL. That is, if DEFVAL is 0 for pin 0, and pin 0 becomes HIGH, then interrupts will be triggered until pin 0 goes back LOW.
  • INTCON: This register sets whether a pin generates an interrupt based on DEFVAL or its previous value (interrupt on change). The pin uses its previous value if the corresponding bit position is set to 0, and it uses DEFVAL if the corresponding bit position is set to 1.
  • IOCON: This register is different from the others since it configures the overall operation rather than just how a pin acts. Bit 5 enables or disables sequential operation (SEQOP), which increments the address pointer (points at one of the registers) every time a byte is transferred (either read or write). Bit 4 enables or disables the slew rate (DISSLW). If enabled, the SDA slew rate is controlled when driving from a HIGH to a LOW. Bit 3 is not used on the MCP23008, but is used on the MCP23S08, which is the SPI version of this chip. Bit 2 is the open-drain control bit (ODR) which enables or disables the INT pin for open-drain configuration. Bit 1 is the interrupt polarity control bit (INTPOL), which sets the polarity of the INT pin. If ODR is set, then this bit is not functional.
  • GPPU: This register is used to enable or disable internal pull-up resisters (100 kΩ). This only affects the pin if it is configured as an input.
  • INTF: This register tracks which pins have triggered an interrupt. A set bit indicates that an interrupt was triggered by the corresponding pin. This register is also read-only, so any attempted writes to it will be ignored.
  • INTCAP: This register captures the GPIO value of the pin that triggers an interrupt. This register is also read-only. Interrupts are cleared by reading this register or the GPIO register.
  • GPIO: This register is the general interface to the IO pins. Reading this register gives the current state of the GP pins. Writing to this port modifies the OLAT register which sets the GP pin set to OUTPUT.
  • OLAT: This register provides access to the output latches. Any writes to this register will modify any pins configured as OUTPUTs. A read from this register will only reflect OLAT and not the port itself.

Register Defaults

When the I/O expander is powered on for the first time or is reset, the registers are set to their default values. For all but one register, the default value is 0 for all the bits. The one register that is different is the IODIR register, which is defaulted to all bits set to 1. This means that all the pins are set to inputs on reset.

Interrupt Logic

Interrupts are configured by 4 registers:

  1. GPINTEN: Enables interrupts on individual pins.
  2. DEFVAL: Holds a value to compare against the associated input values.
  3. INTCON: Controls whether an interrupt is triggered by using DEFVAL or by the previous value on the port.
  4. IOCON: Configures the INT output pin as push-pull, open-drain, or active-level.

Of course, only pins set as inputs and enabled by GPINTEN will cause interrupts. When an interrupt is triggered, the value of the port is stored in INTCAP. The first interrupt copies the value of the port register to INTCAP, until the original interrupt is cleared (by reading INTCAP or GPIO), any other interrupt events are effectively ignored.

An interrupt is triggered one of two ways depending on how the I/O expander is configured. Using default configuration values, an interrupt is triggered when a pin changes logic state. So in the case of a button press, two interrupts will be triggered; one from when the button is pressed and the second from when the button is released. When configured to use DEFVAL, an interrupt is triggered whenever the input pin is opposite of the DEFVAL value for that pin. Even when the interrupt is cleared, if the input pin is still opposite of DEFVAL, another interrupt will be triggered.

  • Other product and company names mentioned herein are trademarks or trade names of their respective companies. © 2014 Digilent Inc. All rights reserved.