MCP23017 working, but not on breadboard

Hi guys,

I have designed and built a 16 relay solution using a MCP23017 I2C chip. I used ULN2803 drivers for the relays. This works fine, soldered on some standard experiment-PCB's.

Now I am working on a next stage, building input boards. I am trying to get it to work on a breadboard but no success so far. Now I've been told that the MCP23017 is very sensitive to parasitic capacities caused by breadboards.

First general question: does anyone have such experience, and what to do about it?

Gerard

Breadboards are fine for a quick proof of concept lashup. Anything more than that, you should be using stripboard etc.

You don't specify what 'not working' means so I offer this:

breadboard small.PNG

breadboard small.PNG

dougp:
You don’t specify what ‘not working’ means so I offer this:

‘not working’ means that it does not perform the function for which I wired it.

The address lines A0-A2 are connected to ground, so the address is 0x20.
The reset pin is hooked to VCC.
SCK and SDA are attached to the ATMEGA328P pins SCL and SDA respectively.

I attached a CNY74-4 opto-coupler for galvanic separation of the input signal and hooked it’s output up to GPA3 - GPA0 of the MCP23017. GPA7 - GPA4 are connected to ground (through 10K resistors).
I offer 0101 to GPA3 - GPA0, so I expect to see 0x05 when I read from it using I2C.

I checked all inputs on my Rigol multimeter and they react as I expect, they have the proper values (GND or HIGH).

Here’s my sketch:

// MCP23017 : Input test
//
// Toggle LEDs and read input from Port A.
//

#include <Time.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>

#define MYLED 13

Adafruit_MCP23017 mcp;
 
void setup() {  

 pinMode(MYLED, OUTPUT);
 
 mcp.begin(20);                      // Device address 20
 
 for (int i=0; i<8; i++){
   mcp.pinMode(i, OUTPUT);           // pin to INPUT
   mcp.pullUp(i, HIGH);              // Pull up
 }
 
 Serial.begin(9600);
 Serial.println("Start program");

}

// Read pins
// display values
void loop() {
 char buf[80];
 char prt[9];
 int val = 0;
 for (int i=0; i<8; i++) {
   int v = mcp.digitalRead(i);
   val = (2 * val) + v;
 }
 dtostrf(millis(), 9, 0, prt);
 sprintf(buf, "%s : %x", prt, val);
 Serial.print(buf);
 Serial.println("");
 
 delay(300);
 digitalWrite(MYLED, HIGH);
 delay(300);
 digitalWrite(MYLED, LOW);
}

A schematic is preferred over a written description of the circuit.

Read the how to use this forum-please read sticky to see how to properly post code.

 dtostrf(millis(), 9, 0, prt);

Not sure what happens when you feed an unsigned long data type to a function that expects a double (float). It probably is not what you want.

groundFungus:
A schematic is preferred over a written description of the circuit.

Read the how to use this forum-please read sticky to see how to properly post code.

I did. It says " Post a circuit if there is doubt". There isn't.

Furthermore, my original question, which we diverted from, was:

"I am trying to get it to work on a breadboard but no success so far. Now I've been told that the MCP23017 is very sensitive to parasitic capacities caused by breadboards.
First general question: does anyone have such experience, and what to do about it?"

Gerard

groundFungus:

 dtostrf(millis(), 9, 0, prt);

Not sure what happens when you feed an unsigned long data type to a function that expects a double (float). It probably is not what you want.

Oh it is. It makes the output of millis() right justified, padded on the left with spaces, just how I want it.
But that is a wee bit off topic.

There's nothing special about the chip, its just a CMOS logic chip.

You must use a decoupling capacitor on every CMOS logic chip, 100nF ceramic as close to the pins as
possible - without this expect all sorts of random behaviour....

The I2C bus must have suitable pullups - keep the length of wiring short for logic busses like I2C and SPI
(a few inches). Ensure wiring is neat and every signal wire has a ground return wire alongside it (several
signals can share a ground wire). Random sprawling separate wires all over the place will misbehave
at logic speeds, this is what you should aim for: wires - How to improve wiring a breadboard? - Arduino Stack Exchange

Thanks MarkT

Here's my breadbaords. The ATMEGA328P is on top, below you find the MCP23017 on the left and the (proved to be working by measuring the outputs) opto-coupler on the right.

As you can see, the little blue blobs are the 100nF cap's.

Okay, new try… :confused:

Hi,
OPs image;


However for us all to be on the same page and understand your project, please post a circuit diagram.
Even a hand drawn circuit will suffice if the components and pinouts are labelled.

Question;
why123.jpg
Why have you got the three resistors that I have circled?
What value are they?
You can switch directly to 5V.

Thanks.. Tom.. :slight_smile:

why123.jpg

Hi,
Looking at the Adafruit examples, if you connect ALL the address lines to gnd, then that is the default value when you use their library.
In the examples they have this;

mcp.begin();      // use default address 0

instead of this;

 mcp.begin(20);                      // Device address 20

Also;

for (int i=0; i<8; i++){
   mcp.pinMode(i, OUTPUT);           // pin to INPUT
   mcp.pullUp(i, HIGH);              // Pull up
}

Shouldn’t you be declaring the INPUTS as INPUTS not OUTPUTS?

Have you tried I2C Scanner to see if the I2C is working and can detect the expander?

Thanks… Tom… :slight_smile:

