MCP23017 Library Port

@Trekky, it is working using the Adafruit RGB Shield as a test platform. First, you can’t connect the INTA output to D2 of the Core as it is not 5V tolerant (!) On the shield, I had to solder a wire from pin 20 (INTA) of the MCP23017 and connect it to pin D3 of the Core. I also found a little oddity in the RGBLCDShield library which used pinMode. It turns out that the Arduino definitions for INPUT and OUTPUT are opposite those for the Core!

The combo of both libraries required to use the RGBLCDShield is here. I included the HelloWorld example and also the interrupt example which shows the use of interrupts from the MCP23017. @Trekky, you can modify interrupt.ino to test interrupts without the shield easily.

@JackANSI, if you want a working RGBLCDShield library, there you go! :smile:

@peekay123 I’m very interested in I2C working in general. I use a MCP23017 in chip form on one of my projects in my home (an audio source switcher). Having this chip working saves me from redoing the whole thing when I switch that from a Pi to a core or photon.

But…

If I had to pick an adafruit product or two directly:
A. Bi-color bar graph (based on Holtek HT16K33) https://www.adafruit.com/products/1721

B. The MCP23008 based I2C character backpack https://www.adafruit.com/products/292

If you wanted another challenge and need either or both of them I can provide a gift certificate to cover that and provide incentive :smiley:

@JackANSI, check out the IDE for libraries. the MCP23008 lib is there, the LCD library for the backpack needs to be ported and the bi-color bargraph is a no brainer to port :stuck_out_tongue: I’ll see what I can over the next few days. As for the gift certificate, donate to your local food bank and make a small difference on my behalf :sunny:

3 Likes

@peekay123 you got it.

1 Like

@peekay123 Thank you very much for your effort. The interrupts are working now! For the record the correct working layout is below.

3 Likes

I have tested around with the MCP23017 and like to share my experiences.

I figured out that the MCP Interrupt Register must be read to recognize interrupts correct. That means after the initialisation of the MCP and after the interrupt occured it must be cleared with mcp.readGPIOAB().
I added a functional example here (thank you @peekay123 for the inspiration) .

The corresponding description is in the datasheet:

The interrupt will remain active until the INTCAP or GPIO register is read. Writing to these registers will not affect the interrupt. The interrupt condition will be cleared after the LSb of the data is clocked out during a read command of GPIO or INTCAP.
The first interrupt event will cause the port contents to be copied into the INTCAP register. Subsequent interrupt conditions on the port will not cause an interrupt to occur as long as the interrupt is not cleared by a read of INTCAP or GPIO.

2 Likes

Hi,

with just a few lines, the inverse input function can be added.
Usefull for buttons driving the internal pullups low.

add in the .h file

void inputInvert(uint8_t p, uint8_t d);       

add in the .cpp file

/**
* Sets the invert register to either normal or invert
*/
void Adafruit_MCP23017::inputInvert(uint8_t p, uint8_t d) {
  updateRegisterBit(p,(d==INPUT),MCP23017_IPOLA,MCP23017_IPOLB);
}

useage

mcp.inputInvert( pin, HIGH );    // invert input
mcp.inputInvert( pin, LOW );     // normal input

pin 0…15

1 Like

Hi, I'm working on a project where I need to expand a Photon's number of digital GPIO's to around 60...

It seems an ideal solution to me to use four MCP23017 I/O expander ICs.

I tried the library examples with one IC today and everything works perfectly. The fact that you can configure every one of the 16 I/O pins as INPUT and OUTPUT is exactly what I need!

I know the 3 hardware address pins 15~17 are used to determine the I2C bus address for the chip, but I cannot figure out how to address pins on each of the four ICs...

All library examples contain this line:

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

I guess to address 3 more chips, you should hardwire them to address 1, 2, 3 and use an extra identifier in the code, right?

Can anybody help?

You’ll need to instantiate an instance of the class for each MCP23017 and use the address you assigned them in the mcp.begin(addr) routine. You may not have noticed but it’s overloaded to also take a parameter, the address.

Here’s the link to the source:
https://github.com/pkourany/Adafruit_MCP23017_IDE/blob/master/firmware/Adafruit_MCP23017.cpp#L110

If you’re using the online code editor, there’s a little github icon that shows next to Library name once its selected. This takes you right to the firmware source for the library.

1 Like

Thanks for your reply @jbeacon !
I suppose that’s also what @ScruffR explained in the new topic I started (LINK)

I will do my best, but I’m not sure if I can figure it out how exactly to do this.
Actually, I was hoping for an example… :wink:

PS: I’m only a hardware engineer who has programming in “wiring” as a hobby…

Great @jbeacon and @ScruffR !
I scrolled through the library: it’s a masterpiece!
But it goes far beyond my capabilities to interpret how to use all possibilities without an example…

