Problem with i2c

Hello Folks

I have a bit of a problem when trying to interface the Arduino with an MCP23008 8bit i/o expander.

The problem is, everything works fine the moment I upload it to the board, but if I then disconnect the power and then reconnect it, it no longer works and I have to keep pressing the reset button until eventually it starts to function.

I have tried several different chips and they all behave the same.

To add more issues to the works, I have also tried running it from a 12v power source: it works immediately, but counts up erratically.

Please help, I think I am looseing my mind :cry:

This is the code I am using:

//MCP230008 experiments

//define registers
byte IODIR = 0x00; // I/O Direction Control
byte IPOL = 0x01; // Input Polatrity Register
byte GPINTEN = 0x02; // Interrupt-on-chnage control register
byte DEFVAL = 0x03; // Default compare register for interrupt-on-change
byte INTCON = 0x04; // Interrupt Control register
byte IOCON = 0x05; // Configuration register
byte GPPU = 0x06; // Pull-Up resistor configuration register
byte INTF = 0x07; // Interrupt Flag register
byte INTCAP = 0x08; // Interrupt Capture register
byte GPIO = 0x09; // Port register (input)
byte OLAT = 0x0A; // Output latch register (output)

#include <Wire.h>

int ADDR = B0100011;

void setup()
{
Wire.begin(0x08);
setMCP(ADDR, IOCON, 0x0C);
delay(100);
setMCP(ADDR, IODIR, 0x00); //set the IO direction control to output on all pins
delay(100);
setMCP(ADDR, OLAT, B10101010);
delay(500);
setMCP(ADDR, OLAT, B01010101);
delay(500);
}

void loop()
{
for (int i=0; i < 255; i ++)
{
setMCP(ADDR, OLAT, i);
delay(20);
}
}

void setMCP(byte addr, uint8_t reg, byte val)
{
Wire.beginTransmission(addr),
Wire.send(reg);
Wire.send(val);
Wire.endTransmission();
}

Thanks, Chris

This is just a guess, but does anything change if you insert a delay (say 100 ms) as the first statement in setup?

Also, is there a reason you are specifying an address in your Wire.begin statement? According to the documentation this joins the I2C bus as a slave rather than a master.

Yeah, I have tried inserting delays, ranging from 50 to 2000 and still no luck.

If you check the documentation it in fact says that the address is optional for being a master. I have tried it both ways (with and without specifying an address) and it seems to be slightly more stable this way.

Hmmm.. nothing obvious wrong with the code. I only write to GPIO rather than OLAT but I don't think that should matter. Also not clear why you are setting ODR and HAEN in IOCON, but that shouldn't matter?

Do you have pullups on the I2C lines?

I do recall that many repeated Wire calls led my Arduino to behave erratically. Have you inserted some debugging prints to see if "not working" means the Arduino is freezing, or if the MCP is just ignoring you?

Sorry, the 0x0C in the IOCON register is a typo I copied from someone else’s code in my desperation to make it work. It should be 0x00.

Good idea about the debugging. I will do it.

Ok, added some debug info, and the program is running correctly buy the MCP is not responding until I hit reset.

More progress:

I have got it to run by first setting the value of pins 4 and 5 high and keeping them there for 3.25 seconds (I arrived at this time by starting with a 5 second delay, then performing a 'binary chop' style search until I found the lowest value it would reliably start up at).

This is a not an ideal solution, and every now and again the output freezes for no readily apparent reason, so I have ordered an i2c LED driver to play with to see if that has any problems. If it does then the problem could well be my Arduino.

Thanks for you help

You might try with and without pullup resistors on the I2C lines. Supposedly the Wire library enables the weak pullups on pins 4 and 5, but it can't hurt to see if the presence or absence of external pullups (4700 ohms seems traditional) makes a difference.

I think it is interesting that it behaves so differently when powered by 12 volts.
Regardless of any issues with code & etc, if the voltage regulator is working properly you would expect the behavior to be the same.

If you look at the reference for the Wire library, it says quite explicitly that

Wire.begin(address) initializes the Wire library with the Arduino functioning as a slave at address address.

I haven't checked the code to confirm it, but that should mean that the internal pullups are off.

There are lots of possible hardware causes for your problem that haven't been discussed.

You haven't told us anything about how the MCP23008 is wired. How long are the SCL and SDA wires? Are there external pullups on them? Do you have good power and ground connections? Is there a decoupling capacitor for the power supply near the chip?

It appears that you're driving LEDs with the I/O pins, but they're only rated to source about 3mA and sink 8mA, according to the data sheet. Have you chosen the current-limiting resistors accordingly?

Ran Talbott, you are quite right about the whole Wire.begin() thing. I check the source code to confirm it. I can't think for the life of me where I read that it made no difference, although it doesn't in fact make much difference in this case as there are only two devices and they are both using different addresses. Honest. I tested it. However, I have changed the code to reflect that it is better to have the device as the Master.
According to the source code for twi.c, the internal pullups should be on: (I have a 328p)

 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__)
    // activate internal pull-ups for twi
    // as per note from atmega8 manual pg167
    sbi(PORTC, 4);
    sbi(PORTC, 5);
  #else

I am not sure if this is working or not. I have measured the voltage with a voltmeter, but to get a true reading I need an oscilloscope as a voltmeter will, by it's very nature, give me the RMS value (or something like it). Given the lack of a 'scope, I found that the problem was solved by using 4.7k resistors as external pullups.

Thanks once again for all your help

Chris,
Did you solve your problem. I think have the exact same problem. Everything works fine until I want to use the INT pin. After the first few lines in my interrupt code runs the arduino freezes.

I tried a delay(2000) in place of the next few lines and it freezes during the delay.

If I just trigger the int myself and then don't try to use Wire to read the GPIO of the MCP23008 then it seems to work fine.

np

If I just trigger the int myself and then don't try to use Wire to read the GPIO of the MCP23008 then it seems to work fine.

Hi np,
It seems that it isn't possible to use any Wire methods from within the interrupt service routine. I have got round this problem in the past by using the interrupt to set a flag to indicate that the GPIO register needs reading, then picking up that flag from within the main loop and read the register then reset the flag.

Hope that helps.

Chris

It appears that you're driving LEDs with the I/O pins, but they're only rated to source about 3mA and sink 8mA, according to the data sheet.

According to the data sheet I read:-

Maximum output current sunk by any output pin ....................................................................................................25 mA
Maximum output current sourced by any output pin ...............................................................................................25 mA

Those lower figures were only test conditions for the voltage measurements.