There are numerous python libraries out there for the 16 port MCP23017 GPIO expander chip that works with the Raspberry Pi, so why yet another one? None of the ones I could find actually implement interrupts via the chip Polling is not ideal for my home monitoring setup. I was already monitoring via interrupts and the onboard GPIO pins using the awesome RPIO module and wanted to continue using interrupts with the expansion chip. So I built my own module, leveraging Adafruit’s I2C library for the nitty gritty backend interface.
- Simple digital input and output via all pins
- Input interrupts
- Interrupt port mirroring is configurable – either INTA and INTB can trigger independently for their respective GPIO port banks, or both INTA and INTB can trigger at the same time regardless of what GPIO pin causes the interrupt
- Configurable interrupt polarity – INT could pull the pin high or push it low
- Each GPIO pin can be configured for interrupts independently to either compare against the previous value or against a default pin value
- A utility method cleanupInterrupts that can be called periodically to clear the interrupt if it somehow gets stuck on
You can find the library on my BitBucket.
Stick around after the break for a breakdown of how to use it.
First, this is a python 3 library, so you’ll need to get python 3 installed.
Second, you’ll need to python 3 smbus python module installed. As of this writing, there is no prebuilt package for python 3 smbus, however, cobbling together various instructions I came across, I assembled this process that works to install a python 3 compatible smbus module: https://bitbucket.org/dewoodruff/mcp23017-python-3-library-with-interrupts/wiki/smbus%20python%203
Lastly, you’ll need a python 3 port of Adafruit’s I2C library, which I have included as part of the BitBucket repository. Note that this chip is available in both I2C and SPI interfaces – my library uses I2C.
Wiring up the chip
For ease, I went with the Slice Of Pi/O breakout board for this chip which already has the header to connect to the Pi and does not block the other pins that aren’t used by the MCP23017. Here is the site with assembly instructions: http://openmicros.org/index.php/articles/94-ciseco-product-documentation/raspberry-pi/223-slice-of-pio. I purchased mine on eBay from a US seller but they are available from several resellers.
Once you’ve assembled the Slice of Pi/O, plug it into the Pi and configure I2C on the Pi. Adafruit once again to the rescue with a simple tutorial to get I2C configured: https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-i2c
By default, the Slice of Pi/O puts the MCP23017 on the 0x20 address. If you have multiple I2C devices, you will need to solder the jumpers on the bottom of the board to change the address – details are at the assembly instructions link above.
Now, to use interrupts from the expander, you need to use at least one of the onboard Pi GPIO pins to monitor for when an interrupt occurs. I’ve wired mine up to onboard port 4 using a 12K ohm resistor to INTB on the expander as seen in the picture below. I’m using interrupt pin mirroring so I only need one of the ports wired up. Note, you really need to use a resistor to keep the current flow between the two ports low to avoid damage – 10 or 12K will work fine.
Interrupt port mirroring means that if an interrupt appears on any of the 16 ports, both INT ports will trigger at the same time. Alternatively, the library can configure the chip so an interrupt on the first 8 ports would trigger INTA and the second 8 ports would trigger INTB.
I have several functioning examples for using this chip the examples directory on BitBucket:
- basicinput.py reads input via polling
- blinky.py blinks 6 connected LEDS randomly
- interrupttest.py is a complete example implementing interrupts
- singleblink.py blinks a single LED
That is it! I hope others find this useful. If you have improvements or bug fixes, please submit a pull request!