1 /* 2 * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha (at) intel.com> 3 * Copyright (c) 2014 Intel Corporation. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <iostream> 26 #include <string> 27 #include <stdexcept> 28 #include <unistd.h> 29 #include <stdlib.h> 30 31 #include "bmpx8x.h" 32 33 using namespace upm; 34 35 BMPX8X::BMPX8X (int bus, int devAddr, uint8_t mode) : m_controlAddr(devAddr), m_i2ControlCtx(bus) { 36 37 m_name = "BMPX8X"; 38 39 mraa::Result ret = m_i2ControlCtx.address(m_controlAddr); 40 if (ret != mraa::SUCCESS) { 41 throw std::invalid_argument(std::string(__FUNCTION__) + 42 ": mraa_i2c_address() failed"); 43 return; 44 } 45 46 if (i2cReadReg_8 (0xD0) != 0x55) { 47 throw std::runtime_error(std::string(__FUNCTION__) + 48 ": Invalid chip ID"); 49 return; 50 } 51 52 if (mode > BMP085_ULTRAHIGHRES) { 53 mode = BMP085_ULTRAHIGHRES; 54 } 55 oversampling = mode; 56 57 /* read calibration data */ 58 ac1 = i2cReadReg_16 (BMP085_CAL_AC1); 59 ac2 = i2cReadReg_16 (BMP085_CAL_AC2); 60 ac3 = i2cReadReg_16 (BMP085_CAL_AC3); 61 ac4 = i2cReadReg_16 (BMP085_CAL_AC4); 62 ac5 = i2cReadReg_16 (BMP085_CAL_AC5); 63 ac6 = i2cReadReg_16 (BMP085_CAL_AC6); 64 65 b1 = i2cReadReg_16 (BMP085_CAL_B1); 66 b2 = i2cReadReg_16 (BMP085_CAL_B2); 67 68 mb = i2cReadReg_16 (BMP085_CAL_MB); 69 mc = i2cReadReg_16 (BMP085_CAL_MC); 70 md = i2cReadReg_16 (BMP085_CAL_MD); 71 } 72 73 int32_t 74 BMPX8X::getPressure () { 75 int32_t UT, UP, B3, B5, B6, X1, X2, X3, p; 76 uint32_t B4, B7; 77 78 UT = getTemperatureRaw(); 79 UP = getPressureRaw(); 80 B5 = computeB5(UT); 81 82 // do pressure calcs 83 B6 = B5 - 4000; 84 X1 = ((int32_t)b2 * ( (B6 * B6)>>12 )) >> 11; 85 X2 = ((int32_t)ac2 * B6) >> 11; 86 X3 = X1 + X2; 87 B3 = ((((int32_t)ac1*4 + X3) << oversampling) + 2) / 4; 88 89 X1 = ((int32_t)ac3 * B6) >> 13; 90 X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16; 91 X3 = ((X1 + X2) + 2) >> 2; 92 B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15; 93 B7 = ((uint32_t)UP - B3) * (uint32_t)( 50000UL >> oversampling ); 94 95 if (B7 < 0x80000000) { 96 p = (B7 * 2) / B4; 97 } else { 98 p = (B7 / B4) * 2; 99 } 100 X1 = (p >> 8) * (p >> 8); 101 X1 = (X1 * 3038) >> 16; 102 X2 = (-7357 * p) >> 16; 103 104 p = p + ((X1 + X2 + (int32_t)3791)>>4); 105 106 return p; 107 } 108 109 int32_t 110 BMPX8X::getPressureRaw () { 111 uint32_t raw; 112 113 i2cWriteReg (BMP085_CONTROL, BMP085_READPRESSURECMD + (oversampling << 6)); 114 115 if (oversampling == BMP085_ULTRALOWPOWER) { 116 usleep(5000); 117 } else if (oversampling == BMP085_STANDARD) { 118 usleep(8000); 119 } else if (oversampling == BMP085_HIGHRES) { 120 usleep(14000); 121 } else { 122 usleep(26000); 123 } 124 125 raw = i2cReadReg_16 (BMP085_PRESSUREDATA); 126 127 raw <<= 8; 128 raw |= i2cReadReg_8 (BMP085_PRESSUREDATA + 2); 129 raw >>= (8 - oversampling); 130 131 return raw; 132 } 133 134 int16_t 135 BMPX8X::getTemperatureRaw () { 136 i2cWriteReg (BMP085_CONTROL, BMP085_READTEMPCMD); 137 usleep(5000); 138 return i2cReadReg_16 (BMP085_TEMPDATA); 139 } 140 141 float 142 BMPX8X::getTemperature () { 143 int32_t UT, B5; // following ds convention 144 float temp; 145 146 UT = getTemperatureRaw (); 147 148 B5 = computeB5 (UT); 149 temp = (B5 + 8) >> 4; 150 temp /= 10; 151 152 return temp; 153 } 154 155 int32_t 156 BMPX8X::getSealevelPressure(float altitudeMeters) { 157 float pressure = getPressure (); 158 return (int32_t)(pressure / pow(1.0-altitudeMeters/44330, 5.255)); 159 } 160 161 float 162 BMPX8X::getAltitude (float sealevelPressure) { 163 float altitude; 164 165 float pressure = getPressure (); 166 167 altitude = 44330 * (1.0 - pow(pressure /sealevelPressure,0.1903)); 168 169 return altitude; 170 } 171 172 int32_t 173 BMPX8X::computeB5(int32_t UT) { 174 int32_t X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) >> 15; 175 int32_t X2 = ((int32_t)mc << 11) / (X1+(int32_t)md); 176 177 return X1 + X2; 178 } 179 180 mraa::Result 181 BMPX8X::i2cWriteReg (uint8_t reg, uint8_t value) { 182 mraa::Result error = mraa::SUCCESS; 183 184 uint8_t data[2] = { reg, value }; 185 error = m_i2ControlCtx.address (m_controlAddr); 186 error = m_i2ControlCtx.write (data, 2); 187 188 return error; 189 } 190 191 uint16_t 192 BMPX8X::i2cReadReg_16 (int reg) { 193 uint16_t data; 194 195 m_i2ControlCtx.address(m_controlAddr); 196 m_i2ControlCtx.writeByte(reg); 197 198 m_i2ControlCtx.address(m_controlAddr); 199 m_i2ControlCtx.read((uint8_t *)&data, 0x2); 200 201 uint8_t high = (data & 0xFF00) >> 8; 202 data = (data << 8) & 0xFF00; 203 data |= high; 204 205 return data; 206 } 207 208 uint8_t 209 BMPX8X::i2cReadReg_8 (int reg) { 210 uint8_t data; 211 212 m_i2ControlCtx.address(m_controlAddr); 213 m_i2ControlCtx.writeByte(reg); 214 215 m_i2ControlCtx.address(m_controlAddr); 216 m_i2ControlCtx.read(&data, 0x1); 217 218 return data; 219 } 220