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.
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