So I wired up an MCP23017 GPIO expander to my Bus Pirate and couldn't understand why it wasn't acknowledging commands. Upon closer inspection of the datasheet I discovered that it expects an extra bit set in the I2C device address byte. The datasheet refers to this as the "Device Opcode".
Thus, if your device address lines are all tied to ground, ie. an address of 0x20, the address to write to is 0x40.
Once you've connected everything, the first step is to put your Bus Pirate in I2C mode and turn on the power:
HiZ>m4 Set speed: 1. ~5KHz 2. ~50KHz 3. ~100KHz 4. ~400KHz (1)>1 Ready I2C>W POWER SUPPLIES ON
This example assumes you've tied all three address lines from the MCP23017 to ground, making its I2C address 0x20. Now we'll configure both IO banks to be all outputs; the 0:3 notation tells the Bus Pirate to write the value three times. The first 0 selects the IODIRA register address. The second and third 0s clear all the bits in the IODIRA and IODIRB registers, thus configuring them as outputs.
I2C>[0x40,0:3] I2C START BIT WRITE: 0x40 ACK WRITE: 0x00 ACK 0x00 ACK 0x00 ACK I2C STOP BIT
Finally, we turn on all eight GPIOA pins by writing 0xFF to register 0x12.
I2C>[0x40,0x12,0xFF] I2C START BIT WRITE: 0x40 ACK WRITE: 0x12 ACK WRITE: 0xFF ACK I2C STOP BIT
As always, read the fine datasheet!