Library to wrapper most of the functions on the MPL3115A2 pressure and temperature sensor.

Dependents:   WeatherBalloon4180 WeatherBalloon4180 mbed_rifletool Smart_Watch_4180_Final_Design ... more

MPL3115A2 Precision Altimeter

This class wraps the functions of the MPL3115A2 sensor into a usable class that exposes most functions to your project. Functions that are not exposed can easily be added using the existing functions in this library. Specifically, I did not add any functions to handle FIFO logging or the use of either of the pin interrupts. This should not be too difficult to add if you need those features.

The motivation here was to get a set of support classes together that supported the chip and could be expanded on. With this library you can extract all relevant data from the sensor.

Be sure to download the DATASHEET and the App Note AN4519.

This library was created using the mbed NXP LPC11U24. Pins p27 and p28 were used for the I2C functions. Be sure to install 1K pull-up resistors on both lines. Also, if you're not using the SparkFun breakout board, be sure to use the right caps on the power pin. If you don't, the jitter can cause problems.

This library was inspired by the similar library available for the Arduino written by Nathan Seidle at SparkFun. I copied some of the number crunching routines and tried to follow his style of coding for the library. That way users of Arduinos could step into this library a little easier.

Below is some sample code that outputs the sensor data to a serial debug terminal window. If you have a logic analyzer, like the Saleae Logic, then you might not need the debug terminal window. If you still need the serial driver for your mbed, you can get it here.

Sample Code

#include "mbed.h"
#include "MPL3115A2.h"

I2C i2c(p28, p27);       // sda, scl

// Comment out all of the references to 'pc' on this page if you don't have the 
// serial debug driver for your mbed board installed on your computer. If you do,
// I personally like to use Putty as the terminal window to capture debug messages.
Serial pc(USBTX, USBRX); // tx, rx

// Again, remove the '&pc' parameter is you're not debugging.
MPL3115A2 sensor(&i2c, &pc);

DigitalOut myled(LED1);     // Sanity check to make sure the program is working.
DigitalOut powerPin(p21);   // <-- I powered the sensor from a pin. You don't have to.

int main() {
    
    powerPin = 1;
    wait_ms(300);

    pc.printf("** MPL3115A2 SENSOR **\r\n");

    sensor.init();

    pc.printf("Who Am I: 0x%X\r\n", sensor.whoAmI());

    Altitude a;
    Temperature t;
    Pressure p;
    
    // Offsets for Dacula, GA
    sensor.setOffsetAltitude(83);
    sensor.setOffsetTemperature(20);
    sensor.setOffsetPressure(-32);
    
    while(1) 
    {
        sensor.readAltitude(&a);
        sensor.readTemperature(&t);
        
        sensor.setModeStandby();
        sensor.setModeBarometer();
        sensor.setModeActive();
        sensor.readPressure(&p);
        
        pc.printf("Altitude: %sft, Temp: %sºF, Pressure: %sPa\r\n", a.print(), t.print(), p.print());
        pc.printf("OFF_H: 0x%X, OFF_T: 0x%X, OFF_P: 0x%X\r\n", sensor.offsetAltitude(), sensor.offsetTemperature(), sensor.offsetPressure());
    
        myled = 1;
        wait(5);
        myled = 0;
        wait(5);

        sensor.setModeStandby();
        sensor.setModeAltimeter();
        sensor.setModeActive();
    }
}

MPL3115A2.cpp

Committer:
sophtware
Date:
2014-04-02
Revision:
3:7c7c1ea6fc33
Parent:
0:beb43bc3d6d4

File content as of revision 3:7c7c1ea6fc33:

#include "MPL3115A2.h"
#include "mbed.h"

#include "stdarg.h" // For debugOut use of the ... parameter and va_list

MPL3115A2::MPL3115A2(I2C *i2c, Serial *pc) : _i2c(i2c), _debug(pc)
{
}

