Photon + MPL3115A2 - Not Reading

Hey folks,

Any ideas here? Whether or not the sensor is connected the serial output is the same…I am assuming that means noob error. I have read the data sheet a few times now and looked all over for examples…

Anyway, here is a pic of the Fritzing diagram and here is a picture of the actual wired up set. Thoughts?

I’ve set the Addr to 0x60 as well as 0xC0 and no change. Below is a seemingly relevant code snippet.

I already tried the libraries that are there but it seems I’m not able to get connected to the sensor, once I can do that, I will gladly use the libraries that are already there.

Thanks.

#include <application.h>
#include <spark_wiring_i2c.h>

// MPL3115A2 I2C address is 0x60(96)
#define Addr 0x60

double cTemp = 0.0, fTemp = 0.0, pressure = 0.0, altitude = 0.0;
int temp = 0, tHeight = 0;
long pres = 0;
void setup()
{
    // Set variable
    Particle.variable("i2cdevice", "MPL3115A2");
    Particle.variable("cTemp", cTemp);
    Particle.variable("pressure", pressure);
    Particle.variable("altitude", altitude);

    // Initialise I2C communication
    Wire.begin();
    // Initialise Serial Communication, set baud rate = 9600
    Serial.begin(9600);

    // Start I2C transmission
    Wire.beginTransmission(Addr);
    // Select control register
    Wire.write(0x26);
    // Active mode, OSR = 128, altimeter mode
    Wire.write(0xB9);
    // Stop I2C transmission
    Wire.endTransmission();

    // Start I2C transmission
    Wire.beginTransmission(Addr);
    // Select data configuration register
    Wire.write(0x13);
    // Data ready event enabled for altitude, pressure, temperature
    Wire.write(0x07);
    // Stop I2C transmission
    Wire.endTransmission();
    delay(300);
}

What serial output? I don't see any output in your code. Also, you need to be doing some Wire.read commands to read the data, not just writes.

The steps needed to get this to work are quite complicated so I think you should try the libraries again, and if you can't get them to work, come back with details of what you tried, and what results you got.

First, you won't need

#include <application.h>
#include <spark_wiring_i2c.h>

If you are working with an .ino file application.h (or better the newer Particle.h) is included automatically and that in turn will include the headers needed to use Wire in your code.

Next, the address.
You were using another board with exactly the same address in this thread
The hardware (8bit) base address of the device is 0xC0 but for Wire you need the 7bit address (0xC0 >> 1 or 0b11000000 >> 1 which is 0b01100000 or 0x60).
So you might have an address collision unless you set the address of the PCA9531 board to something else.
For that board 0x60 being the 7-bit-base address the bottom three bits are settable via the A0~A2 pins on the LED driver shield via the address jumpers.

But most importantly on the hardware side, you'll need to have pull-up resistors on your I2C lines. The Adafruit MPL3115A2 board has already got 10k in place. But if you are using it in conjunction with the CE board where you can apply them via the dedicated jumpers on your board if you are not using the CE master board you need to make sure the over all pull-up value is still OK.

And once you have the HW set up correctly, you can move on to the SW side of things.

And for reading the MPL3115A2, you'll need to do the reading in loop() and not only once in setup().

Thanks guys. I guess I should have been more clear. @ScruffR, you’re correct, there is another board I have with the same address but not part of this circuit.

Here’s the full code, I was trying to save people from having to read the entire code set, I figured it was the wiring. Please find the full code below.

Lastly, I tried pull up resistors on the SCL/SDA but as you mentioned the MPL board already has the resistor in place as far as I can tell.

#include <application.h>
#include <spark_wiring_i2c.h>

// MPL3115A2 I2C address is 0x60(96)
#define Addr 0x60

double cTemp = 0.0, fTemp = 0.0, pressure = 0.0, altitude = 0.0;
int temp = 0, tHeight = 0;
long pres = 0;
void setup()
{
    // Set variable
    Particle.variable("i2cdevice", "MPL3115A2");
    Particle.variable("cTemp", cTemp);
    Particle.variable("pressure", pressure);
    Particle.variable("altitude", altitude);

    // Initialise I2C communication
    Wire.begin();
    // Initialise Serial Communication, set baud rate = 9600
    Serial.begin(9600);

    // Start I2C transmission
    Wire.beginTransmission(Addr);
    // Select control register
    Wire.write(0x26);
    // Active mode, OSR = 128, altimeter mode
    Wire.write(0xB9);
    // Stop I2C transmission
    Wire.endTransmission();

    // Start I2C transmission
    Wire.beginTransmission(Addr);
    // Select data configuration register
    Wire.write(0x13);
    // Data ready event enabled for altitude, pressure, temperature
    Wire.write(0x07);
    // Stop I2C transmission
    Wire.endTransmission();
    delay(300);
}

