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