TomGeorge:
why123.jpg
Why have you got the three resistors that I have circled?
What value are they?

Worse in fact, they appear to be the same value as the pull-downs, meaning they would set the voltage at half of Vcc, making the logic level indeterminate. :cold_sweat:

This would be a problem if any DIP switch was "ON". :astonished:

I see that you are using turned-pin sockets in the breadboard. That is usually asking for problems. The turned pins are too short to make a proper contact. Remove the chip from the socket and put directly in the breadboard.

// Per.

TomGeorge:
In the examples they have this;

mcp.begin();      // use default address 0

instead of this;

 mcp.begin(20);                      // Device address 20

Also;

for (int i=0; i<8; i++){

mcp.pinMode(i, OUTPUT);           // pin to INPUT
  mcp.pullUp(i, HIGH);              // Pull up
}



Shouldn't you be declaring the INPUTS as INPUTS not OUTPUTS?

Have you tried I2C Scanner to see if the I2C is working and can detect the expander?

Thanks.. Tom... :)

Thanks Tom!
Thanks to you I found a few errors in my code. (slapping myself on the head now)…

Checking for I2C device:
I built in code to check the presence of a device on the address where I expect it, thanks for that tip; that’s how I discovered that I had the wrong address.

The address:
I inadvertently specified a hex value (20) in a place where it was supposed to be decimal; So I changed it to hexadecimal 0x20 and now it IS being discovered. Note on the side: the MCP23017 offsets the address from 0x20, so when A0-A2 are tied to ground, the address will be 0x20.
OUTPUT / INPUT:
Wow, I should have seen this myself. Thanks for pointing that out!
Results:
I now know that there IS a device at the address where I expect it. I get different results; the program showed all x’ff’ all the time, but now it gives me x’a0’, no matter what I change in the input:

Start program
Scanning for I2C device
I2C device found at address 32
       23 : a0
      627 : a0
     1231 : a0
     1836 : a0
     2440 : a0
     3044 : a0
     3648 : a0
     4252 : a0
     4856 : a0

New sketch:

// MCP23017 Example: Show input of port A as a hexadecimal number

#include <Time.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>

#define MYLED 13
#define address 0x20

Adafruit_MCP23017 mcp;

char buf[80];
  
void setup() {  

  Serial.begin(9600);                 // Start talkin'
  Serial.println("Start program");

  //
  // Check for the presence of an I2C device at the address we specify
  //
  Wire.begin();
  Serial.println("Scanning for I2C device");
  Wire.beginTransmission(address);
  int error = Wire.endTransmission();
  if (error == 0) {
    Serial.print("I2C device found at address ");
    Serial.println(address);
  } else {
    Serial.print("ERROR: NO I2C device found at address ");
    Serial.println(address);
    Serial.print("Program ends now");
    delay(500);
    exit(0);
  }
  
  pinMode(MYLED, OUTPUT);             // Built in LED for flashing indication
  
  mcp.begin();                        // start the I2C library
  
  for (int i=0; i<8; i++){
    mcp.pinMode(i, INPUT);            // pin to INPUT
    mcp.pullUp(i, HIGH);              // Pull up
  }
  
}

// Read pins and display values
void loop() {
  char prt[9];
  int val = 0;
  for (int i=0; i<8; i++) {
    int v = mcp.digitalRead(i);
    val = (2 * val) + v;
  }
  dtostrf(millis(), 9, 0, prt);
  sprintf(buf, "%s : %x", prt, val);
  Serial.print(buf);
  Serial.println("");
  
  delay(300);                         // Flash
  digitalWrite(MYLED, HIGH);          //  the LED
  delay(300);                         //    to indicate
  digitalWrite(MYLED, LOW);           //      the program is still going
}

Somehow, it automagically works now…
I did discover another logic error, in that I read the bits in reverse order. That is why I got 0xa0, which is binary 0b10100000, while I expected 0x05, binary 0b00000101
I changed the code, see snippet below, and now it works:

// Read pins and display values
void loop() {
  char prt[9];
  int val = 0;
  for (int i=7; i>=0; i--) {        // <<<=== CHANGED THIS LINE
    int v = mcp.digitalRead(i);
    val = (2 * val) + v;
  }
  dtostrf(millis(), 9, 0, prt);
  sprintf(buf, "%s : %x", prt, val);
  Serial.print(buf);
  Serial.println("");

Zapro:
I see that you are using turned-pin sockets in the breadboard. That is usually asking for problems. The turned pins are too short to make a proper contact. Remove the chip from the socket and put directly in the breadboard.

// Per.

My preference is not to use sockets in breadboards, but alas, in my case it's just the opposite, the chips popped out when I didn't use these sockets. The socket pins are just a bit longer.
Thanks Per

TomGeorge:
Why have you got the three resistors that I have circled?
What value are they?
You can switch directly to 5V.

The values are 1K, I put them there because I wasn't sure whether I could hook them up to VCC...

Attached you will find the - now working - I2C signals.

Just as a warning, might you want to use the Adafruit library for the MCP23017 chip.

After a lot of hassle I discovered that I had made a false assumption.

I had assumed that the address one had to specify for the mcp.begin() function was to be same as the hardware address and thus the same as the address for the wire.begin() function.

Apparently for the Adafruit library one has to specify the address as a number from 0 to 7, which will then be added to the MCP23017 base-address of 0x20... pffft...

So that you know.

Gerard