I2C unstable data readings

Hello!

We are using the i2c communication protocol with a TCA9548A i2c multiplexer and an electron device to control several (up to 4) temperature and humidity sensors (SHT31) that are attached to the electron with cables. and we are getting strange values, sometimes for a few readings it works well for all sensors and sometimes there is one sensor that either only displays humidity or only displays temperature. in your opinion is this a hardware or a software problem?

The relevant code is displayed below:

#include "Adafruit_SHT31.h"


// Disable GSM on boot
SYSTEM_MODE(AUTOMATIC);


/* Information about time */
#define DEEP_SLEEP_TIME_INTERVAL_S 60
#define POST_SOC_READ_DELAY_MS 100
#define POST_TEMP_READ_DELAY_MS 100
#define POST_HUM_READ_DELAY_MS 100
#define POST_WIRE_BEGIN_DELAY_MS 100
#define POST_WIRE_END_DELAY_MS 100
#define POST_SERIAL_BEGIN_DELAY_MS 100
#define POST_SERIAL_END_DELAY_MS 100
#define POST_PUBLISH_DELAY_MS 5000
#define POST_PROCESS_DELAY_MS 100
#define TIME_EPOCH_START 1970

/* TCA9548A I2C Multiplexer adress */
#define TCAADDR 0x70


/* Enabling Backup RAM (SRAM) */
STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));
retained uint8_t last_day_sync_d = 0;


/* Define a fuel gauge instance */
FuelGauge fuel;

/* Define a Adafruit_SHT31 instance */
Adafruit_SHT31 sht31 = Adafruit_SHT31();



/**************************************************************************/
/*
        Functions declarations
 */
/**************************************************************************/
/* Synchronise RTC time with Particle cloud one */
bool syncTime(uint16_t timeout_ms = 1000) {
    if (Particle.connected()) {
        Particle.syncTime();

        // syncTime is non-blocking, so wait for a valid time to come back
        // from the server before proceeding
        uint32_t timeout = millis() + timeout_ms;
        uint32_t now = millis();
        while (Time.year() <= TIME_EPOCH_START && now < timeout) {
            Particle.process();
            delay(POST_PROCESS_DELAY_MS);
            now = millis();
        }
        return now < timeout;
    }
    return false;
}

/* Initialize I2C buses from TCA9548A I2C Multiplexer */
void tcaselect(uint8_t i2c_bus) {
  if (i2c_bus > 7) return;

  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i2c_bus);
  Wire.endTransmission();
}

/* Begin SHT31 sensors */
void beginSHT31Sensors() {
    tcaselect(0);
    if (!sht31.begin(0x44)) {
        Serial.println("couldn't find SHT31 sensor from board");
        while (1) delay(1);
    }

    tcaselect(1);
    if (!sht31.begin(0x44)) {
        Serial.println("couldn't find SHT31 sensor from beehive 1");
        while (1) delay(1);
    }

    tcaselect(2);
    if (!sht31.begin(0x44)) {
        Serial.println("couldn't find SHT31 sensor from beehive 2");
        while (1) delay(1);
    }

    tcaselect(4);
    if (!sht31.begin(0x44)) {
        Serial.println("couldn't find SHT31 sensor from beehive 3");
        while (1) delay(1);
    }

    tcaselect(7);
    if (!sht31.begin(0x44)) {
        Serial.println("couldn't find SHT31 sensor from beehive 4");
        while (1) delay(1);
    }
}

