To simplify using the the MCP23017 I/O Expander on the Raspberry Pi I’ve made a little plug in board using a Slice of Pi from Ciseco. The Slice of Pi is a handy little PCB that plugs directly onto the Raspberry Pi’s GPIO pins and gives a convenient row of labelled standard 0.1 inch (2.54mm) headers for the built in GPIO, SPI and I2C pins, a small prototyping area and optionally headers for plugging in an XBee style wireless devices such as the XRF, XBee, RN-XV etc. It’s not expensive at £3.90 plus postage either. (Update 27/7/12 – Ciseco are now doing an MCP23017 specific board called the Slice of PI/O, here is a comparison of the two)

I’ve fitted a 28 pin DIL socket to it for the MCP23017 and connected power and the SCL and SDA pins from the Pi as well as the required lines to switch it on and set the I2C address (fixed to 0x20). I’ve also added two sets of 0.1″ headers for the 16 I/O pins.

The result is a simple plug in expander board that can provide up to 16 inputs or outputs that can sink or source up to 25mA each, more than the 16mA of the Pi’s own GPIO pins and safer, the MCP23017 costs less than £1 and if you do accidentally blow it up and can just be popped out and a new one popped in. Along with the Python tools I’m working on I’m hoping this will be useful to help provide a simple, low cost and relatively safe way for people to experiment with connecting other hardware to the Raspberry Pi.

Here’s the layout of the board and the required connections as well as pictures of the front and back of the finished board:Note: Make sure pins 15,16,17 of the MCP23017 all connected to ground (the 3 pins top left of the diagram, shown linked in blue).

Using it

I’ve tried to make this a simple step by step guide but I didn’t take notes when doing it so it has been done from memory, please let me know if I’ve left anything out or if something isn’t clear.

To use this you will need a Raspberry Pi with the Debian Squeeze distro and a kernel that supports I2C. Update 28/7/12: If you are using the new Raspbian image this is much easier and doesn’t need a replacement kernel, see the instructions in this comment below.

You can get the source for a suitable kernel here or you can use one that I’ve already compiled by copying this kernel.img to /boot and extract this modules tar.gz file to /lib/modules/

To get the I2C device driver to load on boot you will need to edit /etc/modules and add new line containing i2c-dev. Otherwise you can do sudo modprobe i2c-dev to load it manually each time you boot the Pi.

Reboot now so that you are using the new kernel and install the i2c-tools package with:

sudo apt-get install i2c-tools

To give your regular user account permission to use the expander add it to the i2c group with:

sudo adduser your-userid i2c

and you should now be able to do i2cdetect -y 0 (use i2cdetect -y 1 if you have one of the new revision 2 Raspberry Pis with mounting holes and marked as made in the UK) and see the expander is located at address 0x20 as below:

A previous post explained how you can go on to use i2c-tools to control the MCP23017 or read on to find out how you can use the Python tools I’m working on. So far they are only working for output but I plan on extended them to cover input as well.

Command Line Tool

To use my Python command line tool you will need to install the python-smbus python module with:

Note: If you are using one of the new revision 2 Raspberry Pis you will need to change the line bus = smbus.SMBus(0) to bus = smbus.SMBus(1)

To test it connect an LED with the cathode (short leg) to ground and the anode (long leg) connected via a resistor to the port marked GPA0 in the diagram above. To calculate the resistor required for your LED see this page or if you don’t know the resistors specification a 220 Ohm resistor should be safe for a 3mm or 5mm LED.

and then try the following to make GPA0 high (ie. 5v) and turn the LED on:

./mcp23017.py -b a -o 0 -s high

you should get a response of “Output GPA0 changed to high” and the LED will turn on. To turn it off:

./mcp23017.py -b a -o 0 -s low

Web Interface:

To use the initial version of the web interface that I’m working on then you will also need the python-smbus package so if you didn’t install that above do so now:

sudo apt-get install python-smbus

next install the apache webserver:

sudo apt-get install apache2

I got an error that Apache failed to start as there is no www-data group, you can fix this with:

sudo addgroup www-data sudo adduser www-data www-data

Now install mod-wsgi with:

sudo apt-get install libapache2-mod-wsgi

enable the module with:

sudo a2enmod wsgi

and then edit /etc/apache2/sites-available/default and under the <Directory /var/www/> section add ExecCGI to the end of the Options line and before </Directory> add AddHandler wsgi-script .wsgi so it reads:

Related

