I was wondering if anybody here has experience with controlling this I/O expander from Microchip. I've gone through a few code examples and so far no luck. Maybe I'm missing something small and any thoughts would be much appreciated.
Basically I'm trying to set bank A to output, then turn everything on, then output a value that increases slowly.
However you have got the address wrong. The wire library doesn't use a separate address for read and write but one address for the device and separate calls for read and write. This means the address you should be using is your address shifted to the right by one place for all calls to the library.
I've used the MCP23017 before and it works pretty much flawlessly. Unfortunately don't have the code I used right here, but might remember to come back and post it.
16 general purpose I/O with pin change interrupt and programmable pullups for $1, not bad.
I fixed that issue with the expander address. I'm still having some sort of issue with getting it to work. I'm fairly new to I2C and the Wire library.
Overall what I'm trying to do right now is just some rudimentary control of a single MCP23017. What the code does (attempts) is to set bank A to output mode and then set all pins high. The main loop alternately sets all bank A pins low, then high, rinse and repeat. I have leds hooked up to each of the bank A pins, so I should have some physical indication that what I'm doing is right. My code is the same as originally posted above with the exception of the suggested address fix. Still no response from the device. Is there another register I need to configure?
You might want to verify that your address pins are actually all connected to ground. The datasheet says they must be externally biased. If you let them hang in the wind they could be anything.
Yes. I have the 4.7K pullups on both the SCL and SDA lines... but I thought I read somewhere that this is not totally necessary due to the micro having internal pullups. I could be wrong.
#include <Wire.h>
//redefine highByte and lowByte to return byte, not int
#define loByte (byte)lowByte
#define hiByte (byte)highByte
#define opcode B0100000 // address = 000; 7 bits!
#define ioconbyte B00100000 // disable sequential operation mode;
#define iocon 0x0A
#define iodira 0x00
#define gpioa 0x12
#define gppua 0x0C //pullups
#define gpintena 0x04
#define defvala 0x06
#define intcona 0x08
#define intfa 0x0E
#define intcapa 0x10
#define ipola 0x02
void MCPstore (byte i2caddress, byte i2cregister, word i2cdata) // Store 16 bits in specified register of MCP23017
{
byte controlbyte = B0100000 | i2caddress; // note that bit 0 not used b/c 7-bit opcode for Wire library
Wire.beginTransmission(controlbyte);
Wire.send(i2cregister);
Wire.send(loByte(i2cdata));
Wire.send(hiByte(i2cdata));
Wire.endTransmission();
}
word MCPread (byte i2caddress, byte i2cregister) // Read 16 bits from MCP23017
{
byte controlbyte = B0100000 | i2caddress; // note that bit 0 not used b/c 7-bit opcode for Wire library
word tempdata;
Wire.beginTransmission(controlbyte);
Wire.send(i2cregister);
Wire.endTransmission();
Wire.requestFrom(controlbyte,(byte)2); // otherwise function gets one byte and one int & chokes
while (Wire.available() < 2) { }
tempdata = Wire.receive(); // get lower 8 bytes
tempdata |= (Wire.receive() << 8); // get upper 8 bytes
return tempdata;
}
void setup()
{
Serial.begin(9600);
Wire.begin();
Wire.beginTransmission(opcode);
Wire.send(iocon);
Wire.send(ioconbyte);
Wire.endTransmission();
MCPstore (0,iodira,0xffff); // all input
MCPstore (0,gppua,0xffff); // all pullups on
}
void loop()
{
word mcpdata = MCPread(0,gpioa);
byte firstbyte = hiByte(mcpdata);
byte secondbyte = loByte(mcpdata);
Serial.println(firstbyte,HEX);
Serial.println(secondbyte,HEX);
}
The program just displays the input state of GPIOA & GPIOB, but the 16-bit read and store routines should be portable. I have used them to set outputs as well.
Note that with the sequential address mode disabled (or maybe even with it enabled) if you write 8 bits to an A register, the address pointer automatically increments to the B register. So if you set the address pointer to the A register, you can read or write to the B register without a restart just by requesting or sending 16 bits.
Unfortunately the Wire routines do not report whether there was an I2C acknowledge; this would be very helpful in troubleshooting.
Thanks for the example code. I've looked over it and it seems to be consistent with the datasheet on how to read/write to the device. I'm still having no luck in getting it to work with my setup, so I think I'll go ahead and order another IC or two just to see if I have a bad one after all.
The code works now. Thanks Chaos! As it turns out I think I may have fried the I2C pins on my first Arduino. I ordered another board and it worked flawlessly!