Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PCF8583 event counter not woking with SoftWire #32

Open
sumitfyllo opened this issue Sep 16, 2022 · 10 comments
Open

PCF8583 event counter not woking with SoftWire #32

sumitfyllo opened this issue Sep 16, 2022 · 10 comments

Comments

@sumitfyllo
Copy link

I am trying to use pfc8583 . Board is STM32. It always hangs on setMode function..

Sample code:

uint16_t PCF8583::setMode(uint8_t address,uint8_t mode)

{

_address = address >> 1;

// _wire = theWire;

if(!Newwire.available())

{

  Newwire.setTxBuffer(NewwireTxBuffer, sizeof(NewwireTxBuffer));

Newwire.setRxBuffer(NewwireRxBuffer, sizeof(NewwireRxBuffer));

Newwire.setTimeout(1000);

delay(100);

  Newwire.begin();

  delay(200);

}

// if(!Newwire.available())

// return 1;

// return 2;

delay(200);

// convert to 7 bit so Wire doesn't choke

uint8_t control = getRegister(LOCATION_CONTROL);

// uint8_t control = getRegister(LOCATION_CONTROL);

control = (control & ~MODE_TEST) | (mode & MODE_TEST);

setRegister(LOCATION_CONTROL, control);

}

It hangs when Calling setMode

@stevemarple
Copy link
Owner

I don't understand how this is connected to the SoftWire library, please explain.

@sumitfyllo
Copy link
Author

sumitfyllo commented Sep 16, 2022

Hello @stevemarple .
Apologies for not making it clear. Newwire here is a SoftWire object.

It's declared as SoftWire Newwire(sdaPin,slcPin);

I was using Wire.h earlier but wanted to use timeout facility of SoftWire.

But it is not working working with PCF8583.
Wire.h works fine.

@stevemarple
Copy link
Owner

setMode() probably hangs when it calls if(!Newwire.available()) - that will be because the available function uses _rxBufferIndex and _rxBufferBytesRead which are only initialised in setRxBuffer(). In your setMode() function that will occur after the call to Newwire.available().

You need to call Newwire.setRxBuffer(), Newwire.setTxBuffer(), and Newwire.begin() in Arduino's setup() function, and nowhere else. See the ReadDS1307 example for the correct usage of the SoftWire library.

@stevemarple
Copy link
Owner

stevemarple commented Sep 18, 2022

Yesterday you posted a comment with your setRegister() code that contained references to to the Wire library, and the comment was removed a short while later. Does this mean you have now found and resolved the problem? Can I close this issue?

@sumitfyllo
Copy link
Author

Hi Steve,

It's behaving irriatically. Sometimes it counts and sometimes it does not.

I moved Newwire.setRxBuffer(), Newwire.setTxBuffer(), and Newwire.begin() in Arduino's setup() function.

I have two 3 sensors BH1750 for lux and SHT31 and BMP80 for air temperature and Air pressure on same I2C line but on different addresses.

I am reading all using Softwire library.

I do Newwire.setRxBuffer(), Newwire.setTxBuffer(), and Newwire.begin() once. And then use it every time.
BH1750 for lux and SHT31 and BMP80 work fine but PCF8583 event counter mode doesn't work always.

@stevemarple
Copy link
Owner

Are you using repeated starts? What version of SoftWire are you using?

@sumitfyllo
Copy link
Author

No. Made sure only one begin. If I remove SHT21 sensor. Event counter works.

Using 2.0.9

@stevemarple
Copy link
Owner

Repeated starts are a feature of the I2C protocol, see https://www.i2c-bus.org/repeated-start-condition. There was an issue in SoftWire which meant repeated starts were not handled correctly, it was fixed in v 2.0.8.

So the event counter does now work with SoftWire? Without seeing the whole code it is hard to know what is wrong but if SoftWire can successfully communicate with each device it doesn't seem like it is a problem in the library.

@sumitfyllo
Copy link
Author

sumitfyllo commented Sep 21, 2022

PCF8583 when used with Software 2.0.9 alongwith BMP80 and SHT31 on I2C line, gives getCount always as 1666665.

When removing BMP80 and SHT31, it gives 0 and works fine.

With v2.0.8 , even after removing getCount gives 101 always. It doesn't go to 0.

Code is :

// SETUP Code
boolean firstTime = true;
void setup() {
pinMode(PC13, OUTPUT);
digitalWrite(PC13, LOW);
for (int i = 0; i < 20; i++)
{
digitalWrite(PC13, !digitalRead(PC13));
delay(50);
}
digitalWrite(PC13, LOW);
delay(100);
LowPower.begin();
pinMode(PC13, OUTPUT);

 if (!Mod.modemInit())

{
deviceSleepSave();
}
if (!Mod.modemNetworkConnect())
{
deb.println("Shutting down..");
deviceSleepSave();
}

pinMode(_sen_pwr,OUTPUT);
pinMode(_mux_S0,OUTPUT);
pinMode(_mux_S1,OUTPUT);
pinMode(_leaf_wet_pwr_pin,OUTPUT);
pinMode(_leaf_wet_pin, INPUT);
pinMode(_ldr_pin, INPUT);
pinMode(_irro_pin,INPUT);
digitalWrite(_sen_pwr,LOW);
Newwire.setTxBuffer(NewwireTxBuffer, sizeof(NewwireTxBuffer));
Newwire.setRxBuffer(NewwireRxBuffer, sizeof(NewwireRxBuffer));
Newwire.setTimeout(1000);
flipDelay(100);
Newwire.begin();
delay(100);

               if(firstTime == true){

sensors.setRainfallMode();
firstTime = false;
float rainfall = sensors.getRainfallCount();
deb.println("Rain");
deb.println(rainfall);
while(rainfall != 0){
delay(100);
deb.println(rainfall);
sensors.setRainfallMode();
rainfall = sensors.getRainfallCount();

}
deb.println("RainFINAL");

deb.println(rainfall);
}

deb.println("Sensor reading begins");

delay(1000);
readData();

if (serializeJson(doc, payload) == 0) {
deb.println("ERR : Failed to write to file JSON to string");
}
else
{
deb.println(payload);
}
httpReplyRead();
// delay(100);

// deb.println(json_pub);
delay(300);
if(strlen(broker)>5)
{
mqttPublish();
mqtt.mqttDisconnect();
}
powerOff();
}

void loop() {
deb.println("stuck in loop");
}

void readData()
{
sensors.begin();

char encoded_imei[Base64.encodedLength(strlen(Mod.imei))];
Base64.encode(encoded_imei, Mod.imei, strlen(Mod.imei));
uint16_t *sm = sensors.getSoilMoistureKpa();
doc["imei"] = encoded_imei;
doc["time"] = Mod.time_stamp;
doc["Ts"] = sensors.getSoilTemperature();
doc["m1"] = sm[0];
doc["m2"] = sm[1];

doc["Lw"] = sensors.getLeafWetness();
doc["Sq"] = Mod.signal_strength;
doc["BATV"] = Mod.battery_charge_voltage;
doc["BATP"] = batterypercentage();
delay(100);

for(int i=0;i<3;i++){
doc["Lx"] = sensors.getLightIntensity();
delay(100);
float *athp = sensors.getAirTemperatureHumidity();
doc["Ta"] = athp[0];
doc["Ha"] = athp[1];
athp[2]= sensors.getAirPressureBMP();
doc["Pa"] = athp[2];

doc["Wd"] = sensors.getWindDirection();
doc["Ws"] = sensors.getWindSpeed();
doc["Rf"] = sensors.getRainfall();
}

}

PCF8583 code :

void PCF8583::setMode(uint8_t address,uint8_t mode)
{
if(!Newwire.available())
{
Newwire.begin();
}
_address = address >> 1; // convert to 7 bit so Wire doesn't choke
uint8_t control = getRegister(LOCATION_CONTROL);
control = (control & ~MODE_TEST) | (mode & MODE_TEST);
setRegister(LOCATION_CONTROL, control);
}

uint8_t PCF8583::getMode() {
return getRegister(LOCATION_CONTROL) & MODE_TEST;
}

void PCF8583::setCount(unsigned long count) {
icStop();
Newwire.beginTransmission(_address);
Newwire.write(LOCATION_COUNTER);
Newwire.write(byte2bcd(count % 100));
Newwire.write(byte2bcd((count / 100) % 100));
Newwire.write(byte2bcd((count / 10000) % 100));
Newwire.endTransmission();
icStart();
}

unsigned long PCF8583::getCount() {

Newwire.beginTransmission(_address);
Newwire.write(LOCATION_COUNTER);
Newwire.endTransmission();
Newwire.requestFrom(_address, (uint8_t) 3);

unsigned long count = 0;
count = bcd2byte(Newwire.read());
count = count + bcd2byte(Newwire.read()) * 100L;
count = count + bcd2byte(Newwire.read()) * 10000L;

return count;

}

// Private methods

void PCF8583::icStop() {
uint8_t control = getRegister(LOCATION_CONTROL);
control |= 0x80;
setRegister(LOCATION_CONTROL, control);
}

void PCF8583::icStart() {
uint8_t control = getRegister(LOCATION_CONTROL);
control &= 0x7F;
setRegister(LOCATION_CONTROL, control);
}

void PCF8583::setRegister(uint8_t offset, uint8_t icValue) {
Newwire.beginTransmission(_address);
Newwire.write(offset);
Newwire.write(icValue);
Newwire.endTransmission();
}

uint8_t PCF8583::getRegister(uint8_t offset) {
Newwire.beginTransmission(_address);
Newwire.write(offset);
Newwire.endTransmission();
Newwire.requestFrom(_address, (uint8_t) 1);
return Newwire.read();
}

uint8_t PCF8583::bcd2byte(uint8_t icValue) {
return ((icValue >> 4) * 10) + (icValue & 0x0f);
}

uint8_t PCF8583::byte2bcd(uint8_t icValue) {
return ((icValue / 10) << 4) + (icValue % 10);
}

@stevemarple
Copy link
Owner

stevemarple commented Sep 21, 2022

I said previously

You need to call Newwire.setRxBuffer(), Newwire.setTxBuffer(), and Newwire.begin() in
Arduino's setup() function, and nowhere else. See the ReadDS1307 example for the correct
usage of the SoftWire library.

In PCF8583::setMode(uint8_t address,uint8_t mode) you still call the SoftWire begin() function. Do not do this.

The PCF8583::getRegister(uint8_t offset) makes two separate accesses to the I2C bus. The first writes the register offset, which concludes with endTransmission() sending a STOP condition. A new access is started with the call to requestFrom(). If you look at the datasheet for this device (https://www.nxp.com/docs/en/data-sheet/PCF8583.pdf#page=18) figure 19 shows a repeated start condition. The call to endTransmission() should be replaced with endTransmission(false), so that the STOP condition is not sent and the START condition from requestFrom() becomes a repeated start. You must use version 2.0.9 or later to obtain the correct repeated start behaviour.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants