stevemarple / SoftWire

Software I2C implementation for Arduino and other Wiring-type environments
GNU Lesser General Public License v2.1
139 stars 31 forks source link

PCF8583 event counter not woking with SoftWire #32

Open sumitfyllo opened 2 years ago

sumitfyllo commented 2 years ago

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 commented 2 years ago

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

sumitfyllo commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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

sumitfyllo commented 2 years ago

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

Using 2.0.9

stevemarple commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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.