// By default I set the sensor to altimeter mode. I inserted a 1ms pause 
// between each call to allow logic capture if needed. This give a small
// gap between captures on the bus to make working with the data easier.
void MPL3115A2::init()
{
    setModeStandby();
    wait_ms(1);
    setModeAltimeter();
    wait_ms(1);
    setOversampleRate(7);
    wait_ms(1);
    enableEventFlags();
    wait_ms(1);
    setModeActive();
    wait_ms(1);
}

// This method wait for a specified amount of time for one of the data
// ready flags to be set. You need to pass in the correct data ready
// mask for this to work. See page 22 of the datasheet.
int MPL3115A2::dataReady(const char mask)
{
    int attempts = 0;
 
    while ((i2cRead(STATUS) & mask) == 0)
    {
        attempts++;
        
        if(attempts > MAX_DATA_READY_ATTEMPTS) 
            return 0; // Failed
            
        wait_ms(1);
    }
    
    return 1; // Success
}

Altitude* MPL3115A2::readAltitude(Altitude* a)
{
    // Force the sensor to take a new reading.
    toggleOneShot();
    
    // Wait for the data to be ready.
    if (!pressureDataReady())
    {
        debugOut("MPL3115A2::readAltitude: Sensor failed to generate an altitude reading in a reasonable time.\r\n");
        
        // We leave the altitude object as is if we encounter an error.
        return a;
    }
        
    // Get the new data from the sensor.
    _i2c->start();                              // Start
    if (_i2c->write(MPL3115A2_ADDRESS) != 1)    // A write to device
        debugOut("MPL3115A2::readAltitude: Sensor failed to respond to write request at address 0x%X\r\n", MPL3115A2_ADDRESS);
    
    if (_i2c->write(OUT_P_MSB) != 1)            // Register to read
        debugOut("MPL3115A2::readAltitude: Sensor at address 0x%X did not acknowledge register 0x%X\r\n", MPL3115A2_ADDRESS, OUT_P_MSB);
    
    // Write the data directly into our Altitude object. This object
    // takes care of converting the compressed data from the sensor, and
    // provides functions to get the data in various units. And it also
    // has a print function to output the data as a string.
    _i2c->read(MPL3115A2_ADDRESS, (*a), Altitude::size);
    a->setAltitude();

    return a;
}

// See readAltitude for comments about this function.
Pressure* MPL3115A2::readPressure(Pressure* p)
{
    toggleOneShot();
    
    if (!pressureDataReady())
    {
        debugOut("MPL3115A2::readPressure: Sensor failed to generate a pressure reading in a reasonable time.\r\n");
        return p;
    }

    _i2c->start(); 
    if (_i2c->write(MPL3115A2_ADDRESS) != 1)
        debugOut("MPL3115A2::readPressure: Sensor failed to respond to write request at address 0x%X\r\n", MPL3115A2_ADDRESS);
    
    if (_i2c->write(OUT_P_MSB) != 1) 
        debugOut("MPL3115A2::readPressure: Sensor at address 0x%X did not acknowledge register 0x%X\r\n", MPL3115A2_ADDRESS, OUT_P_MSB);
    
    _i2c->read(MPL3115A2_ADDRESS, (*p), Pressure::size);
    p->setPressure();

    return p;
}

// See readAltitude for comments about this function.
Temperature* MPL3115A2::readTemperature(Temperature* t)
{
    toggleOneShot();

    if (!temperatureDataReady())
    {
        debugOut("MPL3115A2::readTemperature: Sensor failed to generate a temperature reading in a reasonable time.\r\n");
        return t;
    }

    _i2c->start();  
    if (_i2c->write(MPL3115A2_ADDRESS) != 1)
        debugOut("MPL3115A2::readTemperature: Sensor failed to respond to write request at address 0x%X\r\n", MPL3115A2_ADDRESS);
    
    if (_i2c->write(OUT_T_MSB) != 1)        
        debugOut("MPL3115A2::readTemperature: Sensor at address 0x%X did not acknowledge register 0x%X\r\n", MPL3115A2_ADDRESS, OUT_P_MSB);
    
    _i2c->read(MPL3115A2_ADDRESS, (*t), Temperature::size);
    t->setTemperature();
    
    return t;
}

