I2C - GPIO Port Expander
What is I2C?
I2C (eye-squared-cee) is a communication protocol that the Raspberry Pi can use to speak to other embedded devices (temperature sensors, displays, accelerometers, etc). In this example, we'll be connecting an MCP23008 I/O expander to our Raspberry Pi. The I/O expander adds additional GPIO ports. These can be used as both inputs, and outputs at either 3.3V or 5V. This makes it an ideal level shifter chip for peripherals that are 5V and not natively compatible with the RPi's 3.3V GPIO ports. The MCP23008 can also generate interrupts based on input, but we won't be covering that here.
I2C is a two wire bus, the connections are called SDA (Serial Data) and SCL (Serial Clock). Each I2C bus has one or more masters (the Raspberry Pi) and one or more slave devices, like the I/O Expander. As the same data and clock lines are shared between multiple slaves, we need some way to choose which device to communicate with. With I2C, every device has an address that each communication must be prefaced with. The I/O Expander defaults to an address of 0x20, but it has 3 pins which can be used to change the address to any value up to 0x27. This means you can use up to 8 MCP23008s on a single I2C bus.
The Rasperry Pi has two I2C buses. One is available on the GPIO (P1) header, the other is only available from the P5 header. To access these, you'll need to solder on your own header pins.
Preparing RPi for I2C
Comment out the i2c-bcm2708 line from the raspi-blacklist.conf file:
Confirm that the i2c modules are loaded and active:
Install some i2c utilities:
i2c-tools includes some cool utilities, like i2cdetect, which will enumerate the addresses of all slave devices on a single bus. Try it out by running 'sudo i2cdetect -y 1' with the MCP23008 connected. Another utility, i2cdump lets you query the state of individual settings (registers) on a specific I2C device. This is the output you should see with the MCP23008 connected as below, and configured for the default address of 0x20:
Connecting MCP23008
Controlling MCP23008
There is a great I2C Python library available from Adafruit. It is already available in the WebIDE if you are using that tool. Otherwise, the library can be downloaded from Adafruit's GitHub Page. This file needs to be in the same directory as your python script. Bytes can be read and written from the I2C bus using code like the following:
You can see that all i2c commands have to be addressed to the MCP23008 device (address 0x20), but also to a specific register on the device. The registers on the MCP23008 are (from the data sheet): 0x00 IODIR Controls input/output state of each of the 8 inputs. Setting a bit to 1 makes it an input
0x01 IPOL
0x02 GPINTEN Enables interrupt on change
0x03 DEFVAL Default value to base interrupt on change for
0x04 INTCON Interrupt control - compare against previous value or compare against DEFVAL
0x05 IOCON
0x06 GPPU Configures internal 100k pullup resistors for pins set as inputs
0x07 INTF Shows interrupt state of each port
0x08 INTCAP Captures value of pin experiencing interrupt. Reading this clears the interrupt
0x09 GPIO State of each individual GPIO pnin
0x0A OLAT
Adafruit has already written a good interface library for the MCP23008 and its bigger brother: