Trouble with the Wire library for TCA9954

Hey guys,

I am writting a library for the TCA9554 gpio expander to be used in a project. It is based on a 2019 publicly available github project that does not seem to work, so I am tweaking it and making some minor corrections. I have managed to do everything I need, except read from it's registers.

From TI datasheet of the chip, this is the sequence of messages it needs to receive to return the current state of the registors.

image

It seems straight foward enough, but I haven't been able to receive a correct answer from it. The code I am currently using to read the output register is the following.

/*
  TCA9554.h - Library for work with TCA9554 or TCA9554a GPIO expander
  Created by Prohorov Vladimir, Octomber 14, 2019.
  Released into the public domain.
*/
#ifndef TCA9554_H
#define TCA9554_H

#include "Arduino.h"
#include <Wire.h>

#define INPUT_PORT_REG 0x0
#define OUTPUT_PORT_REG 0x1
#define POLARITY_INVERSION_REG 0x2
#define CONFIG_REG 0x3

class TCA9554
{
  public:
    TCA9554(int address);
    int PinSetMode(byte pin, bool mode);
    int DigitalWrite(byte pin, bool state);   // it return 0 if write successful, else retrun -1
    int DigitalRead(byte pin);                // it return pin state if read successful, else return -1
    int GetAddress();                         // it return init address
  private:
    int _address;
	byte _current_out;
};

TCA9554::TCA9554(int address)
{
  _address = address;
  _current_out = 0;
}

int TCA9554::PinSetMode(byte pin, bool mode)
{
  byte output_reg = 0;

  Wire.beginTransmission(_address);
  Wire.write(CONFIG_REG);
    
  Wire.requestFrom(_address, 1);
  while (Wire.available()) 
  {                                   
    output_reg = Wire.read();    
  }
  
  byte error = Wire.endTransmission();
  if (error > 0)
    return -1;

  if (mode == INPUT)
  {
    output_reg |= ((1 << pin) << 1);
  }
  else if (mode == OUTPUT)
  {
    output_reg &= ~((1 << pin) << 1);
  }
  
  Wire.beginTransmission(_address);
  Wire.write(CONFIG_REG);
  Wire.write(output_reg);
  error = Wire.endTransmission();

  if (error > 0)
    return -1;

  return 0;
}

int TCA9554::DigitalWrite(byte pin, bool state)
{
  byte output_reg = 0;
  Wire.beginTransmission(_address);
  Wire.write(OUTPUT_PORT_REG);
  
  byte error = Wire.endTransmission(0);
  if (error > 0){
	Serial.println("Error 1!!");
    return -1;
  }
  
  int num = Wire.requestFrom(_address, 1);
  Serial.println("Will read what I received");
  while (Wire.available()) 
  {
	Serial.print(".");
    output_reg = Wire.read();    
  }
  Serial.println("\nFinished reading");
  
  /*error = Wire.endTransmission();
  if (error > 0){
	Serial.println("Error 2!!");
    return -1;
  }*/
  
  Serial.println("I received " + String(num) + " total bytes");
  
  Serial.print("Current out reg is: ");
  Serial.println(output_reg);

  // This code get update register 
  if (state == HIGH)
  {
    _current_out |= (1 << pin);
  }
  else if (state == LOW)
  {
    _current_out &= ~(1 << pin);
  }
  
  Wire.beginTransmission(_address);
  Wire.write(OUTPUT_PORT_REG);
  Wire.write(_current_out);
  error = Wire.endTransmission();
  
  if (error > 0)
    return -1;

  return 0;
}

int TCA9554::GetAddress()
{
  return _address;
}
#endif

To which I receive the following answer:

"Will read what I received
.
I received 1 total bytes
Current out reg is: 0"

However, I know for a fact that the output register is not 0 as I have 4 output doors which are cycling 4 leds from HIGH to LOW, and, regardless from the LED state, I receive 0.

Can someone please shed some light into what I am doing wrong, please?

From what I understand, using Wire.endtransmission(false) would not send a stop condition and the next start condition would be a restart one instead. Also, if I am not mistaken requestFrom should send both the start and the stop condition, and change the last bit from the address to 1 to signalize a reading operation. I have tried several other ways of doing that, but to no avail.

I am using an ESP32 module to control everything in my project, maybe there is some difference in the wire libraries that I am not aware of?

Any help is welcome.

Thank you

Please autoformat the code in IDE and post the entire code. Not enough information in the cut out.

You do a wire.read into "char outputReg = wire.read....".
That saves the very last read. Then You print strings...

Thank you for your answer,

I have added the relevant parts of the code to make it easier to understand. As I stated on the question, I am able to write into the registers with DigitalWrite, but I cannot read the state of said register, which forces me to use a memory array (_current_out).

Regarding your comments, as per Wire.requestFrom(_address, 1), I am only reading a single byte, so storing it into a char is no problem at all. I know there is loss of efficiency by doing so many conversions (byte -> char -> string), but it is only for testing purposes and will be removed from the final library. As there is no loss of information in these conversions, that is not the problem. In fact, that is the way that the wire.read() documentation does it just for simplicity sake.

I believe that what I am doing wrong has to do with a possible misundertanding as to how the wire.requestFrom works. From what I understand, it should send the 3rd byte on the image I have posted. I will try this weekend to hook 2 esp32 together on the I2C busses and reproduce this code to see exactly what I am sending. Though, any help you could offer would still be greatly appreciated.

You have theories and ideas what to try. That's good.

One thing I forgot to mention in my question (I have edited it to include it now) is that I am using an ESP32 to control everything. I was trying to read what the ESP would send with another ESP32, and, for my astonishment, it seems that the wire library for ESP32 is incomplete and does not support the function wire.onReceive. Maybe there is a difference on the arduino and the ESP32 variantes of the library?

Does anyone know if there is any other significant difference on these 2 libraries?

Thanks for any answers that I might receive.

There was a small error on the code. The code uploaded now should work with the current esp32 release, if anyone wants it.