66 thoughts on “Raspberry Pi I/O Expander Board”

quick question, you write there “To test it connect an LED with the cathode (short leg) to ground and the anode (long leg) connected via a resistor to the port marked GPA0” why you don’t use the 3.3V instead of the 5V, so you need no resistor for the LED?

The main reason I went with the 5v supply though is that you can only draw 50mA from the 3v3 pin on the Pi, not a lot when shared over a potential 16 outputs. The 5v pin on the other hand can supply whatever the input can less what the Pi and any peripherals are drawing, given a 1A supply this will typically leave you with around 300mA to play with. You can power the expander chip and the outputs with an external supply to get more or a different voltage but I wanted to keep it straightforward for now.

Turns out the production boards are being fitted with a 700mA polyfuse on the input so the elinux site is wrong on the current available from the 5v pin, the maximum is more likely to be in the region of 150-250mA, maybe less depending on the devices plugged into the Pi. More here.

Crikey: me a total linux innocent got it to work! I used the SK Pang starter kit and your wiring from the May 19th post.

A couple of ‘challenges’ though. First up, the ‘sudo mv’ commands in lines 3 and 5 of your linux command list did not work: suspected I needed to be in root, but had no idea what the root password was. Quick search of Pi forum (search ‘root password’) and on to the Wiki, supplied the answer: basically, the Debian distro does not have one (strange?) and you create one yourself! Created one, and as root, the mv commands were good.

Second up, bit of confusion with ‘modprobe i2c-dev’. I needed ‘sudo’ before it to get it to work. Also, if you use modprobe, when rebooting (as in your following para), ‘sudo modprobe (etc)’ needs to be typed again, otherwise you get ‘not found’ errors. Obvious? Yeah, probably, but not to me initially! (I’m still wary of manually editing system files.)

Have also noted the discussion on Pi and i2c voltages, so tried 3v3 from RPi P1-pin 1 to Vdd on the MCP23017. Worked fine, led a little less bright perhaps. Guess it would not work with a lot of leds, though.

Now onto the led chaser project and trying to figure out what’s going on in your python script (I seem to have misplaced the brain cell holding bitwise operations.) And a tutorial for i2c, and …. it’s a fun beasty, this Pi!

@Pine, Great, glad you got there and thanks for the feedback, really appreciate it. I’m guessing the error with copying the kernel over to /boot was “failed to preserve ownership”, if so it was actually copying the file but just warning that owner had been changed (to root in this case). I’ve updated the instructions to include a “chown” to explicitly change ownership to root before moving so you don’t get that (also fixes issue mentioned by Graeme above).

Have also added sudo to the modprobe command, you’re correct that you will have to do that on each boot, that’s what I meant when I said if you want to load it on boot you need to edit /etc/modules. I think I’ve clarified that a bit now too.

@Andy It shouldn’t run hot on 5v no, is there a short somewhere maybe?

Have you got pins 15,16,17 of the MCP23017 all connected to ground (the 3 pins top left in my diagram), it’s easy to miss and if they were left floating (ie. not connected) that could explain the hardware address changing I suppose.

Ah yes, pins 15,16 and 17 were floating! It now works fine on 3V3 and the chip stays cool, but it still gets extremely hot when connected to the 5V pin on the PI (all other connections were the same). I guess I will stick to using the 3V3 supply. Thanks.

Do you know of a tutorial for python-smbus or smbus itself? The man pages and python help function are not too informative. I found a web page here http://wiki.erazor-zone.de/wiki:linux:python:smbus:doc which gave a summary of the commands, and have managed to figure out the read_byte_data function – it basically seems to be:

Aval = bus.read_byte_data(0x20,0x12)

for GPA (assuming address = 0x20 and you’ve called the instance of smbus.SMBus(0) ‘bus’). For GPB change the second parameter to 0x13.

Looking at the above page, there’s an intriguing range of other commands – block read/write, word read/write etc. And how to make the interupts work? I’ve looked at the data sheet for the mcp23017 but would appreciate something a little less terse!

I don’t. I haven’t looked into in that much detail and haven’t done anything with smbus before, have just gone of what the datasheet says. Still need to find some time to get it working for inputs too.

