Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pinMode() behavior seems to differ from pinMode8(). #9

Closed
federico77 opened this issue Jun 19, 2023 · 33 comments
Closed

pinMode() behavior seems to differ from pinMode8(). #9

federico77 opened this issue Jun 19, 2023 · 33 comments
Assignees
Labels
question Further information is requested

Comments

@federico77
Copy link

Hello gents, I am testing this library before using in my project and I am having a problem that seems silly but I can't get my head around it.

What I see is that the digitalRead(pin) example works perfectly when using pinMode8(0x00). On the reverse, when I am using the single pin methods and setting each pin individually with:

MCP.pinMode(0, INPUT);

the resulting digitalRead(pin) is always 1 as return value. Curiously enough, if I set the pinMode as OUTPUT, everything works as expected.

At this point I am not sure if there is something crooked with the library code or if I am doing something wrong (mistunderstanding or problems with my schematics).

Although I believe it is not related, I am using a chip identified as 0x22 on I2C and I also have a 0x21 on the same bus.

Can you please helpme to find out what is going on here?

@RobTillaart
Copy link
Owner

RobTillaart commented Jun 19, 2023

Thanks for filing the issue,
It is rather late now, so I will come back later this week.

(labelled it as question for now)

@RobTillaart RobTillaart self-assigned this Jun 19, 2023
@RobTillaart RobTillaart added the question Further information is requested label Jun 19, 2023
@RobTillaart
Copy link
Owner

RobTillaart commented Jun 19, 2023

Can you print the return value of bool b = mcp.pinMode(0, INPUT); in your project?

If it returns false there is something wrong.

snippet

bool b = mcp.pinMode(0, INPUT);
serial.println(b);
serial.println(mcp.lastError());

@federico77
Copy link
Author

Hello, thanks for the quick feedback.
b=1, lastError=0

Also, maybe just partially related, I noticed that both digitalWrite() and digitalRead() examples report the same values for pinMode8().

As a reference I have 2x MCP23008 on the same I2C bus: GPIs are controlled (read) by one chip; relays are controlled (write) by the other chip. All GPI pins are on an open circuit, when closed, the GPI pin connects to a 5v source.

@RobTillaart
Copy link
Owner

RobTillaart commented Jun 20, 2023

I have to dive into the datasheet, to refresh the mind about this chip / library.

image

@RobTillaart
Copy link
Owner

What I see is that the digitalRead(pin) example works perfectly when using pinMode8(0x00).

So if you set all lines to OUTPUT digitalRead(pin) does work as it should with INPUT.

Do you have pull up resistors on the IO-lines?

You can set them with

mcp.setPullup8(0xFF);
or
mcp.setPullup(pin, true);

@RobTillaart
Copy link
Owner

Check of the code in the library did not reveal a bug so far when writing 1's for INPUT and 0's for OUTPUT.
To be continued later.

@federico77
Copy link
Author

So, to summarize the behavior I see when I have pin0 triggered:

All pins methods show the following:

MCP.pinMode8(0x00);
MCP.setPullup8(0xFF);

Console returns: 1 0 0 0 0 0 0 0

Single pin methods:

MCP.pinMode(pin, INPUT);
MCP.setPullup(pin, true);

Console returns: 1 1 1 1 1 1 1 1

As said, still with the single pins methods:

MCP.pinMode(pin, OUTPUT);
MCP.setPullup(pin, true);

Console returns: 1 0 0 0 0 0 0 0

For further reference: I am using an Arduino Uno board for this kind of tests but the final plaform will use ESP32.
I had the same results with Arduino IDE 1.8.9 and with VisualStudio/Platformio.

@RobTillaart
Copy link
Owner

Can you post your test sketch so I understand what is happening (maybe).
I have no spare mcp23008 so I cannot test myself unfortunatelly

@RobTillaart
Copy link
Owner

RobTillaart commented Jun 20, 2023

can you add the following (debug) function to mcp23008.h,
That allows us to see if the data direction register is set correctly with pinMode.

uint8_t getPinMode8()
{
  uint8_t value = readReg(0);
  Serial.println(value, HEX);
  return value;
}

I'll make a develop branch asap which includes this function later.

@RobTillaart
Copy link
Owner

RobTillaart commented Jun 20, 2023

develop branch made - https://github.com/RobTillaart/MCP23008/tree/develop
It includes a debug function getPinMode8() to read back the set pinMode + a test sketch.

(build successful)

@federico77
Copy link
Author

Dude, you're awesomely fast. :) I will probably need some more time later today to test it and provide a feedback.
Thanks!!

@federico77
Copy link
Author

Nevermind, i had a few minutes to spare.
With your test sketch and the dev branch lib, results are the following (pin 8 is supposed to be triggered):

