MCP23017 Port Expander giving false readings.

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I spend the day today fiddeling with a MCP23017 port expander on the i2c.

Im not getting consistent readings all the time and I do not really know how to get any progress.

 

Im usingt various arduinos, and the problem is consistent. When i read a port I get to many pins low.

 

The results could look like this: (Serial Output).

128 - 10000000
128 - 10000000
222 - 11011110
223 - 11011111
223 - 11011111
223 - 11011111
223 - 11011111
223 - 11011111
223 - 11011111
223 - 11011111
223 - 11011111
95 - 1011111

(123 was expected)

My Code Is:

#include <Wire.h>
byte inputs=0;

void setup()
{
 Serial.begin(9600);
 Wire.begin(); // wake up I2C bus
 Wire.write((byte)0x0c); // set all of bank B to inputs
 Wire.write(0x00); //enable pullup???
}
void loop()
{
 Wire.beginTransmission(0x20);
 Wire.write(0x12); // set MCP23017 memory pointer to GPIOB address
 Wire.endTransmission();
 Wire.requestFrom(0x20, 1); // request one byte of data from MCP20317
 inputs=Wire.read(); // store the incoming byte into "inputs"
 
 Serial.print(inputs);// print as normal int
 Serial.print(" - ");
 Serial.println(inputs, BIN); // display the contents of the GPIOB register in binary
 delay(200); // 
 }

 

If I change the dalay in last line to a shorter than 20 delay the error seems to go all beserk...

 

 

The schematich appears to be ok. A i2c scanner reports consistant connection.

Reset pin is tied to hidg, and i got pullup on the i2c.

 

I have tried with several arduinos and cables with the same results.

 

Im out of resistors so I have NUT tries to use pullups directly on the pins. 

 

ANy sugestions or ideas on what to try?

 

Peter

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Begin by posting a schematic or clear picture of your setup.

 

When using I2C, you must look at the return status of the call and look for errors and print them out.

That will guide you in troubleshooting bus problems.  Then carefully read the datasheet for the device and

verify you are sending commands / receiving data in the correct format.  Pay attention when reading data from an I2C device to NAK the last byte expected from the slave device

so it will release the bus back to the master and the master can then stop the bus properly.

 

Jim

 

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
Wire.write((byte)0x0c); // set all of bank B to inputs

bank B? Are you attempting to pullup and read from port A or port B, 0xc is GPPUA, the pullup control for port A.

 Wire.write(0x00); //enable pullup???

No, 0xff would enable pullup on all inputs.

 

 Wire.write(0x12); // set MCP23017 memory pointer to GPIOB address

No, 0x12 is GPIOA.

Do you have a different datasheet? I looked at this 

http://ww1.microchip.com/downloa...

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have no beginTrsnsmission or endTransmission in setup()
So you have no initialisation.
.
From memory, you can set the GPIOB port register and tell it not to increment.
Then you simply call requestFrom() continuously.
.
Print out the list of register addresses. It is easier to choose what initial is required.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Would this library and examples help?   https://github.com/adafruit/Adaf...

 

Jim

 

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do the I2C pins, both on the master side and on the peripheral side have pull=up resistors?

 

It takes more than the internal pull-up resistors in the micro. Typically in the low Kohm or less range.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Wed. Dec 27, 2017 - 10:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I followed my own advice.   Printed out the Register Summaries on paper.   My head still hurts.

 

Make your mind up what you want to do. e.g. 8-bit input port GPIOB with pullups.

 

Then choose BANK=1 and SEQOP=0.

 

You can set pullups with GPPUB @ 0x16,  and read GPIOB @ 0x19 (continuously)

 

You can do it with BANK=0 if you want.  GPPUB @ 0x0D, GPIOB @ 0x13.

 

Somehow,   I don't think you have decided whether you want to use GPIOA or GPIOB.

I strongly recommend printing the Register Summaries.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This chip I2C errata is pretty old & likely not for you, but double-check what chip rev you have...there could be other chip errata as well...I spent some time fiddling with a PIC uart , only to find one of the status bits was inoperable (errata).

 