void MPL3115A2::setModeAltimeter()
{
    setRegisterBit(CTRL_REG1, 0x80);    // Set ALT bit
}

void MPL3115A2::setModeBarometer()
{
    clearRegisterBit(CTRL_REG1, 0x80);  // Clear ALT bit
}

void MPL3115A2::setModeStandby()
{
    clearRegisterBit(CTRL_REG1, 0x01);  // Clear SBYB bit for Standby mode
}
void MPL3115A2::setModeActive()
{
    setRegisterBit(CTRL_REG1, 0x01);    // Set SBYB bit for Active mode
}

void MPL3115A2::setOversampleRate(char sampleRate)
{
    if(sampleRate > 7) 
        sampleRate = 7;                 // OS cannot be larger than 0b.0111
    
    sampleRate <<= 3;                   // Align it for the CTRL_REG1 register
  
    char temp = i2cRead(CTRL_REG1);     // Read current settings
    temp &= 0xC7;                       // Clear out old OS bits
    temp |= sampleRate;                 // Mask in new OS bits
    i2cWrite(CTRL_REG1, temp);
}

void MPL3115A2::enableEventFlags()
{
    i2cWrite(PT_DATA_CFG, 0x07); // Enable all three pressure and temp event flags 
}

void MPL3115A2::toggleOneShot(void)
{
    clearRegisterBit(CTRL_REG1, 0x02);  // Clear OST bit
    setRegisterBit(CTRL_REG1, 0x02);    // Set the OST bit.
}

void MPL3115A2::clearRegisterBit(const char regAddr, const char bitMask)
{
    char temp = i2cRead(regAddr);   // Read the current register value
    temp &= ~bitMask;               // Clear the bit from the value
    i2cWrite(regAddr, temp);        // Write register value back
}

void MPL3115A2::setRegisterBit(const char regAddr, const char bitMask)
{
    char temp = i2cRead(regAddr);   // Read the current register value
    temp |= bitMask;                // Set the bit in the value
    i2cWrite(regAddr, temp);        // Write register value back
}

char MPL3115A2::i2cRead(char regAddr)
{
    _i2c->start();                              // Start
    if (_i2c->write(MPL3115A2_ADDRESS)!=1)      // A write to device
        debugOut("MPL3115A2::i2cRead: Sensor failed to respond to write request at address 0x%X\r\n", MPL3115A2_ADDRESS);
    
    if (_i2c->write(regAddr)!=1)                // Register to read
        debugOut("MPL3115A2::i2cRead: Sensor at address 0x%X did not acknowledge register 0x%X\r\n", MPL3115A2_ADDRESS, regAddr);
    
    _i2c->start();                  
    if (_i2c->write(MPL3115A2_ADDRESS|0x01)!=1) // Read from device
        debugOut("MPL3115A2::i2cRead: Sensor failed to respond to read request at address 0x%X\r\n", MPL3115A2_ADDRESS);

    char result = _i2c->read(READ_NAK);         // Read the data
    _i2c->stop();
    
    return result;  
}

void MPL3115A2::i2cWrite(char regAddr, char value)
{
    char cmd[2];
    cmd[0] = regAddr;
    cmd[1] = value;
    if (_i2c->write(MPL3115A2_ADDRESS, cmd, 2) != 0)
        debugOut("MPL3115A2::i2cWrite: Failed writing value (%d, 0x%X) to register 0x%X\r\n", value, regAddr);    
}

void MPL3115A2::debugOut(const char * format, ...)
{
    if (_debug == NULL)
        return;
        
    va_list arg;
    _debug->printf(format, arg);
}