0

Easiest way to write to a single port of MCP23017 - i2c 16 i
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Easiest way to write to a single port of MCP23017 - i2c 16 i

by wrichman on Fri Sep 13, 2019 1:12 pm

There's a "write all 16 bits" function in the library, but I need to just write to the B port all at once, which "pushes buttons" on a matrix keyboard just fine using analog multiplexers, but now I need to start using the other 8 bits, and there doesn't seem to be a function to write *just* the A port or *just* the B port. I guess I could keep the desired values for all 16 bits in a 16-bit variable and update the bits in that, and then dump the whole thing to the MCP23017 each time, but I was hoping there might be an easier way. I don't really want to take the time to delve too far into the library and the functionality of the chip if I don't have to, so I'm hoping someone can offer some insight. Any suggestions?

-Bill

wrichman
 
Posts: 18
Joined: Fri Apr 12, 2019 11:29 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by adafruit_support_bill on Fri Sep 13, 2019 1:22 pm

There is no function in the library for that. But the library code is rather straightforward. It would not be difficult to hack for your needs:
https://github.com/adafruit/Adafruit-MC ... P23017.cpp

adafruit_support_bill
 
Posts: 76213
Joined: Sat Feb 07, 2009 10:11 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by kcl1s on Fri Sep 13, 2019 4:03 pm

I could keep the desired values for all 16 bits in a 16-bit variable and update the bits in that, and then dump the whole thing to the MCP23017 each time, but I was hoping there might be an easier way.

I did this for a relay controller project where I wanted the relays to set at the same time. This page helped me with the bit logic. https://playground.arduino.cc/Code/BitMath/#common The quick reference at the bottom shows how to set a bit with a single line of code for (1) and another line of code for (0). I just made a small function and passed in a place value (n= 0 to 15) and a bool toggle value (state = 0 or 1) then a single if else to direct to the line of code to set a bit in my relays variable. I called the writeGPIOAB when I wanted to set all the relays.

Fellow hobbyist
Keith

kcl1s
 
Posts: 1459
Joined: Tue Aug 30, 2016 12:06 pm

Re: Easiest way to write to a single port of MCP23017 - i2c

by wrichman on Fri Sep 27, 2019 12:27 pm

Okay - so I added this in the library, and it seems to work as expected.

Adafruit_MCP23017.h
Code: Select all | TOGGLE FULL SIZE
 void writeGPIOA(uint8_t);
 void writeGPIOB(uint8_t);


Adafruit_MCP13017.cpp
Code: Select all | TOGGLE FULL SIZE
/**
 * Writes port A pins only. -wmr
 */
void Adafruit_MCP23017::writeGPIOA(uint8_t a) {
   Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
   wiresend(MCP23017_GPIOA);
   wiresend(a);
   Wire.endTransmission();
}

/**
 * Writes port B pins only. -wmr
 */
void Adafruit_MCP23017::writeGPIOB(uint8_t b) {
   // Serial.print("GPIOB b: ");Serial.println(b);
   Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
   wiresend(MCP23017_GPIOB);
   wiresend(b);
   Wire.endTransmission();
}


I'm having another issue with the MCP that was there before I made my changes, though. Is there anything special about GPA5 and GPA6? Both of them read "low" when I do this:

Code: Select all | TOGGLE FULL SIZE
const unsigned int mcpRedButton = 5; // input-pullup
const unsigned int mcpBlackButton = 6; //    "
mcp.pinMode(mcpRedButton, INPUT_PULLUP);
mcp.pinMode(mcpBlackButton, INPUT_PULLUP);
b1 = mcp.digitalRead(mcpBlackButton); // read the buttons
b2 = mcp.digitalRead(mcpRedButton);



I've even gone so far as to add 10K pull-up resistors to 5V, and even unsoldered and replaced the MCP chip, but I'm still seeing the same thing. mcpRedButton and mcpBlackButton are just normally-open momentary pushbuttons, with one side of each connected to ground and the other side connected to A5 and A6 on the MCP. I kept thinking it must be hardware, because even a logic probe applied to those two pins shows "low", with or without the external 10K resistors, but even with nothing connected to those two pins on the chip except a couple of empty solder pads, they still show "low". I guess I can try reading the whole "A" port and masking out the bits I'm interested in and see if that makes any difference. But... any ideas?

-Bill

wrichman
 
Posts: 18
Joined: Fri Apr 12, 2019 11:29 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by wrichman on Fri Sep 27, 2019 12:47 pm

Just for fun, I did this, since the code I posted before is just a few lines extracted from an 1,100 line program. It still reads "0" for both inputs. I even went so far as to pull the chip out of the socket (which I installed when I replaced it), bend up the A5 and A6 pins so they're not even in the socket. What am I doing wrong here?