MCP23008_test version: 0.1.4
0
FF

FE
FC
F8
F0
E0
C0
80
0

1
3
7
F
1F
3F
7F
FF

FE
FC
F8
F0
E0
C0
80
0

1
3
7
F
1F
3F
7F
FF

@RobTillaart
Copy link
Owner

They all return what was expected ==> OK,
so the DDRA register is set correctly by both pinMode() and pinMode8() functions.

So next test is testing digitalRead(). I will add some code to the test-sketch

@RobTillaart
Copy link
Owner

digital read test added, please give it a try

@federico77
Copy link
Author

federico77 commented Jun 20, 2023

Thanks a lot for the effort Rob. So the results in this case are:

MCP23008_test version: 0.1.4
0
FF

FE
FC
F8
F0
E0
C0
80
0

1
3
7
F
1F
3F
7F
FF

FE
FC
F8
F0
E0
C0
80
0

1
3
7
F
1F
3F
7F
FF

FF
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111111

I have checked the Adafruit 23017 library meanwhile and spotted this:
[Issue 56](adafruit/Adafruit-MCP23017-Arduino-Library#56)

I'm getting super confused right now but I have a bad feeling about how I wired the GPIO right now (I'm quite noob at electronics), maybe you can confirm my assumptions: so I basicallly have the button connected to 5v and to the MCP pin as I was expecting the pin to be "ground". Is that correct?

To clarify the last point: if I setPolarity8(0xFF) my digitalRead() results are 00000000 which makes more sense... sadly it does not seem to recognize the pin7 being closed...

@federico77
Copy link
Author

So... sorry to be so verbose but I had a bit of an epiphany:

  MCP.pinMode8(0x00);
  MCP.setPullup8(0xFF);
  MCP.setPolarity8(0xFF);

This works perfectly and my digitalRead() calls return what I expect, that is: 0 0 0 0 0 0 0 1

The following, sadly, does not, as it sets open GPI to 0 but digitalRead() never sees the closed GPI returning: 0 0 0 0 0 0 0 0

  for (int pin = 0; pin < 8; pin++)
  {
    MCP.pinMode(pin, INPUT);
    MCP.setPullup(pin, true);
    MCP.setPolarity(pin, true);
  }

MCP.setPolarity(pin, false); indeed shows all pins to 1 on digitalRead()

@RobTillaart
Copy link
Owner

RobTillaart commented Jun 20, 2023

The adafruit issue should not be a problem in the pinMode code
I only compare the values INPUT, OUTPUT and INPUT_PULLUP, not using them as parameter.

However if the parameter does not match anything nothing is changed....
but the function would return false!

bool MCP23008::pinMode(uint8_t pin, uint8_t mode)
{
  if (pin > 7)
  {
    _error = MCP23008_PIN_ERROR;
    return false;
  }
  if ((mode != INPUT) && (mode != INPUT_PULLUP) && (mode != OUTPUT))   <<<<<<<<<<< just compare
  {
    _error = MCP23008_VALUE_ERROR;
    return false;
  }

  uint8_t dataDirectionRegister = MCP23008_DDR_A;
  uint8_t val = readReg(dataDirectionRegister);
  if (_error != MCP23008_OK)
  {
    return false;
  }
  uint8_t mask = 1 << pin;
  //  only work with valid
  if ((mode == INPUT) || (mode == INPUT_PULLUP))     <<<<<<<<<<< just compare
  {
    val |= mask;
  }
  else if (mode == OUTPUT)     <<<<<<<<<<< just compare
  {
    val &= ~mask;
  } 
  //  other values won't change val ....
  writeReg(dataDirectionRegister, val);
  if (_error != MCP23008_OK)
  {
    return false;
  }
  return true;
}

have to attend another task, to be continued.

@RobTillaart
Copy link
Owner

mmm, can you check what mcp.pinmode(0, INPUT); returns?
true or false?

@federico77
Copy link
Author

federico77 commented Jun 20, 2023

Result of .pinMode() is 1 (so, true)

@federico77
Copy link
Author

Hello @RobTillaart, have you had a chance to further look into this?

@RobTillaart
Copy link
Owner

I have cross checked the code with the MCP23017 which is a 16 channel and those match.
Have no MCP23008 hardware to test in practice.

Had also a look at the Adafruit library which works very similar (same steps).
Only differences are

  • it sets the pullup explicitly, see snippet below
  • it does not have a pinMode8()

https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/src/Adafruit_MCP23XXX.cpp

