Previous Entry Share Next Entry
i2c IO Expander
tibman wrote in arduino_related

Need more digital IO ports?

Another i2c post. This one is about a 16 port IO Expander that works well with the arduino. I'm driving a bunch of leds with it now, i guess you could get eight of these things and drive 128 leds through i2c if you wanted.

Part Description: IC I/O Expander I2C 16B 28SDIP
Digikey part number: MCP23016-I/SP-ND
Price from Digikey: $1.90 US on 20 Sep 09

You will also need two additional parts to support the chip.
1x 33pF Cap
1x 3.9k Resistor

Wiring Diagram

Once the chip is setup, it's very easy to use. The device's i2c address is 0100xxx. Connecting an addr pin to ground makes it '0' and to +5v makes it '1'. This gives you enough addresses to use eight expanders at the same time. Also, this device didn't like i2c bus speed over 100k :(

I ended up writing a library (class) to manage the IO expander. It's kind of big so i'm just going to put the important bits here.

//Basic Write command
void Write(byte reg, byte data1, byte data2)
  Wire.send(reg); // Command

//Read inputs
void Read()
  //Set read from GP0
  Wire.send(0x00); // Command: Access to GP0
  //Recieve bytes from module
  Wire.requestFrom(addr,2); //only two bytes
  { io_data[0].set(Wire.receive()); io_data[1].set(Wire.receive());}
  else {Serial.println("ERROR: request from GP0 failed");} //FIXME - this should be removed

The Datasheet has a list of commands. The important ones are 0x06 (io direction) and 0x00 (pin status). All reads and writes have to be done in pairs. So even if you only want to read one pin, you have to read two bytes (16 bits) and extract the one you want.

I had a difficult time doing bitwise stuff (my first time really) and made a debug function to help. If you are having problems i recommend something like this, it helps so much.

I think it's a great little chip. If you ever feel like your arduino is running out of IO space, drop $2 into one of these. Well worth it!

Two leds and a Button hooked up to the IO Expander

  • 1

Pin 16 cant be used?

Hello, the first this I would say is thank you for the lib.
But I cant manage to use pin 16 as a output, if i set it with
the pinMode function of your lib.

If I set all pins as output with:

> Wire.begin();
> Wire.beginTransmission(0x20);
> Wire.send(0x06);
> Wire.send(0x00); // DDR Port0 all output
> Wire.send(0x00); // DDR Port1 all output
> Wire.endTransmission();

Then I'm able to write to pin 16.

Is there any workaround to fix your pinMode?
Many thanks and sorry for my bad english.

Regards, Jack.

Re: Pin 16 cant be used?

hmm, it's been a while since i've worked on this. But! Give me a few minutes to research an answer for you.

Ok, so it does the same thing if you use the io_expander blink example on pin 16 as well?

The only thing i can think of right now is the pin states are saved in arduino memory and not read from the io_device (to save on io). It's possible that what is in memory is different than what the device is actually set to. Try pulling power from the chip completely and resetting the arduino. I use a reset command (like in the example) to flush all the values and reset the chip, but there are some things it doesn't reset.

But there is also the possibility that i never even tested pin 16 : / I'll put a test setup together and see if i can reproduce your problem.

Edited at 2011-06-28 03:33 am (UTC)

Re: Pin 16 cant be used?

There is completely nothing wrong with your lib.
I can write to pin 16.

I wrote a generic class for a handful of chips, and this
class needs a pin range to init correctly. The range I set
was 1 entry to short. <.< .. took me about 2 days to figure
that out.

Thank you for your feedback and the fast answer and the lib.
Regards, Jack.

Re: Pin 16 cant be used?

yay! Glad to hear it's working for you. If you expand the library any, i'd love to add it to the SourceForge download. Just let me know how the credit should be given (in a readme or in the .cpp files and what it should say).

  • 1

Log in

No account? Create an account