Python & CircuitPython

It's easy to use an MCP23xx I/O extender with Python or CircuitPython and the Adafruit CircuitPython MCP23xx module. This module allows you to easily write Python code to add extra digital inputs and outputs.

You can use this I/O expander with any CircuitPython microcontroller board or with a computer that has GPIO and Python thanks to Adafruit_Blinka, our CircuitPython-for-Python compatibility library.

CircuitPython Microcontroller Wiring

Connect your MCP230xx to your CircuitPython board using a standard I2C connection.

Here's an example of wiring a MCP23017 to a Feather M0 board:

Remember you need to explicitly add pull-up resistors to the I2C SCL and SDA connections as shown above!

  • Board 3.3V output to MCP23017 Vdd
  • Board ground/GND to MCP23017 Vss
  • Board SCL to MCP23017 SCL
  • Board SDA to MCP23017 SDA
  • MCP23017 SCL to 4.7 KΩ resistor connected to 3.3V
  • MCP23017 SDA to 4.7 KΩ resistor connected to 3.3V
  • MCP23017 A0 to ground
  • MCP23017 A1 to ground
  • MCP23017 A2 to ground
  • MCP23017 reset to 3.3V

When in doubt consult the MCP23017 datasheet for exact details on its pins and wiring.

Here's an example of wiring a MCP23008 to a Feather M0 board:

Remember you need to explicitly add pull-up resistors to the I2C SCL and SDA connections as shown above!

  • Board 3.3V output to MCP23008 Vdd
  • Board ground/GND to MCP23008 Vss
  • Board SCL to MCP23008 SCL
  • Board SDA to MCP23008 SDA
  • MCP23008 SCL to 4.7 KΩ resistor connected to 3.3V
  • MCP23008 SDA to 4.7 KΩ resistor connected to 3.3V
  • MCP23008 A0 to ground
  • MCP23008 A1 to ground
  • MCP23008 A2 to ground
  • MCP23008 reset to 3.3V

When in doubt consult the MCP23008 datasheet for exact details on its pins and wiring.

Python Computer Wiring

Since there's dozens of Linux computers/boards you can use we will show wiring for Raspberry Pi. For other platforms, please visit the guide for CircuitPython on Linux to see whether your platform is supported

Here's the Raspberry Pi wired to the MCP23017 with I2C:

  • Pi 3V3 output to MCP23017 Vdd
  • Pi GND to MCP23017 Vss
  • Pi SCL to MCP23017 SCL
  • Pi SDA to MCP23017 SDA
  • Pi GND to MCP23017 A0
  • Pi GND to MCP23017 A1
  • Pi GND to MCP23017 A2
  • Pi 3V3 to MCP23017 reset

Here's the Raspberry Pi wired to the MCP23008 with I2C:

  • Pi 3V3 to MCP23008 Vdd
  • Pi GND to MCP23008 Vss
  • Pi SCL to MCP23008 SCL
  • Pi SDA to MCP23008 SDA
  • Pi GND to MCP23008 A0
  • Pi GND to MCP23008 A1
  • Pi GND to MCP23008 A2
  • Pi 3V3 to MCP23008 reset

CircuitPython Installation of MCP230xx Library

You'll need to install the Adafruit CircuitPython MCP230xx library on your CircuitPython board.

First make sure you are running the latest version of Adafruit CircuitPython for your board.

Next you'll need to install the necessary libraries to use the hardware--carefully follow the steps to find and install these libraries from Adafruit's CircuitPython library bundle.  Our CircuitPython starter guide has a great page on how to install the library bundle.

For non-express boards like the Trinket M0 or Gemma M0, you'll need to manually install the necessary libraries from the bundle:

  • adafruit_mcp230xx.mpy
  • adafruit_bus_device

Before continuing make sure your board's lib folder or root filesystem has the adafruit_mcp230xx.mpy, and adafruit_bus_device files and folders copied over.

Next connect to the board's serial REPL so you are at the CircuitPython >>> prompt.

Python Installation of MCP230xx Library