void Adafruit_MCP23XXX::pinMode(uint8_t pin, uint8_t mode) {
  Adafruit_BusIO_Register IODIR(i2c_dev, spi_dev, MCP23XXX_SPIREG,
                                getRegister(MCP23XXX_IODIR, MCP_PORT(pin)));
  Adafruit_BusIO_Register GPPU(i2c_dev, spi_dev, MCP23XXX_SPIREG,
                               getRegister(MCP23XXX_GPPU, MCP_PORT(pin)));
  Adafruit_BusIO_RegisterBits dir_bit(&IODIR, 1, pin % 8);
  Adafruit_BusIO_RegisterBits pullup_bit(&GPPU, 1, pin % 8);

  dir_bit.write((mode == OUTPUT) ? 0 : 1);
  pullup_bit.write((mode == INPUT_PULLUP) ? 1 : 0);   <<<<<<<<<<<<<<<
}

Setting the pullup should not cause your problems as the working pinMode8() does not set them either and that call works.

So I found no clues in the library code that explain your problem.

Is it possible for you to do a test with the Adafruit libray, see if their input example works?

@RobTillaart
Copy link
Owner

@federico77
As far as I have investigated I could not find a cause in my library. Therefor I ordered two MCP23008 to redo the testing of the library. At least it will allow me to either recreate your problem or verify the library is OK.
To be continued.

@RobTillaart
Copy link
Owner

@federico77

Is it possible for you to do a test with the Adafruit libray, see if their input example works?

Did you test with the Adafruit library?

@RobTillaart
Copy link
Owner

RobTillaart commented Jul 6, 2023

@federico77

I have ordered two MCP23008 to redo input and output tests.
They came in yesterday and I spend whole morning doing tests to see if I could replicate your problem.

Arduino UNO
IDE 1.8.19
sketch: MCP23008_digitalWrite.ino and MCP23008_digitalRead.ino (slightly modified to generate more output)
No external pullups used.

tested

  • pinMode() pinMode8(), both with INPUT and INPUT_PULLUP
  • digitalRead() digitalRead8(), digitalWrite(), digitalWrite8()

No problems found so far.

@RobTillaart
Copy link
Owner

Points of attention

  • needed to connect the RESET pin to 5V to have the MCP23008 working.

@RobTillaart
Copy link
Owner

RobTillaart commented Jul 6, 2023

rereading the whole thread

As a reference I have 2x MCP23008 on the same I2C bus: GPIs are controlled (read) by one chip; relays are controlled (write) by the other chip. All GPI pins are on an open circuit, when closed, the GPI pin connects to a 5v source.

The GPI should have a PULLDOWN resistor (1-10 KΩ ) if you have a switch to 5v.
You should not let it "float" as that can cause undefined states.

MCP.setPullup8(0xFF); will only enable pull ups.
disabling pull ups does not imply enabling pull downs

@RobTillaart
Copy link
Owner

I'm quite noob at electronics

This book (you can skip a lot of math) might be helpful (at least it helped me to fill gaps)

https://www.amazon.com/Practical-Electronics-Inventors-Fourth-Scherz/dp/1259587541/ref=sr_1_1

@RobTillaart
Copy link
Owner

@federico77
is this still an issue?

@federico77
Copy link
Author

Hello Rob, I really appreciate your effort with this topic. I have been on holiday recently hence I was a bit absent, I apologize for that. Let me answer to the various points you wrote in the thread:

  • RESET pin to 5V to have the MCP23008 working: done. All chips are correctly recognized by microcontroller.
  • Pulldowns. Sadly my GPI pins are floating right now (I haven't thought about it), so I will need to run tests with resistors (one per pin I assume). On these regards what worries me is that behavior seems correct when all pins are set with a single pinMode8() compared to several pinMode().
  • Thanks for the link to the book, I'm looking for the same book distributed from Amazon IT.

Will let you know how it goes with the tests as soon as I have the opportunity.

Meanwhile I really thank you for your help.

@RobTillaart
Copy link
Owner

Hope you enjoyed your holiday!

The book might be cheaper at other bookstores, Amazon has a lot of books but not always best price. The previous version is almost the same but might be way cheaper.

I could not replicate the pinMode() problem so I wait for your tests.

@federico77
Copy link
Author

Hey Rob, once again tanks a lot for your help. I tested the library by adding 10k resistors to ground on each GPI pin and now I have more consistent results so I believe it all comes down to my poor design... :(

I'll keep testing the various pins configurations but I believe the library is not guilty.

PS: I bought the book.

@RobTillaart
Copy link
Owner

OK, if you think it is solved you may close the issue.

PS: I bought the book.

👍 Have fun reading it, it has some serious math, but most is explained very well.

@RobTillaart
Copy link
Owner

I released the 0.1.4 with the getPinMode() added
So I close this issue for now, if needed feel free to reopen it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants