adafruit / Adafruit_PCF8574

Arduino library for Adafruit PCF8574 & PCF8575 GPIO expander
Other
10 stars 9 forks source link

PCF8574 dynamic allocation error? #8

Closed TouCam4 closed 3 months ago

TouCam4 commented 3 months ago

My skecth is:

#include <Adafruit_PCF8574.h>

Adafruit_PCF8574 *pPCF;

void setup() {
  while (!Serial) 
   delay(100);
  Serial.begin(115200);
  Serial.println("Adafruit PCF8574 LED blink test");

  if (!pPCF->begin(0x20, &Wire)) {
    Serial.println("Couldn't find PCF8574");
    while (1);
  }
  pPCF->pinMode(7, OUTPUT);
  pinMode(13, OUTPUT);
}

void loop() {
  pPCF->digitalWrite(7, LOW);
  digitalWrite(13, HIGH);
  delay(500);
  pPCF->digitalWrite(7, HIGH);
  digitalWrite(13, LOW);
  delay(500);
}

The led does not blink now.

Is it possible to do as I do? Maybe a syntax mistake?

Thank you in advance.

caternuson commented 3 months ago

It may be possible, but these issues are not for general tech support for library code modification. Issues posted here should be demonstrable with the library code as is.

TouCam4 commented 3 months ago

I solved the problem. Please see the attached text file. It about some issues and is free for you.

Thank you

De: Carter Nelson @.> Enviado el: lunes, 15 de julio de 2024 16:47 Para: adafruit/Adafruit_PCF8574 @.> CC: TouCam4 @.>; Author @.> Asunto: Re: [adafruit/Adafruit_PCF8574] PCF8574 dynamic allocation error? (Issue #8)

It may be possible, but these issues are not for general tech support for library code modification. Issues posted here should be demonstrable with the library code as is.

— Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_PCF8574/issues/8#issuecomment-2228683357 , or unsubscribe https://github.com/notifications/unsubscribe-auth/BHU4UZUJYHO3UMV3XYZMONLZMPOHVAVCNFSM6AAAAABK3D2TQWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMRYGY4DGMZVG4 . You are receiving this because you authored the thread. https://github.com/notifications/beacon/BHU4UZUFB7GVSD6TOKEXJULZMPOHVA5CNFSM6AAAAABK3D2TQWWGG33NNVSW45C7OR4XAZNMJFZXG5LFINXW23LFNZ2KUY3PNVWWK3TUL5UWJTUE24BF2.gif Message ID: @. @.> >

-- Este correo electrónico ha sido analizado en busca de virus por el software antivirus de AVG. www.avg.com I have been able to make my example program work ok creating Adafruit_PCF8574 instances using the "new" dynamic method. To achieve this I detected and corrected 2 problems in your PCF8574 library:

1) About Adafruit_PCF8574::begin:

/*!

i2c_dev has not been initialized, and delete (i2c_dev) may corrupt the program, as happened to me when in instance of Adafruit_PCF8574 is dinamically created using "new".

i2c_dev is a private variable. If delete (i2c_dev) is trying to avoid a problem if the user calls Adafruit_PCF8574::begin two or more times, i2c_dev should be initialized to NULL. I suggest to do this at i2c_dev declaration.

2) As said in the PCF8574 datasheet, "At power on, the I/Os are high.". So the hardware attached to the I/Os MUST be designed to work ok under this requirement.

The PCF8574 does not really have any pinMode internal register, one must simply write to the device a suitable value to allow later correct read/write mode.

When Adafruit_PCF8574::pinMode is called, the _writebuf variable has not been initialized. Even if it could be the first time this variable is used, the compiler may have initialized _writebuf to 0.

This means that in a call to Adafruit_PCF8574::pinMode, the pinnum and val parameters will be used to set the correct BIT value to _writebuf for the pinnum I/O, but WILL LEAVE THE OTHER _writebuf BITS TO 0.

Even if later the Adafruit_PCF8574::pinMode is called to set the correct value for the other I/Os, there WILL be meanwhile a GLITCH problem at startup. This may be a disaster, depending what is connected to the physical port (I'm thinking about water electrovalves).

I believe the solution is easy:

Declare a new variable, let's say _pinModes and initialize it as:

uint8_t _pinModes = 0xFF;

or declare it like this:

uint8_t _pinMode;

and initialize

_pinModes = 0xFF;

in your Adafruit_PCF8574::begin code.

When a call to Adafruit_PCF8574::pinMode is made, simply modify _pinModes to have a 0 in each binary position of an output I/O and a 1 in each binary position of an input I/O, and instead of:

bool Adafruit_PCF8574::digitalWriteByte(uint8_t d) { _writebuf = d; return i2c_dev->write(&_writebuf, 1); }

use:

bool Adafruit_PCF8574::digitalWriteByte(uint8_t d) { _writebuf = d | _pinModes; return i2c_dev->write(&_writebuf, 1); }

In this way, an input I/O will always be "or masked" to receive a 1 and the user may modify only the output I/Os as desired.

I will not mention the bit write function, because I did not use it and so did not test it.

Also remember that the PCF8574 has a weak current source internally attached to each I/O. This source current may be "seen" as an internal pull-up that always will be there so INPUT_PULLUP or OUTPUT may be correct as a parameter for Adafruit_PCF8574::pinMode, but INPUT will NOT. The library user may be confused if it is allowed.

These 2 simple changes will allow Adafruit_PCF8574 library to work ok "out of the box", and maybe will improve the sales of your boards...

PS.: I do not wait any mention to myself if you modify your PCF8574 library as I suggest. You have allowed me to start easily, so I think it is fair to offer you my changes without taking any credit.

Thank you