twilio / breakout-massive-iot-arduino

Apache License 2.0
9 stars 3 forks source link

I2C / Wire.h issues #26

Closed robotastic closed 4 years ago

robotastic commented 4 years ago

Are there any known issues with I2C & Wire.h with the Massive Breakout SDK? I am trying to get the SGP30 Grove sensor to work with the AlfaKit board. The sensor works fine on a Arduino Uno board. I have tried using both the Seeed and Adafruit drivers.

Both the AdaFruit driver and the Seeed driver use Wiring.h to talk with the sensor. With the Adafruit driver, it hangs/crashes during the sensor setup after it the modem has connected. With the Seeed driver it runs, but only returns the default value.

I have tried running just the example sensor program using both Adafruit and Seeed, modified to include the SDK and use LOG, with similar issues.

Have you tested Wire.h and I2C?

Here is the code for the CO2 sensor, using the Adafruit driver:

#define SAMPLE_CO2
#include <Wire.h>
#include <Adafruit_SGP30.h>

// BEGIN CONFIGURATION SECTION

Adafruit_SGP30 sgp;

#define CO2_SEND_INTERVAL (20 * 1000)
#define CO2_BASELINE_INTERVAL (30 * 1000)
#define CO2_SENSE_INTERVAL (1000)
// END CONFIGURATION SECTION

/* return absolute humidity [mg/m^3] with approximation formula
* @param temperature [°C]
* @param humidity [%RH]
*/
uint32_t getAbsoluteHumidity(float temperature, float humidity) {
    // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
    const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
    const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
    return absoluteHumidityScaled;
}

void sample_co2_setup() {
  LOG(L_INFO,"Setting up SGP30 Sensor");
    if (! sgp.begin()){
      LOG(L_INFO,"Sensor not found :(");
      //while (1);
    } else {
    LOG(L_INFO,"SGP30 Sensor found :)");
    }
}

void sample_co2_loop() {
  static unsigned long last_send = 0;
  static unsigned long last_baseline = 0;
  static unsigned long last_sense = 0;

  // If you have a temperature / humidity sensor, you can set the absolute humidity to enable the humditiy compensation for the air quality signals
  //float temperature = 22.1; // [°C]
  //float humidity = 45.2; // [%RH]
  //sgp.setHumidity(getAbsoluteHumidity(temperature, humidity));

  if (!sleep && ((last_sense == 0) || (millis() - last_sense >= CO2_SENSE_INTERVAL))) {

    last_sense = millis();
  if (! sgp.IAQmeasure()) {
    LOG(L_INFO,"Measurement failed");
    return;
  }
  LOG(L_INFO, "TVOC %d ppb \t eCO2 %d \n",sgp.TVOC, sgp.eCO2); 

  if (! sgp.IAQmeasureRaw()) {
    LOG(L_INFO,"Raw Measurement failed");
    return;
  }
  LOG(L_INFO,"Raw H2 %d \t Raw Ethanol %d\n",sgp.rawH2, sgp.rawEthanol );
  }
    if (!sleep && ((last_send == 0) || (millis() - last_send >= CO2_SEND_INTERVAL))) {

    last_send = millis();
 char commandText[512];
    snprintf(commandText, 512, "{\"device\":\"%.*s\",\"TVOC\":%d,\"eCO2\":%4.2f}", imei.len, imei.s, sgp.TVOC,
             sgp.eCO2);
    if (!send_data(commandText)) {
      LOG(L_WARN, "Error publishing message: (client connected status: %d)\r\n", mqtt->isConnected());
    }

    }
  if (!sleep && ((last_baseline == 0) || (millis() - last_baseline >= CO2_BASELINE_INTERVAL))) {

    last_baseline = millis();
    uint16_t TVOC_base, eCO2_base;
    if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) {
      LOG(L_INFO,"Failed to get baseline readings");
      return;
    }
    LOG(L_INFO,"****Baseline values: eCO2: 0x%04x \t & TVOC: 0x%0x4 ",eCO2_base,TVOC_base);
  }
}
OYTIS commented 4 years ago

Hi @robotastic,