Code: Select all | TOGGLE FULL SIZE
#include <Wire.h>
#include <Adafruit_MCP23017.h>
Adafruit_MCP23017 mcp; //GPIO expander initialize
const unsigned int mcpRedButton = 5; // input-pullup
const unsigned int mcpBlackButton = 6; //    "

void setup() {
  Serial.begin(2400);
  mcp.begin();
  mcp.pinMode(mcpRedButton, INPUT_PULLUP);
  mcp.pinMode(mcpBlackButton, INPUT_PULLUP);
}

void loop() {
  Serial.println("*");
  Serial.println(mcp.digitalRead(mcpBlackButton)); // read the buttons
  Serial.println(mcp.digitalRead(mcpRedButton));
}

wrichman
 
Posts: 18
Joined: Fri Apr 12, 2019 11:29 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by adafruit_support_bill on Fri Sep 27, 2019 1:14 pm

All the pins should work the same way. It is possible that those two pins got toasted somehow.

adafruit_support_bill
 
Posts: 76213
Joined: Sat Feb 07, 2009 10:11 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by wrichman on Fri Sep 27, 2019 2:29 pm

I installed a new MCP chip and it did the same thing, on the same pins, though. I've verified that the pins in question are not connected to anything they shouldn't be. They were floating when they were in the socket, and they're even more "floating" now that they're in open air. I follow strict ESD protocol; the desk is topped by a grounded ESD mat, and I always wear a grounded wrist strap. Any time anything needs to be transported, it's placed in an anti-static mylar envelope. I don't get this. I was using "INPUT_PULLUP" for the pin direction, but I've even added " mcp.pullUp(0, HIGH); // turn on a 100K pullup internally" statements, and it doesn't change. Port B is connected to a pair of analog switch ICs which allow me to have the code press buttons on a matrix keypad, and other pins on Port A are connected to things like optical sensor outputs, or switching the gates of FETs and they're all working fine with both ICs. This is on a test fixture I'm trying to get done very soon so it can be shipped to a vendor to test boards for us.

This is my first attempt at using the MCP IC and frankly I wish I'd never heard of it, but I'm kind of committed now. In the future I'm going to use an Arduino Mega 2560 as the basis for fixtures instead of the Nano I'm using now, just so I'll have more I/O without jumping through hoops like this. I can't even get the chip to work right with the "button" demo.

I wonder if these are related somehow?

https://community.particle.io/t/i2c-and ... -666/16323
https://microchipsupport.force.com/s/ar ... put-change

wrichman
 
Posts: 18
Joined: Fri Apr 12, 2019 11:29 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by adafruit_support_bill on Fri Sep 27, 2019 3:35 pm

Interesting. We use these chips in several of our boards and have not run into difficulties like that with them that I am aware of.

I'll run this by some of the other engineers.

adafruit_support_bill
 
Posts: 76213
Joined: Sat Feb 07, 2009 10:11 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by kcl1s on Fri Sep 27, 2019 4:24 pm

This line mcp.pinMode(mcpRedButton, INPUT_PULLUP); actually sets the pin as an output as the keyword INPUT_PULLUP has a value of 2 where the keyword INPUT has a value of 0. Since the library is doing a bitWrite with that passed value it interprets anything not 0 as a 1 which sets the pin to output.

Fellow hobbyist
Keith

kcl1s
 
Posts: 1459
Joined: Tue Aug 30, 2016 12:06 pm

Re: Easiest way to write to a single port of MCP23017 - i2c

by wrichman on Fri Sep 27, 2019 4:28 pm

kcl1s wrote:This line mcp.pinMode(mcpRedButton, INPUT_PULLUP); actually sets the pin as an output as the keyword INPUT_PULLUP has a value of 2 where the keyword INPUT has a value of 0. Since the library is doing a bitWrite with that passed value it interprets anything not 0 as a 1 which sets the pin to output.

Fellow hobbyist
Keith


So it's a bug in the library?

wrichman
 
Posts: 18
Joined: Fri Apr 12, 2019 11:29 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by kcl1s on Fri Sep 27, 2019 4:32 pm

No. Don't use INPUT_PULLUP use INPUT then mcp.pullUp on the next line as in the example.

Keith

kcl1s
 
Posts: 1459
Joined: Tue Aug 30, 2016 12:06 pm

Re: Easiest way to write to a single port of MCP23017 - i2c

by wrichman on Fri Sep 27, 2019 4:41 pm

adafruit_support_bill wrote:Interesting. We use these chips in several of our boards and have not run into difficulties like that with them that I am aware of.

I'll run this by some of the other engineers.


