/* * Author: William Penner * Copyright (c) 2014 Intel Corporation. * * This application code supports the mpl3115a2 digital barometric pressure * and temperature sensor from Freescale. The datasheet is available * from their website: * http://cache.freescale.com/files/sensors/doc/data_sheet/MPL3115A2.pdf * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include "mpl3115a2.h" using namespace upm; MPL3115A2::MPL3115A2 (int bus, int devAddr, uint8_t mode) : m_i2ControlCtx(bus) { int id; m_name = MPL3115A2_NAME; m_controlAddr = devAddr; m_bus = bus; mraa::Result ret = m_i2ControlCtx.address(m_controlAddr); if (ret != mraa::SUCCESS) { throw std::runtime_error(std::string(__FUNCTION__) + ": mraa_i2c_address() failed"); return; } setOversampling(mode); id = i2cReadReg_8(MPL3115A2_WHO_AM_I); if (id != MPL3115A2_DEVICE_ID) { throw std::runtime_error(std::string(__FUNCTION__) + ": incorrect device id"); return; } } /* * Function to test the device and verify that is appears operational * Typically functioning sensors will return "noisy" values and would * be expected to change a bit. This fuction will check for this * variation. */ int MPL3115A2::testSensor(void) { int i, iTries; int iError = 0; float pressure, temperature; float fPMin, fPMax, fTMin, fTMax; fprintf(stdout, "Executing Sensor Test.\n" ); pressure = getPressure(true); temperature = getTemperature(false); fPMin = fPMax = pressure; fTMin = fTMax = temperature; iTries = 20; do { sampleData(); pressure = getPressure(true); temperature = getTemperature(false); if (pressure < fPMin) fPMin = pressure; if (pressure > fPMax) fPMax = pressure; if (temperature < fTMin) fTMin = temperature; if (temperature > fTMax) fTMax = temperature; } while(fPMin == fPMax && fTMin == fTMax && --iTries); if (fPMin == fPMax && fTMin == fTMax) { fprintf(stdout, " Warning - sensor values not changing.\n" ); return -1; } fprintf(stdout, " Test complete.\n"); return 0; } /* * Function to dump out the i2c register block to the screen */ void MPL3115A2::dumpSensor(void) { int i, j, ival; fprintf(stdout, "Dumping i2c block from %s\n", MPL3115A2_NAME); for (i=0; i < 256; i+=16) { fprintf(stdout, " %02x: ", i); for (j=i; j < i+16; j++) { fprintf(stdout, "%02x ", i2cReadReg_8(j)); } fprintf(stdout, "\n"); } } /* * Function used to soft RESET the MPL3115A2 device to ensure * it is in a known state. This function can be used to reset * the min/max temperature and pressure values. */ int MPL3115A2::resetSensor(void) { fprintf(stdout, "Resetting MPL3115A2 device\n" ); i2cWriteReg(MPL3115A2_CTRL_REG1, MPL3115A2_CTRL_RESET); usleep(50000); i2cWriteReg(MPL3115A2_CTRL_REG1, MPL3115A2_CTRL_RESET | MPL3115A2_SETOVERSAMPLE(m_oversampling)); return 0; } int MPL3115A2::sampleData(void) { int val; mraa::Result ret; int tries = 15; uint32_t us_delay; // trigger measurement ret = i2cWriteReg(MPL3115A2_CTRL_REG1, MPL3115A2_CTRL_OST | MPL3115A2_SETOVERSAMPLE(m_oversampling)); if (mraa::SUCCESS != ret) { fprintf(stdout, "Write to trigger measurement failed\n"); return -1; } // Calculate and delay the appopriate time for the measurement us_delay = ((1 << m_oversampling) * 4 + 2) * 1000; usleep(us_delay); // Loop waiting for the ready bit to become active while (tries-- > 0) { val = i2cReadReg_8(MPL3115A2_CTRL_REG1); /* wait for data ready, i.e. OST cleared */ if (!(val & MPL3115A2_CTRL_OST)) break; usleep(20000); } if (tries < 0) { throw std::runtime_error(std::string(__FUNCTION__) + ": timeout during measurement"); return -1; } return 0; } int32_t MPL3115A2::getPressureReg(int reg) { return ((i2cReadReg_16(reg) << 8)|(uint32_t)i2cReadReg_8(reg+2))*100/64; } int32_t MPL3115A2::getTempReg(int reg) { return (int32_t)((int16_t)i2cReadReg_16(reg)) * 1000 / 256; } float MPL3115A2::getPressure(int bSampleData) { int ret; // Trigger request to make a measurement if (bSampleData) { ret = sampleData(); if (ret < 0) { fprintf(stdout, "Error sampling pressure\n"); return -1; } } m_iPressure = getPressureReg(MPL3115A2_OUT_PRESS); return (float)m_iPressure / 100; } float MPL3115A2::getTemperature(int bSampleData) { int ret; // Trigger request to make a measurement if (bSampleData) { ret = sampleData(); if (ret < 0) { fprintf(stdout, "Error sampling temperature\n"); return -1; } } m_iTemperature = getTempReg(MPL3115A2_OUT_TEMP); return (float)m_iTemperature / 1000; } float MPL3115A2::getSealevelPressure(float altitudeMeters) { float fPressure = (float)m_iPressure / 100.0; return fPressure / pow(1.0-altitudeMeters/44330, 5.255); } float MPL3115A2::getAltitude (float sealevelPressure) { float fPressure = (float)m_iPressure / 100.0; return 44330 * (1.0 - pow(fPressure /sealevelPressure,0.1903)); } void MPL3115A2::setOversampling(uint8_t oversampling) { if (oversampling > MPL3115A2_MAXOVERSAMPLE) oversampling = MPL3115A2_MAXOVERSAMPLE; m_oversampling = oversampling; } uint8_t MPL3115A2::getOversampling(void) { return m_oversampling; } float MPL3115A2::getTemperatureMax(void) { return (float)getTempReg(MPL3115A2_T_MAX) / 1000; } float MPL3115A2::getTemperatureMin(void) { return (float)getTempReg(MPL3115A2_T_MIN) / 1000; } float MPL3115A2::getPressureMax(void) { return (float)getPressureReg(MPL3115A2_P_MAX) / 1000; } float MPL3115A2::getPressureMin(void) { return (float)getPressureReg(MPL3115A2_P_MIN) / 1000; } float MPL3115A2::convertTempCtoF(float fTemp) { return(fTemp * 9 / 5 + 32); } /* * This is set for 15degC (Pa = 0.0002961 in Hg) */ float MPL3115A2::convertPaToinHg(float fPressure) { return(fPressure * 0.0002961); } /* * Functions to read and write data to the i2c device */ mraa::Result MPL3115A2::i2cWriteReg (uint8_t reg, uint8_t value) { mraa::Result error = mraa::SUCCESS; uint8_t data[2] = { reg, value }; m_i2ControlCtx.address (m_controlAddr); error = m_i2ControlCtx.write (data, 2); if (error != mraa::SUCCESS) throw std::runtime_error(std::string(__FUNCTION__) + ":mraa_i2c_write() failed"); return error; } uint16_t MPL3115A2::i2cReadReg_16 (int reg) { uint16_t data; m_i2ControlCtx.address(m_controlAddr); data = (uint16_t)m_i2ControlCtx.readReg(reg) << 8; data |= (uint16_t)m_i2ControlCtx.readReg(reg+1); return data; } uint8_t MPL3115A2::i2cReadReg_8 (int reg) { m_i2ControlCtx.address(m_controlAddr); return m_i2ControlCtx.readReg(reg); }