I've tried to reproduce it with Seeed drivers. I get numbers around 0 for tVOC concentration (I'm not sure if it's wrong, we don't have many volcanoes around), and CO2 concentration seems about right (floating between 400 and 500+ ppm).

Please use my branch for the reference, and check if it works for you: https://github.com/twilio/Breakout_Massive_SDK_Arduino/tree/sgp30

If it does, please publish your Seeed example as a repo, and I'll try to reproduce the problem you encounter on my device.

robotastic commented 4 years ago

Weird - I downloaded the updated branch and it still isn't working. I am getting "error reading signals" in the logs when it starts up. It seems like it is not able to communicate with the sensor.

The weird thing is that I can talk with the sensor fine on an Arduino and I just got it work with a Particle Photon this weekend, which runs at 3.3v.

I wonder if there are some timing or voltage variance that are messing up the I2C communication. I can try getting another SGP30 next time I place a Seeed order.

robotastic commented 4 years ago

I should add - I did have this sensor working fine with the Alfa-Kit board with the older Breakout SDK, so I think the board hardware is fine.

OYTIS commented 4 years ago

@robotastic

That is strange indeed, first because Breakout SDK doesn't touch I2C at all, and second because I have an identical board and sensor on my desk.

The only thing I can suspect, is power as you said. Are you powering from USB or from the battery?

Could you please also check the following sample: https://gist.github.com/OYTIS/35547320c684f0b5eacfb1758cc059d0

It does not use the SDK at all, it's just adapted from Seeed driver repo. In my case it reads default values for about 15 seconds (as expected), and then starts reading something real.

robotastic commented 4 years ago

@OYTIS Well, this is interesting. That gist with the sample code works fine! I have the same behavior, where it will start working after 15 sec, as described in the manual.

Looking at the code, the one change from the Example code from the Seeed driver repo is adding:

pinMode(32,OUTPUT);
digitalWrite(32,1);

during Setup(). I added this to the sgp30 branch of the SDK and it is working!!

This caused me to go back and read the HW notes on the board.

It looks like the I2C port may not be powered on by default:

!!!Tip If you want to use the on-board Grove connector, please use digitalWrite(B10, HIGH) to open 3V3_B. except D38 power on by default. Otherwise you can't provide power to Grove modules.

Digging a little into Massive vs Breakout, it looks like the I2C gets powered on in the OwlPowerOn Function however in the Old Breakout it is part of the OwlModem Class.

In Massive it looks like you have to explicitly call owlPowerOn. In Breakout, it is called from powerModuleOn() which calls initModem(). The Breakout examples for all of the different sensors have a call to powerModuleOn(). However, only the Massive Alfakit example for GNSS has a call to owlPowerOn.

In short, calling owlPowerOn(OWL_POWER_BG96) should fix it.

Thanks so much for your help in tracking this down!! Guess I should have hooked a logic analyzer up to it.

OYTIS commented 4 years ago

@robotastic Thank you for digging that far!

As far as I can see, this problem should have been fixed by a commit from 21st of August, powering on the Grove ports is a part of overall power on procedure since then.

This code is missing from the latest release though, but is definitely present in my sgp30 branch, so I am a bit confused to be honest. If you've got time, could you please test against a newly-cloned master branch?

robotastic commented 4 years ago

You are right - that change to the Massive-SDK, should have powered on. However I think part of my problem is that I was hitting the download link in GitHub for Breakout-Massive-SDK-Arduino. When you download the zip file, it doesn't include the sub-repo for Break-Massive-SDK. I must have originally done a git clone which pulled in the Massive SDK sub-repo and then done a download of the .zip from GitHub. I am will try doing a clean install of Arduino to get rid of everything and start fresh.

robotastic commented 4 years ago

I cleaned up everything and can confirm that latest version is working. Thanks for all the help!

It is probably worth adding to the documentation that this library needs to be Cloned or Downloaded from the Releases. If you download a zip using the little button in the upper right hand corner, it does not include the Massive-SDK sub-repo.

I have it streaming data to Adafruit IO.

OYTIS commented 4 years ago

@robotastic

Nice graphs :) Thank you for reporting and sorry for the confusion. It's definitely worth adding to the documentation. I wish we could disable the 'Download Zip' button altogether, but Github won't allow us to.