MCP23017 I2C address seems to change across boards


I am using the Rugged Industrial I/O shield. I am trying to use it with the Arduino Uno, and the Netduino 3 Ethernet. Rugged has this to say about the I2C address of the MCP23017 I/O expander they use on the shield:

Digital Inputs and Outputs are driven by an I2C I/O Expander (MCP23017) on Arduino Pins A4 and A5... The default address is 0b0000001....

I have no reason to doubt this because sure enough, my code works on the Uno with address '1' as seen below:

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

Adafruit_MCP23017 mcp1;
int pin = 0;

void setup() {
 // using address 1
  mcp1.pinMode(pin ,OUTPUT);

void loop() {
      // simple output toggle with led.
      mcp1.digitalWrite(pin, HIGH);
      mcp1.digitalWrite(pin, LOW);

However I could not get the shield to communicate with the Netduino at first. I eventually tried using an I2C address scanner on the shield, and I see that it outputs the following:

I2C scanner. Scanning ...
Found address: 33 (0x21)
Found address: 72 (0x48)
Found 2 device(s).

It findsthe MCP23017 at address 33, and not 1! (the 72 address is an ADC chip on the shield.)
Sure enough, when I use 33 as an address on the Netduino, it works! What is going on here? I would really like to understand this problem so I don't waste hours again when dealing with I2C.


I should add that I did try to take a peak into the Adafruit_MCP23017.h library i'm using, but i didn't see any obvious place where it alteres the address.

I should also note that the Netduino 3 Ethernet has a different development environment, using .NET MicroFramework, not the Arduino IDE. Might the difference be in the back-end of the development environments?

I should add that I did try to take a peak into the Adafruit_MCP23017.h library i'm using, but i didn't see any obvious place where it alteres the address.

It takes more like a close reading than a "peek", but you are well on your way to understanding the Arduino environment if your instincts are to read the source code of the library when you are confused.

First, there is this in MCP23017.h

#define MCP23017_ADDRESS 0x20

Then there is a selectable on board jumper for address modification and it is dealt with in MCP23017.cpp

First, you pass the jumper setting in with begin(), That where you see the value 0 or 1. It becomes a variable called i2caddr

void Adafruit_MCP23017::begin(uint8_t addr) {
	if (addr > 7) {
		addr = 7;
	i2caddr = addr;


	// set defaults!
	// all inputs on port A and B

Then, that is combined with the base address of 0x20 when the device is actually addressed like here with a write command

 * Writes a given register
void Adafruit_MCP23017::writeRegister(uint8_t regAddr, uint8_t regValue){
	// Write the register
	Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);

It is strange that the perpetrators of the Technical Data Sheet would get the description of the addressing messed up for the MPC23017 and, in the same paragraph get the description for the ADS1015 correct.


Thank you, this direction is helping me understand!