http://ww1.microchip.com/downloads/en/DeviceDoc/80252A.pdf

 

 

When in the dark remember-the future looks brighter than ever.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

peterlemans844 wrote:

void setup()

{
 Serial.begin(9600);
 Wire.begin(); // wake up I2C bus
 Wire.write((byte)0x0c); // set all of bank B to inputs
 Wire.write(0x00); //enable pullup???
}

 

Surely this is wrong? You are not sending the device id before trying to configure it.

 

For reference, this is from working, production, code.

 

SEE BELOW FOR CORRECT VERSION

void switch_read(void)
{

	uint8_t portb;
	uint8_t porta;

    i2c_start();
    i2c_write(0x40);		//slave id, write mode
    i2c_write(0x12);		//GPIOA
    i2c_start();
    i2c_write(0x41);		//slave id, read mode
    porta = i2c_read(0);	//read A inputs
    i2c_stop();

    i2c_start();
    i2c_write(0x40);		//slave id, write mode
    i2c_write(0x13);		//GPIOB
    i2c_start();
    i2c_write(0x41);		//slave id, read mode
    portb = i2c_read(0);	//read B inputs
    i2c_stop();

    gSwitch2 = (portb & 0x07);
    mode = gSwitch2 + 1;

    gSwitch1 = ((portb & 0xf0) >> 4) + (porta << 4);
}

 

"This forum helps those that help themselves."

"How have you proved that your chip is running at xxMHz?" - Me

"If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

Last Edited: Thu. Dec 28, 2017 - 09:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Brian,

 

I am well confused.  Table 1-4 and Table 1-6 clearly show reg(0x0C) as GPPUA (BANK=0)

 

Your code will work because at Power-Up BANK=0 and both ports are input.

And reading 0x12 (GPIOA) and 0x13 (GPIOB) will give you the 16-bit state.

 

You could enable SEQOP in reg(0x05) IOCON.

Then read both ports sequentially.  i.e. start(0x40), write(0x12), restart(0x41), porta = read(1), portb = read(0), stop()

 

Untested.   I have never seen a MCP23017 chip.

 

The sequential mode is useful for 16-bit operations.   Non-sequential is good for 8-bit operations.

It powers up with sequential (16-bit friendly) registers but default SEQOP=0.

 

It is not that complicated but it still makes my head hurt.

A minimal 16-bit read is SWSRRP i.e. 450us on 100kHz bus.

A minimal 8-bit read is SRP i.e. 180us  (after you have set the register SWP as a one-off)

 

You don't gain much with the SEQOP if you are doing 16-bit read operations.  i.e. 450us versus 720us

With 16-bit writes it would be SWWWP vs SWWP, SWWP i.e. 360us vs 540us

 

Oh,  and the MCP23017 can run at 100kHz, 400kHz or 1.7MHz.    The PCF8574 is limited to 100kHz.

 

David.

Last Edited: Thu. Dec 28, 2017 - 09:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

I am well confused.  Table 1-4 and Table 1-6 clearly show reg(0x0C) as GPPUA (BANK=0)

 

Sorry, my comments are wrong. I cut-and-pasted this from a customers project and in updating the comments I picked up the wrong set. Let's try again...

 

void switch_init (void)
{
	i2c_start();
    i2c_write(0x40);		//slave id, write mode
    i2c_write(0x0c);		//GPPUA, pull-up for Port A
    i2c_write(0xff);		//all pins with pull-ups
    i2c_stop();

	i2c_start();
    i2c_write(0x40);		//slave id, write mode
    i2c_write(0x0d);		//GPPUB, pull up for Port B
    i2c_write(0xff);		//all pins with pull-ups
    i2c_stop();
}

 

"This forum helps those that help themselves."

"How have you proved that your chip is running at xxMHz?" - Me

"If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Forum

Thank you all for your help.

With your help, a little sleep and a printed datasheet it now works just fine.

My hardware was fine, bur i forgot to pullup on the pins (in software). Also i made mistakes on initialising my chip.

It works now and I really learned a lot.

 

Thank you a lot.

 

Peter