i2C sensors good values initially, then garbage

Hi!

I have a photon sitting on a relay shield, connected to a couple of sensors over i2C.

The sensors are:

adafruit SHT31 Temperature and Humidity (0x44)
adafruit TSL2591 HDR Lux sensor (0x29)

The sensors are powered by the 3v3 and ground pins, with sda on D0 and scl on D1.

I loaded up the libraries for both sensors and cobbled together some code that builds. I am able to get some good data from both sensors on the first try!

However, as you can see, only the first message is correct, the rest are “garbage” values. I get the same result with either sensor, or both, so it seems like an i2C issue? If I reset the Photon, again the first packet is good, then it goes sideways from there. Otherwise, the sensors seem very accurate and react quickly to changing conditions.

Any idea what could be causing this?

Hardware is just one side of the equation.
If you show your code too, we might get a better picture.

1 Like

thanks very much for the reply.

Here is the code, sorry it’s a bit disjointed. I was shocked to see it work at all!

I get the same result printing to the serial monitor and as a particle publish. Sometimes I can get two good readings from both sensors before it gets weird.


 // This #include statement was automatically added by the Particle IDE.
    #include "Adafruit_TSL2591/Adafruit_TSL2591.h"
    #include "Adafruit_TSL2591/Adafruit_Sensor.h"
    
    #include <application.h>
    #include <spark_wiring_i2c.h>
    
    // SHT31 I2C address is 0x44(68)
    #define Addr 0x44    
    
    
    Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)
    
    /**************************************************************************/
    /*
        Displays some basic information on this sensor from the unified
        sensor API sensor_t type (see Adafruit_Sensor for more information)
    */
    /**************************************************************************/
    void displaySensorDetails(void)
    {
      sensor_t sensor;
      tsl.getSensor(&sensor);
      Serial.println("------------------------------------");
      Serial.print  ("Sensor:       "); Serial.println(sensor.name);
      Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
      Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
      Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" lux");
      Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" lux");
      Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" lux");
      Serial.println("------------------------------------");
      Serial.println("");
      delay(500);
    }
    
    /**************************************************************************/
    /*
        Configures the gain and integration time for the TSL2591
    */
    /**************************************************************************/
    void configureSensor(void)
    {
      // You can change the gain on the fly, to adapt to brighter/dimmer light situations
      //tsl.setGain(TSL2591_GAIN_LOW);    // 1x gain (bright light)
      tsl.setGain(TSL2591_GAIN_MED);      // 25x gain
      // tsl.setGain(TSL2591_GAIN_HIGH);   // 428x gain
    
      // Changing the integration time gives you a longer time over which to sense light
      // longer timelines are slower, but are good in very low light situtations!
      tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS);  // shortest integration time (bright light)
      // tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
      // tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
      // tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
      // tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
      // tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS);  // longest integration time (dim light)
    
      /* Display the gain and integration time for reference sake */
      Serial.println("------------------------------------");
      Serial.print  ("Gain:         ");
      tsl2591Gain_t gain = tsl.getGain();
      switch(gain)
      {
        case TSL2591_GAIN_LOW:
          Serial.println("1x (Low)");
          break;
        case TSL2591_GAIN_MED:
          Serial.println("25x (Medium)");
          break;
        case TSL2591_GAIN_HIGH:
          Serial.println("428x (High)");
          break;
        case TSL2591_GAIN_MAX:
          Serial.println("9876x (Max)");
          break;
      }
      Serial.print  ("Timing:       ");
      Serial.print((tsl.getTiming() + 1) * 100, DEC);
      Serial.println(" ms");
      Serial.println("------------------------------------");
      Serial.println("");
    }
    
    
    float cTemp = 0.0, fTemp = 0.0, humidity = 0.0, tLux = 0.0;
    
    void setup(void)
    {
      Serial.begin(9600);
    
      Serial.println("Starting Adafruit TSL2591 Test!");
    
      if (tsl.begin())
      {
        Serial.println("Found a TSL2591 sensor");
      }
      else
      {
        Serial.println("No sensor found ... check your wiring?");
        while (1);
      }
    
      /* Display some basic information on this sensor */
      displaySensorDetails();
    
      /* Configure the sensor */
      configureSensor();
    
    
    
        // Set Particle variables
        Particle.variable("i2cdevice", "SHT31");
        Particle.variable("cTemp", cTemp);
        Particle.variable("humidity", humidity);
        Particle.variable("lux", tLux);
        
        
        // Initialise I2C communication as MASTER 
        Wire.begin();
        // Initialise serial communication, set baud rate = 9600
        Serial.begin(9600);
      
        // Start I2C Transmission
        Wire.beginTransmission(Addr);
        // Send 16-bit command byte          
        Wire.write(0x2C);
        Wire.write(0x06);
        // Stop I2C transmission
        Wire.endTransmission();
        delay(300);
    }
    
    
    
    void advancedRead(void)
    {
      // More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
      // That way you can do whatever math and comparisons you want!
      uint32_t lum = tsl.getFullLuminosity();
      uint16_t ir, full;
      ir = lum >> 16;
      full = lum & 0xFFFF;
      Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
      Serial.print("IR: "); Serial.print(ir);  Serial.print("  ");
      Serial.print("Full: "); Serial.print(full); Serial.print("  ");
      Serial.print("Visible: "); Serial.print(full - ir); Serial.print("  ");
      Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir));
      float tLux = (tsl.calculateLux(full, ir));
      Particle.publish("Lux: ",  String(tLux));
        delay(500);
      
    }
    
    
    
    void loop(void)
    {
        
      displaySensorDetails();
      
      delay(500);
      
      advancedRead();
    
      delay(500);
    
        unsigned int data[6];
        // Start I2C Transmission
        Wire.beginTransmission(Addr);
        // Stop I2C Transmission
        Wire.endTransmission();
        
        // Request 6 bytes of data from the device
        Wire.requestFrom(Addr,6);
        
        // Read 6 bytes of data
        // temp msb, temp lsb, crc, hum msb, hum lsb, crc
        if(Wire.available() == 6)
        {
            data[0] = Wire.read();
            data[1] = Wire.read();
            data[2] = Wire.read();
            data[3] = Wire.read();
            data[4] = Wire.read();
            data[5] = Wire.read();
        }
        delay(500);
      
        // Convert the data
        float cTemp = ((((data[0] * 256.0) + data[1]) * 175.72) / 65536.0) - 46.85;
        float fTemp = (cTemp * 1.8) + 32;
        float humidity = ((((data[3] * 256.0) + data[4]) * 125) / 65535.0) - 6;
        
        // Output data to dashboard
        Particle.publish("Temperature in Celsius: ",  String(cTemp));
        delay(500);
        Particle.publish("Temperature in Fahrenheit: ", String(fTemp));
        delay(500);
        Particle.publish("Relative Humidity: ",  String(humidity));
        delay(500);
    }