void loop()
{
    unsigned int data[6];

    // Start I2C transmission
    Wire.beginTransmission(Addr);
    // Select control register
    Wire.write(0x26);
    // Active mode, OSR = 128, altimeter mode
    Wire.write(0xB9);
    // Stop I2C transmission
    Wire.endTransmission();
    delay(1000);

    // Start I2C transmission
    Wire.beginTransmission(Addr);
    // Select data register
    Wire.write(0x00);
    // Stop I2C transmission
    Wire.endTransmission();

    // Request 6 bytes of data
    Wire.requestFrom(Addr, 6);

    // Read 6 bytes of data from address 0x00(00)
    // status, tHeight msb1, tHeight msb, tHeight lsb, temp msb, temp lsb
    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();
    }

    Serial.println(data[4]);

    // Convert the data to 20-bits
    tHeight = ((((long)data[1] * (long)65536) + (data[2] * 256) + (data[3] & 0xF0)) / 16);
    temp = ((data[4] * 256) + (data[5] & 0xF0)) / 16;
    altitude = tHeight / 16.0;
    cTemp = (temp / 16.0);
    fTemp = cTemp * 1.8 + 32;

    // Start I2C transmission
    Wire.beginTransmission(Addr);
    // Select control register
    Wire.write(0x26);
    // Active mode, OSR = 128, barometer mode
    Wire.write(0x39);
    // Stop I2C transmission
    Wire.endTransmission();

    // Start I2C transmission
    Wire.beginTransmission(Addr);
    // Select data register
    Wire.write(0x00);
    // Stop I2C transmission
    Wire.endTransmission();
    delay(1000);

    // Request 4 bytes of data
    Wire.requestFrom(Addr, 4);

    // Read 4 bytes of data
    // status, pres msb1, pres msb, pres lsb
    if(Wire.available() == 4)
    {
        data[0] = Wire.read();
        data[1] = Wire.read();
        data[2] = Wire.read();
        data[3] = Wire.read();
    }


    // Convert the data to 20-bits
    pres = (((long)data[1] * (long)65536) + (data[2] * 256) + (data[3] & 0xF0)) / 16;
    pressure = (pres / 4.0) / 1000.0;

    // Output data to dashboard
    Particle.publish("Altitude :", String(altitude));
    delay(1000);
    Particle.publish("Pressure :", String(pressure));
    delay(1000);
    Particle.publish("Temperature in Celsius :", String(cTemp));
    Serial.println(cTemp);
    delay(1000);
    Particle.publish("Temperature in Fahrenheit :", String(fTemp));
    delay(1000);
}

@srfnmnk, try running the I2C scanner to see if the device shows up and at what address:

Good to hear you got unstuck :+1:

Just some coding hints about this

    if(Wire.available() == 6)
    {
      ...
    }
    tHeight = ((((long)data[1] * (long)65536) + (data[2] * 256) + (data[3] & 0xF0)) / 16);
    temp = ((data[4] * 256) + (data[5] & 0xF0)) / 16;
    altitude = tHeight / 16.0;
    cTemp = (temp / 16.0);

You may not always get the response fast enough for your if() to catch an otherwise successful request.
You may want to change that for a while (Wire.available() < 6) with a timeout to even catch a sluggish response.
And when combining bytes into a multi byte type, try using shift operations and bitwise OR. That makes the code a bit more readable.
Also keep divisions to a minimum, not only for speed but also for precission. Multiple divisions in a row will cause multiple rounding/truncation errors.

So having said that, this is how I’d do things (not the philosopher’s stone but an alternative way :wink: )

  uint32_t msTimeout = millis();
  while (Wire.available() < 6 && millis() - msTimeout < 10);
  if (Wire.available() >= 6)
  {
    Wire.read();          // drop first byte if not used anywhere else
    tHeight  = ((int)Wire.read()) << 12;
    tHeight |= ((int)Wire.read()) <<  4;
    tHeight |= ((int)Wire.read()) >>  4;
    temp     = ((int)Wire.read()) <<  4;
    temp    |= ((int)Wire.read()) >>  4;
    altitude = tHeight / 16.0;
    cTemp    = temp / 16.0; 
  }
  ...
  // multiple divisions unified
  // pressure = (pres / 4.0) / 1000.0;
  // better
  pressure = pres / 4000.0;

  // a better way to publish data
  char msg[128];
  snprintf(msg, sizeof[msg], "Altitude: %.2f m, Pressure: %.2f mbar, Temp: %.2f °C (%.2f °F)", altitude, pressure, cTemp, fTemp);
  Serial.println(msg);
  Particle.publish("envData", msg, PRIVATE);
  delay(1000);

@ScruffR I didn’t get unstuck yet but I am gonna tray what @peekay123 suggested. Gotta figure out how to scan but I think I can get that. :slight_smile: thanks for the help folks!