/* Read SHT31 Sensors data and return a String containing their values */
String readSHT31SensorsData() {
    String sensors_data = "";

    sensors_data = String::format("%.2f ", fuel.getSoC());
    delay(POST_SOC_READ_DELAY_MS);

    tcaselect(0);
    sensors_data.concat(String::format("%.2f ", sht31.readTemperature()));
    delay(POST_TEMP_READ_DELAY_MS);

    sensors_data.concat(String::format("%.2f ", sht31.readHumidity()));
    delay(POST_HUM_READ_DELAY_MS);

    tcaselect(1);
    sensors_data.concat(String::format("%.2f ", sht31.readTemperature()));
    delay(POST_TEMP_READ_DELAY_MS);

    sensors_data.concat(String::format("%.2f ", sht31.readHumidity()));
    delay(POST_HUM_READ_DELAY_MS);

    tcaselect(2);
    sensors_data.concat(String::format("%.2f ", sht31.readTemperature()));
    delay(POST_TEMP_READ_DELAY_MS);

    sensors_data.concat(String::format("%.2f ", sht31.readHumidity()));
    delay(POST_HUM_READ_DELAY_MS);

    tcaselect(4);
    sensors_data.concat(String::format("%.2f ", sht31.readTemperature()));
    delay(POST_TEMP_READ_DELAY_MS);

    sensors_data.concat(String::format("%.2f ", sht31.readHumidity()));
    delay(POST_HUM_READ_DELAY_MS);

    tcaselect(7);
    sensors_data.concat(String::format("%.2f ", sht31.readTemperature()));
    delay(POST_TEMP_READ_DELAY_MS);

    sensors_data.concat(String::format("%.2f ", sht31.readHumidity()));
    delay(POST_HUM_READ_DELAY_MS);

    return sensors_data;
}



/**************************************************************************/
/*
        Function:  setup
 */
/**************************************************************************/
void setup()
{
    // String variables which contains temperature and humidity data from SHT31 sensors
    String sensors_data = "";

    // Initialize serial communication
    Serial.begin(9600);
    delay(POST_SERIAL_BEGIN_DELAY_MS);

    // Initialize wire communication
    Wire.begin();
    delay(POST_WIRE_BEGIN_DELAY_MS);

    // Synchronise hardware time with Particle Cloud one
    if (Time.day() != last_day_sync_d) {
        syncTime();
        last_day_sync_d = Time.day();
    }

    // Initialize the time zone to the US eastern one
    Time.zone(-4);

    // initialize SHT31 sensors from beehives
    beginSHT31Sensors();

    // Read data from SHT31 sensors and publish them to Particle cloud
    if (Particle.connected()) {
        sensors_data = readSHT31SensorsData();

        Particle.publish("d", sensors_data, PRIVATE);

        delay(POST_PUBLISH_DELAY_MS);
    } else { // Try again if it didn't work the first time
        Particle.connect();

        if (Particle.connected()) {
            sensors_data = readSHT31SensorsData();

            Particle.publish("d", sensors_data, PRIVATE);

            delay(POST_PUBLISH_DELAY_MS);
        }
    }

    // End wire communication
    Wire.end();
    delay(POST_WIRE_END_DELAY_MS);

    // End serial communication
    Serial.end();
    delay(POST_SERIAL_END_DELAY_MS);

    // Activate deep sleep mode of the device for DEEP_SLEEP_TIME_INTERVAL_S seconds
    System.sleep(SLEEP_MODE_DEEP, DEEP_SLEEP_TIME_INTERVAL_S);
}



/**************************************************************************/
/*
        Function:  loop
 */
/**************************************************************************/
void loop()
{
}

@sachaysl what pins are you using for the I2C bus?
Are you level shifting to 5 vdc for mux?
I have been using ControlEverything modules that take care of the 3.3 to 5.0 voltage shift for me. Just a screw shield would do Screw Shield with 12 to 5 vdc regulator it also make connections easy. They have them for the electron also without the regulator.

1 Like

thankyou for sharing! Our multiplexer works on 3.3v and the pins we are using are D0 and D1 (wire communication). Our pullup resistors for SDA and SCL connections are 50cm away from the electron. Do you think he cables could have an impact on the signal?

@sachaysl, the pull-ups need to be near the Electron I2C pins and not at the other end when the distance is that much. The length of the wires will create a capacitance effect and slow the signal rise time. What resistor values are you using?

1 Like

Ok that makes sense , thankyou very much! I’m using 10Kohm pullup resistors.

@sachaysl, you may want to go to stronger pull-ups like 4.7K or 2.2K if that doesn’t work.

@sachaysl one thing that could cause problems is the length of the cables the shorter the better. I try to keep the length to a couple of feet. You may get 10 feet to work at 100khz depending on the capacitance of the wire. Slowing the frequency can help if the sensors can handle it. The longer cables may need some form of error checking (crc etc.).