Home | History | Annotate | Download | only in mpl3115a2
      1 /*
      2  * Author: William Penner <william.penner (at) intel.com>
      3  * Copyright (c) 2014 Intel Corporation.
      4  *
      5  * This application code supports the mpl3115a2 digital barometric pressure
      6  * and temperature sensor from Freescale.  The datasheet is available
      7  * from their website:
      8  * http://cache.freescale.com/files/sensors/doc/data_sheet/MPL3115A2.pdf
      9  *
     10  * Permission is hereby granted, free of charge, to any person obtaining a copy
     11  * of this software and associated documentation files (the "Software"), to deal
     12  * in the Software without restriction, including without limitation the rights
     13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14  * copies of the Software, and to permit persons to whom the Software is
     15  * furnished to do so, subject to the following conditions:
     16  *
     17  * The above copyright notice and this permission notice shall be included in
     18  * all copies or substantial portions of the Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     26  * THE SOFTWARE.
     27  */
     28 
     29 #include <iostream>
     30 #include <string>
     31 #include <stdexcept>
     32 #include <unistd.h>
     33 #include <stdlib.h>
     34 
     35 #include "mpl3115a2.h"
     36 
     37 using namespace upm;
     38 
     39 MPL3115A2::MPL3115A2 (int bus, int devAddr, uint8_t mode) : m_i2ControlCtx(bus)
     40 {
     41     int id;
     42 
     43     m_name = MPL3115A2_NAME;
     44 
     45     m_controlAddr = devAddr;
     46     m_bus = bus;
     47 
     48     mraa::Result ret = m_i2ControlCtx.address(m_controlAddr);
     49     if (ret != mraa::SUCCESS) {
     50         throw std::runtime_error(std::string(__FUNCTION__) +
     51                                  ": mraa_i2c_address() failed");
     52         return;
     53     }
     54 
     55     setOversampling(mode);
     56 
     57     id = i2cReadReg_8(MPL3115A2_WHO_AM_I);
     58     if (id != MPL3115A2_DEVICE_ID)  {
     59         throw std::runtime_error(std::string(__FUNCTION__) +
     60                                  ": incorrect device id");
     61         return;
     62     }
     63 }
     64 
     65 /*
     66  * Function to test the device and verify that is appears operational
     67  * Typically functioning sensors will return "noisy" values and would
     68  * be expected to change a bit.  This fuction will check for this
     69  * variation.
     70  */
     71 
     72 int
     73 MPL3115A2::testSensor(void)
     74 {
     75     int i, iTries;
     76     int iError = 0;
     77     float pressure, temperature;
     78     float fPMin, fPMax, fTMin, fTMax;
     79 
     80     fprintf(stdout, "Executing Sensor Test.\n" );
     81 
     82     pressure    = getPressure(true);
     83     temperature = getTemperature(false);
     84     fPMin = fPMax = pressure;
     85     fTMin = fTMax = temperature;
     86 
     87     iTries = 20;
     88     do {
     89         sampleData();
     90         pressure = getPressure(true);
     91         temperature = getTemperature(false);
     92         if (pressure < fPMin)    fPMin = pressure;
     93         if (pressure > fPMax)    fPMax = pressure;
     94         if (temperature < fTMin) fTMin = temperature;
     95         if (temperature > fTMax) fTMax = temperature;
     96     }
     97     while(fPMin == fPMax && fTMin == fTMax && --iTries);
     98 
     99     if (fPMin == fPMax && fTMin == fTMax) {
    100         fprintf(stdout, "  Warning - sensor values not changing.\n" );
    101         return -1;
    102     }
    103 
    104     fprintf(stdout, "  Test complete.\n");
    105 
    106     return 0;
    107 }
    108 
    109 /*
    110  * Function to dump out the i2c register block to the screen
    111  */
    112 
    113 void
    114 MPL3115A2::dumpSensor(void)
    115 {
    116     int i, j, ival;
    117 
    118     fprintf(stdout, "Dumping i2c block from %s\n", MPL3115A2_NAME);
    119     for (i=0; i < 256; i+=16) {
    120         fprintf(stdout, "  %02x: ", i);
    121         for (j=i; j < i+16; j++) {
    122             fprintf(stdout, "%02x ", i2cReadReg_8(j));
    123         }
    124         fprintf(stdout, "\n");
    125     }
    126 }
    127 
    128 /*
    129  * Function used to soft RESET the MPL3115A2 device to ensure
    130  * it is in a known state.  This function can be used to reset
    131  * the min/max temperature and pressure values.
    132  */
    133 
    134 int
    135 MPL3115A2::resetSensor(void)
    136 {
    137     fprintf(stdout, "Resetting MPL3115A2 device\n" );
    138     i2cWriteReg(MPL3115A2_CTRL_REG1, MPL3115A2_CTRL_RESET);
    139     usleep(50000);
    140     i2cWriteReg(MPL3115A2_CTRL_REG1, MPL3115A2_CTRL_RESET |
    141             MPL3115A2_SETOVERSAMPLE(m_oversampling));
    142 
    143     return 0;
    144 }
    145 
    146 int
    147 MPL3115A2::sampleData(void)
    148 {
    149     int val;
    150     mraa::Result ret;
    151     int tries = 15;
    152     uint32_t us_delay;
    153 
    154     // trigger measurement
    155     ret = i2cWriteReg(MPL3115A2_CTRL_REG1,
    156             MPL3115A2_CTRL_OST | MPL3115A2_SETOVERSAMPLE(m_oversampling));
    157     if (mraa::SUCCESS != ret) {
    158         fprintf(stdout, "Write to trigger measurement failed\n");
    159         return -1;
    160     }
    161 
    162     // Calculate and delay the appopriate time for the measurement
    163     us_delay = ((1 << m_oversampling) * 4 + 2) * 1000;
    164     usleep(us_delay);
    165 
    166     // Loop waiting for the ready bit to become active
    167     while (tries-- > 0) {
    168         val = i2cReadReg_8(MPL3115A2_CTRL_REG1);
    169 
    170         /* wait for data ready, i.e. OST cleared */
    171         if (!(val & MPL3115A2_CTRL_OST))
    172             break;
    173         usleep(20000);
    174     }
    175     if (tries < 0) {
    176         throw std::runtime_error(std::string(__FUNCTION__) +
    177                                  ": timeout during measurement");
    178         return -1;
    179     }
    180 
    181     return 0;
    182 }
    183 
    184 int32_t
    185 MPL3115A2::getPressureReg(int reg) {
    186     return ((i2cReadReg_16(reg) << 8)|(uint32_t)i2cReadReg_8(reg+2))*100/64;
    187 }
    188 
    189 int32_t
    190 MPL3115A2::getTempReg(int reg) {
    191     return (int32_t)((int16_t)i2cReadReg_16(reg)) * 1000 / 256;
    192 }
    193 
    194 float
    195 MPL3115A2::getPressure(int bSampleData) {
    196     int ret;
    197 
    198     // Trigger request to make a measurement
    199     if (bSampleData) {
    200         ret = sampleData();
    201         if (ret < 0) {
    202             fprintf(stdout, "Error sampling pressure\n");
    203             return -1;
    204         }
    205     }
    206     m_iPressure = getPressureReg(MPL3115A2_OUT_PRESS);
    207 
    208     return (float)m_iPressure / 100;
    209 }
    210 
    211 float
    212 MPL3115A2::getTemperature(int bSampleData) {
    213     int ret;
    214 
    215     // Trigger request to make a measurement
    216     if (bSampleData) {
    217         ret = sampleData();
    218         if (ret < 0) {
    219             fprintf(stdout, "Error sampling temperature\n");
    220             return -1;
    221         }
    222 	}
    223     m_iTemperature = getTempReg(MPL3115A2_OUT_TEMP);
    224 
    225     return (float)m_iTemperature / 1000;
    226 }
    227 
    228 float
    229 MPL3115A2::getSealevelPressure(float altitudeMeters) {
    230     float fPressure = (float)m_iPressure / 100.0;
    231     return fPressure / pow(1.0-altitudeMeters/44330, 5.255);
    232 }
    233 
    234 float
    235 MPL3115A2::getAltitude (float sealevelPressure) {
    236     float fPressure = (float)m_iPressure / 100.0;
    237     return 44330 * (1.0 - pow(fPressure /sealevelPressure,0.1903));
    238 }
    239 
    240 void
    241 MPL3115A2::setOversampling(uint8_t oversampling)
    242 {
    243     if (oversampling > MPL3115A2_MAXOVERSAMPLE)
    244         oversampling = MPL3115A2_MAXOVERSAMPLE;
    245     m_oversampling = oversampling;
    246 }
    247 
    248 uint8_t
    249 MPL3115A2::getOversampling(void)
    250 {
    251     return m_oversampling;
    252 }
    253 
    254 float
    255 MPL3115A2::getTemperatureMax(void)
    256 {
    257     return (float)getTempReg(MPL3115A2_T_MAX) / 1000;
    258 }
    259 
    260 float
    261 MPL3115A2::getTemperatureMin(void)
    262 {
    263     return (float)getTempReg(MPL3115A2_T_MIN) / 1000;
    264 }
    265 
    266 float
    267 MPL3115A2::getPressureMax(void)
    268 {
    269     return (float)getPressureReg(MPL3115A2_P_MAX) / 1000;
    270 }
    271 
    272 float
    273 MPL3115A2::getPressureMin(void)
    274 {
    275     return (float)getPressureReg(MPL3115A2_P_MIN) / 1000;
    276 }
    277 
    278 float
    279 MPL3115A2::convertTempCtoF(float fTemp)
    280 {
    281     return(fTemp * 9 / 5 + 32);
    282 }
    283 
    284 /*
    285  * This is set for 15degC (Pa = 0.0002961 in Hg)
    286  */
    287 float
    288 MPL3115A2::convertPaToinHg(float fPressure)
    289 {
    290     return(fPressure * 0.0002961);
    291 }
    292 
    293 /*
    294  * Functions to read and write data to the i2c device
    295  */
    296 
    297 mraa::Result
    298 MPL3115A2::i2cWriteReg (uint8_t reg, uint8_t value) {
    299     mraa::Result error = mraa::SUCCESS;
    300 
    301     uint8_t data[2] = { reg, value };
    302     m_i2ControlCtx.address (m_controlAddr);
    303     error = m_i2ControlCtx.write (data, 2);
    304 
    305     if (error != mraa::SUCCESS)
    306       throw std::runtime_error(std::string(__FUNCTION__) +
    307                                ":mraa_i2c_write() failed");
    308     return error;
    309 }
    310 
    311 uint16_t
    312 MPL3115A2::i2cReadReg_16 (int reg) {
    313     uint16_t data;
    314 
    315     m_i2ControlCtx.address(m_controlAddr);
    316     data  = (uint16_t)m_i2ControlCtx.readReg(reg) << 8;
    317     data |= (uint16_t)m_i2ControlCtx.readReg(reg+1);
    318 
    319     return data;
    320 }
    321 
    322 uint8_t
    323 MPL3115A2::i2cReadReg_8 (int reg) {
    324     m_i2ControlCtx.address(m_controlAddr);
    325     return m_i2ControlCtx.readReg(reg);
    326 }
    327 
    328