Since both chips seem to behave the same when installed on my board, but work correctly when on a breadboard wired to the same Nano I2C and power lines, I tried connecting the two inputs that are giving me problems in parallel to both the chip installed on the board and the one on the breadboard. Running this code, I get the following output when pushing the buttons that pull the inputs to ground. mcp is the chip on the board and mcp2 is the one on the breadboard. It almost looks like I'm running afoul of the current limitations which I seem to remember reading were a combination of current used to drive outputs (all a maximum of one TTL load or equivalent) and the current for the pull-ups...? Regardless of which IC is where, the one on the board always reads 00's whether or not the buttons are pressed, and the one on the breadboard reads 11's when neither button is pressed, and the expected 00, 01, 10, or 11 respectively with both pressed, one or the other pressed, and neither pressed. All the other I/O seems to work correctly on the MCP installed on my fixture board, so I have to guess that maybe I'm exceeding a current limit on the fully-wired chip somehow...? Maybe I'll just slap the second MCP chip on the board somewhere and use it just to read the buttons. Seems like a waste, but every single I/O pin (including the RX and TX lines and the LED pin) on the Nano are in use, as are all but the last two pins on the original MCP.

Code: Select all | TOGGLE FULL SIZE
15:18:34.543 -> mcp:00
15:18:34.577 -> mcp2:11
15:18:35.050 -> mcp:00
15:18:35.083 -> mcp2:11
15:18:35.557 -> mcp:00
15:18:35.591 -> mcp2:10
15:18:36.068 -> mcp:00
15:18:36.104 -> mcp2:01
15:18:36.544 -> mcp:00
15:18:36.578 -> mcp2:11
15:18:37.052 -> mcp:00
15:18:37.087 -> mcp2:11
15:18:37.557 -> mcp:00



Code: Select all | TOGGLE FULL SIZE
#include <Wire.h>
#include "Adafruit_MCP23017.h"

// Basic pin reading and pullup test for the MCP23017 I/O expander
// public domain!
Adafruit_MCP23017 mcp;
Adafruit_MCP23017 mcp2;

void setup() {
  Serial.begin(2400);
  mcp.begin(0);      // use default address 0
  mcp.pinMode(5, INPUT);
  mcp.pullUp(5, HIGH);  // turn on a 100K pullup internally
  mcp.pinMode(6, INPUT);
  mcp.pullUp(6, HIGH);  // turn on a 100K pullup internally

  mcp2.begin(1);      // use default address 0
  mcp2.pinMode(5, INPUT);
  mcp2.pullUp(5, HIGH);  // turn on a 100K pullup internally
  mcp2.pinMode(6, INPUT);
  mcp2.pullUp(6, HIGH);  // turn on a 100K pullup internally
}

void loop() {
  Serial.print("mcp:"); Serial.print(mcp.digitalRead(5)); Serial.println(mcp.digitalRead(6));
  Serial.print("mcp2:"); Serial.print(mcp2.digitalRead(5)); Serial.println(mcp2.digitalRead(6));
  delay(500);
}

wrichman
 
Posts: 18
Joined: Fri Apr 12, 2019 11:29 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by adafruit2 on Fri Sep 27, 2019 4:50 pm

i think start with one mcp chip, get that working perfectly the way you like - then add the second? its hard to debug when you have a lot going on :)

adafruit2
Site Admin
 
Posts: 19053
Joined: Fri Mar 11, 2005 7:36 pm

Re: Easiest way to write to a single port of MCP23017 - i2c

by wrichman on Fri Sep 27, 2019 4:55 pm

adafruit2 wrote:i think start with one mcp chip, get that working perfectly the way you like - then add the second? its hard to debug when you have a lot going on :)


The reason I'm adding the 2nd one is because the 1st one doesn't seem to want to play nice with the last two inputs. *facepalm*

wrichman
 
Posts: 18
Joined: Fri Apr 12, 2019 11:29 am

Re: Easiest way to write to a single port of MCP23017 - i2c

by wrichman on Fri Sep 27, 2019 4:57 pm

kcl1s wrote:No. Don't use INPUT_PULLUP use INPUT then mcp.pullUp on the next line as in the example.

Keith


I figured out what you were saying as I was adding the code for the buttons being connected to the 2nd MCP chip. *doh* The bug isn't in the library. It's between my ears! <.<

And incidentally, the buttons are reading correctly with the rest of the code and hardware loaded now that they're hanging off the second GPIO chip. Still don't know why, but at least I have a workaround. Thanks for your assistance. :)

wrichman
 
Posts: 18
Joined: Fri Apr 12, 2019 11:29 am

Please be positive and constructive with your questions and comments.