Thanks for the update on using i2c with the new Raspian image. I downloaded and burnt the image to SD card, and then attempted to follow your guidance above. A couple of ‘challenges’, so some clarifications for my fellow linux innocenti:
1. to edit the two files (I used nano), you need to use sudo as prefix.
2. sudo apt-get install i2c-tools failed for me with error http://mirrordirector.raspian.org/ …. (etcetera) 404 not found.
Maybe the site & page was temporarily down, but the error message suggested trying ‘sudo apt-get update’ which I did, and there after ‘sudo apt-get install i2c-tools’ worked fine.
So now my led-flashing (output) and button-pressing routines (input) work fine.

From the little playing I’ve done, the Raspian distro looks to be an improvement over the original ‘wheezy’, so I’d recommend folks upgrade. It’s faster, there’s direct access from the desktop to python IDLEs and I’ve noticed less problems with missing keystrokes when typing (this was driving me mad!)

Had to larf at the comment in the raspi-blacklist.conf file, tho’ that most people won’t need i2c so we’ll blacklist it! I cannot get my head around this attitude. Wonder what else has been hidden?

Pine,
I am getting a following after a i2cdetect -y 0. I have used the raspbain image and have followed all instructions. Can you tell what you
did so I can follow your steps. I will recheck the wiring..

Hi Nathan, I’ve noticed a gotcha whic is probably prudent to mention which affects both your project and the Slice of PI / O. I constructed the dedicated board and then proceeded to test but couldn’t get it to show up using I2CDetect. Been soldering for 45 years plus so didn’t suspect my skills but didn’t re-flow each joint just in case. I noticed that I have one of the new made in UK boards (from Sony here in Wales) and whic is a revision 2 board. Remembered reading something On the pi blog, sure enough in Revision 2 boards they have swapped the Priimary and Secondary I2C channels, so for Revision 2 boards where it says a zero in the I2CDetect command in your text, this should now be a one I.e. I2CDetect -y 1

Hi Miro, No, that’s not normal, have you got pins 15,16,17 of the MCP23017 all connected to ground (the 3 pins top left of the diagram, shown linked in blue), if they aren’t connected then it could jump between different addresses.

@Rich You probably want to run the MCP23017 from an external supply for that, the amount of available current on the Pi 5V output is going to depend on what else you have plugged into it, the power supply for the Pi and the polyfuse, it’s probably somewhere between 150 and 300mA so I think 16 LEDs will be pushing it.

Miro (early Oct), sorry for delay – been busy doing Pi things! The latch button you want to make is not too difficult. There’s good articles on the basics under In Control in the MagPi on-line magazine (google it if you’ve not seen it) and issue 3 (I think) deals with button pushes and leds. You could adapt their code so that first button push sets a variable which turns an led on, then a seond push clears the variable, so the led turns off.

There is just one thing I don’t understand about this board. If the MCP23017 is powered at 5V, how can it connect to the RPi I2C pins without some form of level shifting? Nothing is mentioned about this in the writeup.

Thanks for writing this guide, it’s very helpful, though I’m having a little trouble at the end. I’ve followed the guide all the way but when I go to ip/mcp23017.wsgi I get a 500 internal server error whether I do it internally (from the pi itself using its 127.x.x.x ip) or externally (from my regular work station using a static ip assigned to the pi). Any idea where I might have forgotten something or screwed up to cause this to happen? As far as I know I’ve done everything exactly as written. It’s a rev 2 rPi if that helps.

Ok I figured it out.
I was able to fix the problem by moving the bus set to open from line 14&15 to line 75. It appears that if you try to open a bus for output on a newly initialized IC then it sets everything to low.

So I’ve just tried to do another install on a new Pi, and for some reason I’m getting a 403 error when attempting to access the ‘mcp23017.wsgi’. I’ve tried from local on the pi, and from my laptop. Been over the tutorial lots of times, so I’m just wondering if something has changed in a newer apache release? Any help would be really appreciated!

Thanks to all for help. I have a MyPi – Protect Your Pi – 32 I/O Point Expansion & GPIO Shield Board (https://www.modmypi.com/raspberry-pi-expansion-boards/protect-your-pi ) that is not exact the same of the example but I could read and control it with raspberry B+ that have also a different Gpio connector. I used the nathan test program mcp23017.py and the messages are ok. But I have a power problem. I don’t have 3,3volts on the interface and no led power on. Is the interface to power in some way over the gpio connection? Can I give a supplimentary power to the interface? Thanks for help.

I am getting an issue with the MCP23017 output levels. Basically its being driven by 5v, and the GPIO high is about 4.7v, but GPIO low is about 0.6v. I am trying to trigger a relay which requires <0.5v to trigger.