14 Jun 2014

IO Expander PCF8574 with Raspberry Pi

With the Raspberry Pi, you can easily run out of IO pins. A good way to solve that problem is to use an IO expander to give your Pi a couple more IO. On Tayda Electronics website, you have two different chips, the 8-bits PCF8574 and the 16-bits MCP23017 from Microchip. These two devices can communicate with the PI using the I2C protocol, it only uses two pins : SDA (data) and SCL (clock). The MCP23017 is a bit more complicated than the other one because you have access to a lot of registers on the device. The PCF8574 does not use register address : you simply read or write from it.

First, you will need to activate the I2C port on your Raspberry Pi. There are several tutorials showing how to do this and I covered a couple links in my article about Adafruit's I2C LED matrix. You also have to find the address of your device. If it's a PCF8574A the address will be different.


The three least significant bits of the 7-bits address are A2, A1, and A0. These three bits are set on the pins of the chip that have the same name. That means that you could have a maximum of 8 PCF8574 connected to your Pi without having address conflict. This means you can have up to 64 more IO. If you use 8 PCF8574 and 8 PCF8574A you can double this number :)

On my breadboard, I wired 8 orange leds to the PCF8574 using 220 Ohms resistors. I plugged to chip on the 5V line to have a little bit more current on the LEDs than on the 3.3V line. A2, A1, and A0 are shorted to ground. The address of the device is then 0x38 (0111000). At first I did not understand it was this address because of the picture above, where we see a 0 next to A0. But A0 is really the least significant bit. An I2C address is always 7-bit.

On the rev2 Raspberry Pi, the I2C port is #1 and on rev1 it is #0. This little detail is important to know when we initialize the I2C device. Once everything is wired up and I2C is enabled, we can issue a detect command :


In the command i2cdetect -y 1 we specify that we are using port #1 for the rev2 Pi. There is also a really useful command we can use :
i2cset -y 1 0xADDRESS 0xDATA

For example, if I want to turn on all the LEDs directly on the command line, I can issue this command :
i2cset -y 1 0x38 0xFF

It's easy as that!!!

Python example

This demo would not be complete without some LED chasing and a demo Python program. In the sample below, LED1 through LED8 are the bit position of each LED in hexadecimal. I used the cycle function from the itertools library to create an infinite array that cycle from LED1 to LED8, and back to LED1, etc... Without pausing between each iteration, the Raspberry Pi would do that sequence really fast, so I'm adding a 100ms delay so we can see what is happening.

from smbus import SMBus
from itertools import cycle
from time import sleep

LED1 = 0x01
LED2 = 0x02
LED3 = 0x04
LED4 = 0x08
LED5 = 0x10
LED6 = 0x20
LED7 = 0x40
LED8 = 0x80

PATTERN = (LED1, LED2, LED3, LED4,
           LED5, LED6, LED7, LED8,
           LED7, LED6, LED5, LED4,
           LED3, LED2)

bus = SMBus(1) # Port 1 used on REV2 

for LED in cycle(PATTERN):
    bus.write_byte(0x38, LED)
    sleep(0.1)

Demo video