If I take one of the existing examples “toggle.ino” (LINK), I would like to try it out with a second MCP23017 chip.

So, the first thing I do is set an address with the three pins:

Pin 17 Pin 16 Pin 15 HEX Address
0 0 0 0x20
0 0 1 0x21
0 1 0 0x22
0 1 1 0x23
1 0 0 0x24
1 0 1 0x25
1 1 0 0x26
1 1 1 0x27

Below is part of the “toggle.ino” sketch.
It says: “// use default address 0”

I guess the default address “0” mentioned in the example is actually HEX address “0x20”, right?
Suppose I select for the second chip address “0x21”, that must then be address “1” to use in my sketch. OK?

The questions for me are:

  1. How do I indicate both address 1 and 2 for my two chips
  2. How do I repeat the same commands for the corresponding pins on the two chips?

Adafruit_MCP23017 mcp;

void setup()
{
mcp.begin(); // use default address 0

mcp.pinMode(0, OUTPUT);
}

// flip the pin #0 up and down

void loop()
{
delay(100);

mcp.digitalWrite(0, HIGH);

delay(100);

mcp.digitalWrite(0, LOW);
}


Adafruit_MCP23017 mcp;
Adafruit_MCP23017 secondmcp;
mcp.begin(); //implicit (0)
secondmcp.begin(1);

2 Likes

Thanks @MORA and @peter_a ! (LINK)

So, to summarize how I understand it:
For the above “toggle.ino” sketch I will change as shown in BOLD:


Adafruit_MCP23017 mcp;
Adafruit_MCP23017 secondmcp;

void setup()
{

mcp.begin(); //implicit (0)
secondmcp.begin(1);

mcp.pinMode(0, OUTPUT);
mcp.pinMode(16, OUTPUT);
// I assume chip 1 has pins 0 - 15 and chip 2 has pins 16 - 31

}

// flip the pin #0 and #16 up and down

void loop()
{
delay(100);

mcp.digitalWrite(0, HIGH);
mcp.digitalWrite(16, HIGH);

delay(100);

mcp.digitalWrite(0, LOW);
mcp.digitalWrite(16, LOW);

}


Do you think this is correct?

@FiDel, the MCP23017 are not “aware” of each other so each of their pins are 0-15.

2 Likes

As @peekay123 notes, each mcp unit has 0-15, if you want to use higher pin numbers, you need to write that abstraction yourself.

Adafruit_MCP23017 mcp;
Adafruit_MCP23017 secondmcp;

void setup()
{

mcp.begin(); //implicit (0)
secondmcp.begin(1);

mcp.pinMode(0, OUTPUT);
secondmcp.pinMode(0, OUTPUT);
// I assume chip 1 has pins  0 - 15 and chip 2 has pins 16 - 31

}

// flip the pin #0 and #16 up and down

void loop()
{
delay(100);

mcp.digitalWrite(0, HIGH);
secondmcp.digitalWrite(0, HIGH);

delay(100);

mcp.digitalWrite(0, LOW);
secondmcp.digitalWrite(0, LOW);

}
1 Like

OK! It works!

Now that is indeed logical, but I have not enough background (yet) to figure that out!
This is a great community!

Sorry for creating this new post @ScruffR , but I believe it can help others to find easier how to do this…

I wish I could invite all who helped to a good Belgian beer tonight!
I’ll drink one to your health :wink:

Thanks @peekay123 @MORA @peter_a @jbeacon @ScruffR !

4 Likes

Sorry to bump this thread but is there any way to change the wirespeed for these calls (i need it to be as fast as possible) and perhaps do digitalWriteFast against the chip?

I want to use one of these to control 16 triac devices for ac dimming so increasing the speed of read and writes would be great. The triac relies on millisecond timing so i need to speed my calls up as much as possible

Jamie

@bigjme, the fastest wire speed supported by the Photon is 400KHz.

All digital writes via the MCP23017 are done via a set of I2C commands so there is no "digitalWriteFast" that can be done.

There is, however, an SPI version of the chip (MCP23S17) that can handle 10MHz SPI. I believe I have seen an SPI library for this version of the chip. At that speed, you could control all 16 channels within the target timeframe.

@peekay123, thanks for your reply

I will have to have a look for the SPI code, for now is the wirespeed still set using the following

Wire.setSpeed(CLOCK_SPEED_400KHZ);

I got a little confused as you instigate the begin using an instance of the class

Jamie

@bigjme, yes, that is the way to change the speed. The docs about setClockSpeed() say:

Sets the I2C clock speed. This is an optional call (not from the original Arduino specs.) and must be called once before calling begin(). The default I2C clock speed is 100KHz and the maximum clock speed is 400KHz.