Ok, well I did manage to get somewhere. If I comment out everything in the loop after the lux portion, it will print the lux accurately for a long time.

So the issue is after the advancedRead(); section in the main loop. It goes through it once successfully, but after that, all the i2c readings go berzerk.

I’m not positive, but it looks like the Adafruit SHT31 library sends the 16-bit command request before every temperature/humidity read, which I think is the correct behavior from the data sheet.

Adafruit code:

 writeCommand(SHT31_MEAS_HIGHREP);
  
  delay(500);
  Wire.requestFrom(_i2caddr, (uint8_t)6);
  if (Wire.available() != 6) 
    return false;
  for (uint8_t i=0; i<6; i++) {
    readbuffer[i] = Wire.read();

In your code, you’re sending command only once, in setup()

// Start I2C Transmission
        Wire.beginTransmission(Addr);
        // Send 16-bit command byte          
        Wire.write(0x2C);
        Wire.write(0x06);
        // Stop I2C transmission
        Wire.endTransmission();

The sequences of 0x2C then 0x06 is essentially SHT31_MEAS_HIGHREP. I think you need to move this before every temperature/humidity read.

1 Like

Thanks so much, it works!

I’m going to spend the night trying to understand the fix!

Here are some photos of my project, if anyone is interested. The photon and relay board will go in a sealed box. The sensor daughter board will be outside of the case exposed to the elements in my greenhouse. Next step is to add a few (6-10) soil moisture sensor interfaces to the daughter board. The relays will control water valves and fans.

Thanks again!

1 Like

Can you post your working code with the correct commands from Adafruit?

I’m looking to do something similar and am having a hard time understanding @rickkas7’s suggestion above your reply.