I had a quick play with the I2C drivers that are currently being developed for the Raspberry Pi this afternoon and managed to get a MCP23017 16-bit I/O Expander working with it without any fuss.
Here is a highly exciting video of it blinking an LED:
The MCP23017 is a handy 28 pin chip that gives you 16 pins that can be used as either inputs or outputs (max 25mA from each pin) and up to 8 of the MCP23017 can be used on one I2C bus so it can give you a whole lot more I/O than the Pi has built in as well as reducing the risk of frying the Pi and also has the added advantage that the expander can be located away from the Pi linked with only four wires. There is also the smaller MCP23008 which is an 8 I/O version that can be used in the same way. They are both available in DIP form making it easy for building your own boards with and experimenting on breadboard. Here is the datasheet for the MCP23017.
Read on for some info on what is required to get this working.
Connecting it up
For a quick demo the following needs to be connected on the expander:
Pin 9 to Vcc (eg. 5V on the Pi or external source up to 5.5V)
Pin 10 to Ground
Pin 12 to SCL0 on the Pi
Pin 13 to SDA0 on the Pi
Pins 15,16,17 to ground (this selects the I2C address as 0x20, other combinations can set different addresses)
Pin 18 to Vcc (this turns the expander on)
For the location of the I2C and power pins on the Pi see the diagram here. Note that the maximum you can draw from the 5V pin on the Pi will be the USB input current, typically 1A less the draw of the Pi itself, around 700mA for the Model B so that leaves us with around 300mA max. the maximum you can draw from the 5v pin on the Pi is in the region of 150-250mA, maybe less depending on the devices plugged into the Pi, more here.
For this test I also connected an LED and resistor between GPA0 on the MCP23017 (pin 21) and ground.
Drivers and i2c-tools
See this thread on the Raspberry Pi forums for the current work that is being done on i2c drivers for the Raspberry Pi, it’s still very much in the early development stages. There is the original bitbanging one (slower) and the new faster hardware one, to take a short cut for now you can just download the pre-compiled kernel with the I2C bitbanging driver built in here and simply swap it with the one in /boot on the Debian Squeeze distro and reboot.
Then you will want to install i2c-tools package via apt-get, this gives us some command line tools for scanning the I2C bus and sending values to I2C addresses and registers.
Now we can check that the Pi is communicating with the expander by doing: i2cdetect -y 0
If it is working you should see an ASCII representation of a table with 20 in the first column on the row marked 20. This signifies there is something there with an I2C address of 0x20 as expected.
Controlling the expander
The I/O pins on the MCP23017 are in two banks, A and B and each bank is controlled together. To set whether each pin is an input or an output we need to send a hex value to the correct register (see Table 1.4 in the data sheet). IODIRA (0x00) sets the input/output state for bank A and IODIRB (0x01) for bank B, set each of the 8 bits as 1 for input (the default) and 0 for output. eg. to set pins 0, 1, 7 as input and the rest as outputs it would be 10000011 in binary or 0x83 in hex, to set a whole bank as outputs would be 0x00.
Then to turn each pin on or off we send a hex value to the register for the relevant bank, 0x12 for bank A, 0x13 for bank B. We need to send a 1 to each bit we want on and a 0 for each we want to turn off in the same manner as above, so to turn pin 0 on it’s 00000001 in binary or 0x01 in hex.
For a quick demo we can use the i2cset command that comes with i2c-tools, its format is:
i2cset i2-cbus i2c-address i2c-register value
Set all of bank A to be outputs: i2cset -y 0 0x20 0x00 0x00
Set GPA0 as on: i2cset -y 0 0x20 0x12 0x01
Set GPA0 as off: i2cset -y 0 0x20 0x12 0x00
The -y switch just turns interactive mode off so it doesn’t ask for confirmation.
Here is a simple bash script to blink it 20 times:
i2cset -y 0 0x20 0x00 0x00
until [ $COUNTER -lt 10 ]; do
i2cset -y 0 0x20 0x12 0x01
i2cset -y 0 0x20 0x12 0x00
So there you go, a quick demo of an I2C I/O expander working on the Pi. Next I need to get set up for cross compiling and try the new hardware driver and look at how to use I2C in something a bit more advanced than bash.
UPDATE 20/5/12: I’ve got the 3.2 kernel with hardware I2C driver from here working now. One thing to note is that the 3.2 kernels seem to have some issues working with SD cards that worked fine under 3.1 The 32GB Verbatim Class 6 card I had been using was throwing “mmc0: problem reading SD Status register” and “error -110 whilst initialising SD card” errors as someone else noted in the comments there. I’ve switched to a Sandisk Class 4 MicroSD in an adapter now and that is working fine.
UPDATE 24/5/12: I’ve started work on some Python tools to control the MCP23017 using the Raspberry Pi, see this post for more information.
UPDATE 2/6/12: I’ve created a plug in expander board using the Ciseco “Slice of Pi” and the MCP23017, see this post for details and a step by step guide to getting it working with the above Python tools including a link to a Raspberry Pi kernel/modules with I2C compiled in.