PCA9655E I/O expander question

Status
Not open for further replies.

wolfv

Well-known member
This is more of I/O expander question than a Teensy question. Please tell me if there is a better place to post this question.

I read some I/O expander tutorials and the datasheet but am still easily surprised by I/O expander behavior.
This is the most resent surprise:

A PCA9655E I/O expander is connected to a Teensy 2.0 via I2C.
PCA9655E I/O expander is on the left and Teensy 2.0 on the right:
PCA9655E_test_bb2.png
There is nothing connected to the PCA9655E port pins.

When I run the sketch:
1110 is output to port 0.
1110 is read from port 1.​
How did data get from port 0 to port 1?
There is nothing connected to the port pins.
Code:
#include "Wire.h"

const uint8_t ADDR  = 0x20;                     //PCA9655E I2C address with AD2 AD1 AD0 grounded

void setup()
{
    Wire.begin();

    //configure output
    Wire.beginTransmission(ADDR);
    Wire.write(6);                              //command byte 6: configure port 0
    Wire.write(B00000000);                      //0=output, 1=input with pullup
    Wire.endTransmission();

    //configure input
    Wire.beginTransmission(ADDR);
    Wire.write(7);                              //command byte 7: configure port 1
    Wire.write(B11111111);                      //0=output, 1=input with pullup
    Wire.endTransmission();
}

void loop()
{
    //output
    Wire.beginTransmission(ADDR);
    Wire.write(2);                              //command byte 2: output port 0
    Wire.write(B00001110);                      //0=low, 1=high
    Wire.endTransmission();

    //input to read
    Wire.beginTransmission(ADDR);
    Wire.write(1);                              //command byte 1: input port 1
    Wire.endTransmission();

    //read input
    Wire.requestFrom(ADDR, static_cast<uint8_t>(1)); //request one-byte read

    //display read
    Serial.print("\nport1 = ");                 //port1 = 1110
    Serial.print(Wire.read(), BIN);

    while (true) {}
}
Output:
Code:
port1 = 1110
I am using Teensy 2.0, Arduino 1.0.6, and Teensyduino 1.20.
The PCA9655E data sheet is on http://www.onsemi.com/pub_link/Collateral/PCA9655E-D.PDF
Wire class is on http://arduino.cc/en/Reference/Wire

Thank you.
 
Code:
const uint8_t ADDR  = 0x20;                     //PCA9655E I2C address with AD2 AD1 AD0 grounded

should the Address not be 0x40 (A0,A1,A2) grounded and 0x20 for (GND,SCL,GND)?

also you could try to put input port to GND and see what you read
 
Thanks for the suggestion WMXZ.

The Wire library shifts the 0x20 ADDR left one bit (giving 0x40) and then ors in 0 or 1 for write or read.
This was confirmed by another sketch that worked.

I tried grounding pin 0 of port 1 and got the same result.
Same for grounding pin 1 of port 1.

So I am still stuck. Your suggestions are appreciated.
 
Thanks for the suggestion WMXZ.

The Wire library shifts the 0x20 ADDR left one bit (giving 0x40) and then ors in 0 or 1 for write or read.
This was confirmed by another sketch that worked.

I tried grounding pin 0 of port 1 and got the same result.
Same for grounding pin 1 of port 1.

So I am still stuck. Your suggestions are appreciated.

Unfortunately, I'm not using Wire or AVR, so I 'm not of great help.
 
you might need to test for Wire.available() before doing your Wire.read().
data sheet says pins are pulled high, so default input value for unconnected pin will be 1
 
Hi manitou.

I added Wire.available() as you suggested, it shows 1 byte available for reading as expected.

main loop:
Code:
void loop()
{
    //output
    Wire.beginTransmission(ADDR);
    Wire.write(2);                              //command byte 2: output port 0
    Wire.write(B00001110);                      //0=low, 1=high
    Wire.endTransmission();

    //input to read
    Wire.beginTransmission(ADDR);
    Wire.write(1);                              //command byte 1: input port 1
    Wire.endTransmission();

    //read input
    Wire.requestFrom(ADDR, static_cast<uint8_t>(1)); //request one-byte read

    //display bytes available for reading
    Serial.print("\nbytes available for reading=");
    Serial.print(Wire.available());

    //display read
    Serial.print("\nport1 = ");                 //port1 = 1110
    Serial.print(Wire.read(), BIN);

    while (true) {}
}
Output:
Code:
bytes available for reading=1
port1 = 1110

Since the pins are pulled high, and the port pins are not connected to anything, I am expecting port 1 to read 11111111.
But the port 1 reading is 00001110, which is the value of the port 0.
How did data get from port 0 to port 1?:confused:
 
Output:
Code:
bytes available for reading=1
port1 = 1110

Since the pins are pulled high, and the port pins are not connected to anything, I am expecting port 1 to read 11111111.
But the port 1 reading is 00001110, which is the value of the port 0.
How did data get from port 0 to port 1?:confused:

