Issue #80 resolved
RB
created an issue

I think there is a problem in I2CIO::read() function. T PCF8574 wont correctly work with input pin. According the datasheet, each input pin have to be kept HIGH at any write. The function writes 0 to each input and it doesn' work. With the below fix it works as expected.

I'm using your lib for years so it is my two cents. Thank you!

Robert Badar (aka budvar10)

vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

// // write int I2CIO::write ( uint8_t value ) { int status = 0;

if ( _initialised ) { // Only write HIGH the values of the ports that have been initialised as // outputs updating the output shadow of the device // // 15-FEB-2018 - fix, all I/Os initialized as input must be written as HIGH

// _shadow = ( value & ~(_dirMask) ); _shadow = ( value | _dirMask );

  Wire.beginTransmission ( _i2cAddr );

if (ARDUINO < 100)

  Wire.send ( _shadow );

else

  Wire.write ( _shadow );

endif

  status = Wire.endTransmission ();

} return ( (status == 0) ); }

Comments (15)

  1. Francisco Malpartida repo owner

    Hi Robert, thanks for pointing this out.

    One question, you mention that there is a problem with the I2CIO read method, however, you are making an update the write method in the I2CIO?

    Please clarify.

  2. RB reporter

    Yes, exactly the write.

    To define which I/O is input, appropriate I/O have to be set (write 1) and must be kept set the whole time, it means each write must be 1 to each input pin. See e.g. the PCF8574; PCF8574A datasheet (rev.5 -27 MAY2013) from NXP, page 13-14. In your lib the write function always write 0 to inputs. The 0 at inputs does not mean there is written nothing, like imply in the comment. There is also an explanation on page 7: Input HIGH, Input LOW.

    My real testing is as follows (all inputs are pulled up): 1. If 0 is written to the I/O. The 0 will be read whether is pulled up or connected to GND. Only hard connection to VCC (pull-up resistance less than 50ohm at Vcc = 5V! ) cause that it will read 1. 2. If 1 is written to the i/O. The 1 will be read if pulled-up of even not connected. The 0 will be read in it will be connected to GND or pulled-down with significantly smaller resistance.

    The I/Os are bidirectional and it means that there is no difference between input and output from outside. All functionality is "hidden" in the circuit. The write operation can write only to all pins together. It is impossible to distinguish which pin is written and which one not. In the same time I have to mention that the documentation is not absolutely clear, for me at least. I read the datasheeet from PHILIPS (very old), Texas. All wrote "The I/Os should be HIGH before being used as inputs." but they must be HIGH. Finally in the NXP I found exact example.

    It should work also with writing the direction mask just before read inside of read(), but inside of write function it produce more effective code. I tested proposed change and it worked for me just fine. My testing device had LCD with PCF8574 and 3 other PCF's used as general I/Os.

  3. RB reporter

    I've created the branch. Not sure if it is according your perception since I'm new here on bitbucket. I found same problem in several discussions on the internet.

    Thank you for excellent library and for your effort to keep it maintained.

  4. RB reporter

    Not correct, The I2CIO::write seems to be without change. Only I2CIO::digitalWrite was changed. I2CIO::write is still incorrect with

     _shadow = ( value & ~(_dirMask) );
    
  5. Francisco Malpartida repo owner

    Is the write method the only one you have changed as follows:

          // Only write HIGH the values of the ports that have been initialised as
          // outputs updating the output shadow of the device
          //
          // 15-FEB-2018 - fix, all I/Os initialized as input must be written as HIGH
    
    //    _shadow = ( value & ~(_dirMask) );
          _shadow = ( value | _dirMask );
    

    The digitalWrite method can't be processed as you have shared it since value is not present in the method.

    This is very odd as I have been using these routines for a long, long time without a glitch.

  6. RB reporter

    Hm, I am little bit confused. I can see green/pink highlighted difference in side by side comparison of sources. This is in I2CIO::write() function. Here is complete I2CIO::write() working code (value is a parameter):

    //
    // write
    int I2CIO::write ( uint8_t value )
    {
       int status = 0;
    
       if ( _initialised )
       {
          // Only write HIGH the values of the ports that have been initialised as
          // outputs updating the output shadow of the device
          //
          // 15-FEB-2018 - fix, all I/Os initialized as input must be written as HIGH
    
    //    _shadow = ( value & ~(_dirMask) );
          _shadow = ( value | _dirMask );
    
          Wire.beginTransmission ( _i2cAddr );
    #if (ARDUINO <  100)
          Wire.send ( _shadow );
    #else
          Wire.write ( _shadow );
    #endif  
          status = Wire.endTransmission ();
       }
       return ( (status == 0) );
    }
    

    Lines 154-156. https://bitbucket.org/fmalpartida/new-liquidcrystal/pull-requests/9/issue-80-i2ciocpp-incorrect-pcf8574-i-o-as/diff The ::digitalWrite is going throughout the ::write, so no change is needed in digitalWrite. Please try to check it again.

  7. RB reporter

    Something wrong with my browser? I've check it again with IE instead of Firefox (I'm using latest) and I can see the problem in my source. There is change in ::write but some conflict in ::digitalWrite. Weird... I corrected my source, but did not create a new pull-request. In any case, the int I2CIO::write ( uint8_t value ) need to be changed as in the post above. Written value have to have '1' at all bits for inputs. Not '0'. Sorry for any misunderstanding.

  8. Log in to comment