You'll need to install the Adafruit_Blinka library that provides the CircuitPython support in Python. This may also require enabling I2C on your platform and verifying you are running Python 3. Since each platform is a little different, and Linux changes often, please visit the CircuitPython on Linux guide to get your computer ready!

Once that's done, from your command line run the following command:

  • sudo pip3 install adafruit-circuitpython-mcp230xx

If your default Python is version 3 you may need to run 'pip' instead. Just make sure you aren't trying to use CircuitPython on Python 2.x, it isn't supported!

CircuitPython & Python Usage

To demonstrate the usage of the device we'll initialize it and control the chip's digital I/O lines from the Python REPL.

Run the following code to import the necessary modules and initialize the I2C connection. Note that the import syntax will change depending on which MCP230xx chip you have. Here we show MCP23008:

Download: file
import board
import busio
from adafruit_mcp230xx.mcp23008 import MCP23008
i2c = busio.I2C(board.SCL, board.SDA)

For a MCP23017, the import would look like this:

Download: file
from adafruit_mcp230xx.mcp23017 import MCP23017

Then create an instance of either the MCP23017 or MCP23008 class depending on which chip you're using.  For example the MCP23017:

Download: file
mcp = MCP23017(i2c)

Or the MCP23008:

Download: file
mcp = MCP23008(i2c)

By default the chip's 0x20 I2C address will be assumed (with A0, A1, A2 all grounded). But either class initializer can also be passed an optional address keyword argument to override the I2C address, if you set any of the A0, A1, or A2 pins as described in the datasheet.   For example:

Download: file
mcp = MCP23008(i2c, address=0x24)

Next you're ready to control the GPIO ports of the chip.  This is as easy as using a DigitalInOut instance in CircuitPython, the MCP230xx library makes each chip pin look like CircuitPython DigitalInOut class.  You just need to call the get_pin function to retrieve an instance of the chip's DigitalInOut class. 

For example to create GPIO0 (or GPIOA0 on the MCP23017) as a digital output:

Download: file
pin0 = mcp.get_pin(0)
pin0.direction = Direction.OUTPUT

Then toggle the pin high or low by controlling its value property, just like using the DigitalInOut class.  Try connecting the cathode or anode of a LED to the output to see it turn on or off (or use a multimeter to measure the output voltage).

Download: file
pin0.value = True  # GPIO0 / GPIOA0 to high logic level
pin0.value = False # GPIO0 / GPIOA0 to low logic level

You can also set a pin as an input, again using the same functions and properties as the DigitalInOut class. For example here's how to create GPIO1 / GPIOA1 as a digital input with a pull-up resistor enabled:

Download: file
import digitalio
pin1 = mcp.get_pin(1)
pin1.direction = digitalio.Direction.INPUT
pin1.pull = digitalio.Pull.UP

Note that pull-down resistors are not supported by the chip.  If you need them you'll have to add external resistors yourself!

Again read the state of the input with the value property like a DigitalInOut instance.  Notice since the pull-up resistor is enabled if the pin is not connected it will read True / high logic level.  Connect the pin to ground and you'll see it read False / low logic level.

Download: file

For the MCP23008 you can get a pin instance for any pin numbered 0 to 7.  These correspond to the GPIO0 to GPIO7 pins of the chip.

For the MCP23017 you can get a pin instance for any pin numbered 0 to 15.  These correspond to the GPIOA0 to GPIOA7, then GPIOB0 to GPIOB7 pins.  For example pin 12 corresponds to GPIOB4 on the MCP23017.

That's all there is to using the MCP230xx I2C I/O extender with CircuitPython!

Below is a complete example that will blink pin 0 and read the state of pin 1 with a pull-up resistor enabled. Add a button and an LED to your setup, like in the diagram below. Save the program as on your board, then open the serial REPL to see the output.

Full Example Code

Temporarily unable to load content:
This guide was first published on Mar 08, 2018. It was last updated on Mar 08, 2018. This page (Python & CircuitPython) was last updated on Apr 04, 2020.