Can you verify that port1 seen all different words you sent to port 0?
e.g. looping from 00 to FF
 
Can you verify that port1 seen all different words you sent to port 0?
e.g. looping from 00 to FF

Port1 sees all different bits sent to port 0.

main loop:
Code:
void loop()
{
    for (uint8_t pin = 1; pin > 0; pin = pin << 1)
    {
        //output
        Wire.beginTransmission(ADDR);
        Wire.write(2);                              //command byte 2: output port 0
        Wire.write(pin);                            //0=low, 1=high
        Wire.endTransmission();

        //input to read
        Wire.beginTransmission(ADDR);
        Wire.write(1);                              //command byte 1: input port 1
        Wire.endTransmission();

        //read input
        Wire.requestFrom(ADDR, static_cast<uint8_t>(1)); //request one-byte read

        //display read
        Serial.print("\nport1 = ");
        Serial.print(Wire.read(), BIN);
    }

    while (true) {}
}
output:
Code:
port1 = 1
port1 = 10
port1 = 100
port1 = 1000
port1 = 10000
port1 = 100000
port1 = 1000000
port1 = 10000000
 
Last edited:
Port1 sees all different bits sent to port 0.

main loop:
Code:
void loop()
{
    for (uint8_t pin = 1; pin > 0; pin = pin << 1)
    {
        //output
        Wire.beginTransmission(ADDR);
        Wire.write(2);                              //command byte 2: output port 0
        Wire.write(pin);                            //0=low, 1=high
        Wire.endTransmission();

        //input to read
        Wire.beginTransmission(ADDR);
        Wire.write(1);                              //command byte 1: input port 1
        Wire.endTransmission();

        //read input
        Wire.requestFrom(ADDR, static_cast<uint8_t>(1)); //request one-byte read

        //display read
        Serial.print("\nport1 = ");
        Serial.print(Wire.read(), BIN);
    }

    while (true) {}
}
output:
Code:
port1 = 1
port1 = 10
port1 = 100
port1 = 1000
port1 = 10000
port1 = 100000
port1 = 1000000
port1 = 10000000

what happens if you read always two or four bytes (it should toggle between port 0 and port1)?
 
Thanks for the suggestion WMXZ.

The Wire library shifts the 0x20 ADDR left one bit (giving 0x40) and then ors in 0 or 1 for write or read.
This was confirmed by another sketch that worked.

Did you try simply putting 0x40 into your program? From the datasheet's table on page 7, that really does look like the address for your wiring diagram.
 
what happens if you read always two or four bytes (it should toggle between port 0 and port1)?

Also you could try
Code:
Wire.endTransmission(false);
to avoid the stop between writing the command byte and the read
 
solved

Thanks Paul, for your suggestion. But I think WMXZ figured it out.

output with Wire.endTransmission(false):
Code:
port1 = 11111111
port1 = 11111111
port1 = 11111111
port1 = 11111111
port1 = 11111111
port1 = 11111111
port1 = 11111111
port1 = 11111111

It makes sense after reading the PCA9655E datasheet and Arduino reference:

Reading the Port Registers
After a restart, the device address must be sent again, but this time, the least significant bit is set to logic 1.
Data from the register defined by the command byte will then be sent by the PCA9655E.
http://www.onsemi.com/pub_link/Collateral/PCA9655E-D.PDF

Wire.endTransmission() Parameters stop : boolean.
true will send a stop message, releasing the bus after transmission.
false will send a restart, keeping the connection active.
http://arduino.cc/en/Reference/WireEndTransmission

The Arduino library automatically takes care of things, if the parameters are just right.

Thanks for your help WMXZ.:)

Here is the full code running as expected:
Code:
const uint8_t ADDR  = 0x20;                     //PCA9655E I2C address with AD2 AD1 AD0 grounded

void setup()
{
    Wire.begin();

    //configure output
    Wire.beginTransmission(ADDR);
    Wire.write(6);                              //command byte 6: configure port 0
    Wire.write(B00000000);                      //0=output, 1=input with pullup
    Wire.endTransmission();

    //configure input
    Wire.beginTransmission(ADDR);
    Wire.write(7);                              //command byte 7: configure port 1
    Wire.write(B11111111);                      //0=output, 1=input with pullup
    Wire.endTransmission();
}

void loop()
{
    for (uint8_t pin = 1; pin > 0; pin = pin << 1)
    {
        //output
        Wire.beginTransmission(ADDR);
        Wire.write(2);                              //command byte 2: output port 0
        Wire.write(pin);                            //0=low, 1=high
        Wire.endTransmission();

        //input to read
        Wire.beginTransmission(ADDR);
        Wire.write(1);                              //command byte 1: input port 1
        Wire.endTransmission(false);

        //read input
        Wire.requestFrom(ADDR, static_cast<uint8_t>(1)); //request one-byte read

        //display read
        Serial.print("\nport1 = ");
        Serial.print(Wire.read(), BIN);
    }

    while (true) {}
}
 
Status
Not open for further replies.
Back
Top