bmp280/bme280: C port, C++ wraps C

Some private methods (relating to calibration/compensation) are no
longer exposed.  In addition, the driver auto-detects the chip (BMP280
or BME280) and acts accordingly, rather than requiring the
specification of a chip id in the ctor.

The getHumidity() method no longer accepts an arguement representing
pressure at sea level.  A new method is provided to specify this.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
This commit is contained in:
Jon Trulson 2017-03-10 09:57:09 -07:00
parent 58cdfadf4e
commit c4a506f5a3
17 changed files with 1977 additions and 1215 deletions

View File

@ -6,6 +6,11 @@ compatibility between releases:
# current master
* **bmp280/bme280** Some private methods are no longer exposed
(such as the calibration and compensation routines). In addition,
the *getHumidity()* method no longer accepts an argument representing
pressure at sea level. A separate method is provided to set this now.
* **bno055** This module no longer uses std::strings to pass around
binary data (*read/writeCalibrationData()*). Rather, now *std::vectors* of
the appropriate type are used. In addition, methods that previously

View File

@ -31,7 +31,7 @@
using namespace std;
using namespace upm;
int shouldRun = true;
bool shouldRun = true;
void sig_handler(int signo)
{

View File

@ -1,6 +1,8 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
* Copyright (c) 2016-2017 Intel Corporation.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -31,7 +33,7 @@
using namespace std;
using namespace upm;
int shouldRun = true;
bool shouldRun = true;
void sig_handler(int signo)
{

View File

@ -150,6 +150,7 @@ add_example (wfs)
add_example (enc03r)
add_example (nunchuck)
add_example (bno055)
add_example (bmp280)
# Custom examples
add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps)
@ -161,3 +162,4 @@ add_custom_example (button_intr-example-c button_intr.c button)
add_custom_example (mcp2515-txrx-example-c mcp2515-txrx.c mcp2515)
add_custom_example (le910-example-c le910.c uartat)
add_custom_example (speaker_pwm-example-c speaker_pwm.c speaker)
add_custom_example (bme280-example-c bme280.c bmp280)

89
examples/c/bme280.c Normal file
View File

@ -0,0 +1,89 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* The MIT License
*
* 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 <unistd.h>
#include <stdio.h>
#include <signal.h>
#include "upm_utilities.h"
#include "bmp280.h"
bool shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
int main(int argc, char **argv)
{
signal(SIGINT, sig_handler);
//! [Interesting]
// Instantiate a BME280 instance using default i2c bus and
// address. We use the BMP280 driver to do all of our work, since
// the BMP280 and the BME280 are identical except for the fact
// that the BME280 includes a humidity sensor.
bmp280_context sensor = bmp280_init(BME280_DEFAULT_I2C_BUS,
BME280_DEFAULT_ADDR, -1);
if (!sensor)
{
printf("bmp280_init() failed\n");
return 1;
}
// For SPI, bus 0, you would pass -1 as the address, and a valid pin for CS:
// bmp280_init(BME280_DEFAULT_SPI_BUS,
// -1, 10)
while (shouldRun)
{
// update our values from the sensor
if (bmp280_update(sensor))
{
printf("bmp280_update() failed\n");
bmp280_close(sensor);
return 1;
}
printf("Compensation Temperature: %f C\n",
bmp280_get_temperature(sensor));
printf("Pressure: %f Pa\n", bmp280_get_pressure(sensor));
printf("Computed Altitude: %f m\n", bmp280_get_altitude(sensor));
printf("Relative Humidity: %f %%\n\n", bmp280_get_humidity(sensor));
upm_delay(1);
}
//! [Interesting]
printf("Exiting...\n");
bmp280_close(sensor);
return 0;
}

86
examples/c/bmp280.c Normal file
View File

@ -0,0 +1,86 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* The MIT License
*
* 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 <unistd.h>
#include <stdio.h>
#include <signal.h>
#include "upm_utilities.h"
#include "bmp280.h"
bool shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
int main(int argc, char **argv)
{
signal(SIGINT, sig_handler);
//! [Interesting]
// Instantiate a BMP280 instance using default i2c bus and address
bmp280_context sensor = bmp280_init(BMP280_DEFAULT_I2C_BUS,
BMP280_DEFAULT_ADDR, -1);
if (!sensor)
{
printf("bmp280_init() failed\n");
return 1;
}
// For SPI, bus 0, you would pass -1 as the address, and a valid pin for CS:
// bmp280_init(BMP280_DEFAULT_SPI_BUS,
// -1, 10)
while (shouldRun)
{
// update our values from the sensor
if (bmp280_update(sensor))
{
printf("bmp280_update() failed\n");
bmp280_close(sensor);
return 1;
}
printf("Compensation Temperature: %f C\n",
bmp280_get_temperature(sensor));
printf("Pressure: %f Pa\n", bmp280_get_pressure(sensor));
printf("Computed Altitude: %f m\n\n", bmp280_get_altitude(sensor));
upm_delay(1);
}
printf("Exiting...\n");
bmp280_close(sensor);
//! [Interesting]
return 0;
}

View File

@ -1,5 +1,9 @@
set (libname "bmp280")
set (libdescription "Bosch Atmospheric Sensor Library (bmp280 and Bme280)")
set (module_src ${libname}.cxx bme280.cxx)
set (module_hpp ${libname}.hpp bme280.hpp)
upm_module_init(interfaces mraa)
upm_mixed_module_init (NAME bmp280
DESCRIPTION "Bosch Atmospheric Sensor Library (BMP280 and BME280)"
C_HDR bmp280.h bmp280_regs.h
C_SRC bmp280.c
CPP_HDR bmp280.hpp bme280.hpp
CPP_SRC bmp280.cxx bme280.cxx
CPP_WRAPS_C
REQUIRES mraa interfaces)
target_link_libraries(${libnamec} m)

View File

@ -1,6 +1,8 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
* Copyright (c) 2016-2017 Intel Corporation.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -34,141 +36,23 @@
using namespace upm;
using namespace std;
BME280::BME280(int bus, int addr, int cs, uint8_t theChipID) :
BMP280(bus, addr, cs, theChipID)
BME280::BME280(int bus, int addr, int cs) :
BMP280(bus, addr, cs)
{
m_humidity = 0;
m_dig_H1 = 0;
m_dig_H2 = 0;
m_dig_H3 = 0;
m_dig_H4 = 0;
m_dig_H5 = 0;
m_dig_H6 = 0;
// set sleep mode for now
setMeasureMode(MODE_SLEEP);
// read calibration data
readCalibrationData();
// set the default mode to the highest resolution mode
setUsageMode(USAGE_MODE_INDOOR_NAV);
}
BME280::~BME280()
{
}
void BME280::update()
{
// call the base class method first. This will handle the details
// WRT forced mode so that we can always be sure to read valid data
// regardless of the underlying measurement mode.
BMP280::update();
int32_t hum = 0;
const int dataLen = 2;
uint8_t data[dataLen];
memset(data, 0, dataLen);
int rv;
if ((rv = readRegs(REG_HUMIDITY_MSB, data, dataLen)) != dataLen)
{
throw std::runtime_error(std::string(__FUNCTION__)
+ ": readRegs() failed, returned "
+ std::to_string(rv));
}
// 20 bits unsigned stored in a 32bit signed quanty
hum = ( (data[0] << 8) | data[1] );
m_humidity = float(bme280_compensate_H_int32(hum));
m_humidity /= 1024.0;
}
void BME280::readCalibrationData()
{
m_dig_H1 = readReg(REG_CALIB_DIG_H1);
const int calibLen = 7;
uint8_t calibData[calibLen];
readRegs(REG_CALIB_DIG_H2_LSB, calibData, calibLen);
m_dig_H2 = int16_t((calibData[1] << 8) | calibData[0]);
m_dig_H3 = calibData[2];
m_dig_H4 = int16_t( (calibData[3] << 4) |
(calibData[4] & 0x0f) );
m_dig_H5 = int16_t( ((calibData[4] & 0xf0) >> 4) |
(calibData[5] << 4) );
m_dig_H6 = int8_t(calibData[6]);
# if 0
cerr << std::dec
<< "H1: " << (int)m_dig_H1
<< " H2: " << (int)m_dig_H2
<< " H3: " << (int)m_dig_H3
<< " H4: " << (int)m_dig_H4
<< " H5: " << (int)m_dig_H5
<< " H6: " << (int)m_dig_H5
<< endl;
# endif // 0
// The BMP280 ctor will call it's version of readCalibrationData
}
float BME280::getHumidity()
{
return m_humidity;
return bmp280_get_humidity(m_bmp280);
}
void BME280::setOversampleRateHumidity(OSRS_H_T rate)
void BME280::setOversampleRateHumidity(BME280_OSRS_H_T rate)
{
uint8_t reg = readReg(REG_CTRL_HUM);
reg &= ~(_CTRL_HUM_OSRS_H_MASK << _CTRL_HUM_OSRS_H_SHIFT);
reg |= (rate << _CTRL_HUM_OSRS_H_SHIFT);
writeReg(REG_CTRL_HUM, reg);
bmp280_set_oversample_rate_humidity(m_bmp280, rate);
}
void BME280::setUsageMode(USAGE_MODE_T mode)
{
// Here, we just set the default humidity oversample to 1 and then
// call the base method.
m_humidity = 0;
// set sleep mode first
setMeasureMode(MODE_SLEEP);
setOversampleRateHumidity(OSRS_H_OVERSAMPLING_1);
BMP280::setUsageMode(mode);
}
// This function comes from the BMP180 datasheet, section 4.2.3
// Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format
// (22 integer and 10 fractional bits). Output value of “47445”
// represents 47445/1024 = 46.333 %RH
uint32_t BME280::bme280_compensate_H_int32(int32_t adc_H)
{
int32_t v_x1_u32r;
v_x1_u32r = (m_t_fine - ((int32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((int32_t)m_dig_H4) << 20) - (((int32_t)m_dig_H5) * v_x1_u32r)) +
((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)m_dig_H6)) >> 10) * (((v_x1_u32r * ((int32_t)m_dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * ((int32_t)m_dig_H2) + 8192) >> 14));
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)m_dig_H1)) >> 4));
v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
return (int32_t)(v_x1_u32r>>12);
}

View File

@ -1,6 +1,8 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
* Copyright (c) 2016-2017 Intel Corporation.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -24,192 +26,101 @@
#pragma once
#include <string>
#include <mraa/i2c.hpp>
#include <mraa/spi.hpp>
#include <mraa/gpio.hpp>
#include "interfaces/iHumiditySensor.hpp"
#include "bmp280.hpp"
#define BME280_DEFAULT_I2C_BUS 0
#define BME280_DEFAULT_SPI_BUS 0
#define BME280_DEFAULT_ADDR 0x77
#define BME280_DEFAULT_CHIPID 0x60
namespace upm {
/**
* @library bmp280
* @sensor bme280
* @comname Digital Humidity, Pressure, and Temperature Sensor
* @type pressure humidity
* @man adafruit
* @con i2c spi gpio
* @web https://www.adafruit.com/products/2652
*
* @brief API for the BME280 Digital Humidity, Pressure, and
* Temperature Sensor
*
* The BME280 is as combined digital humidity, pressure and
* temperature sensor based on proven sensing principles. The sensor
* module is housed in an extremely compact metal-lid LGA package
* with a footprint of only 2.5 * 2.5 mm2 with a height of 0.93
* mm. Its small dimensions and its low power consumption allow the
* implementation in battery driven devices such as handsets, GPS
* modules or watches. The BME280 is register and performance
* compatible to the Bosch Sensortec BMP280 digital pressure sensor
*
* @snippet bme280.cxx Interesting
*/
class BME280 : public BMP280, public IHumiditySensor {
public:
/**
* BMP280 registers
*/
typedef enum : uint8_t {
// Do not write into reserved bits.
// We only specify those registers specific to the BME280. The
// rest of them can be found in the BMP280 header file.
// read-only factory calibration data for humidity
REG_CALIB_DIG_H1 = 0xa1,
REG_CALIB_DIG_H2_LSB = 0xe1,
REG_CALIB_DIG_H2_MSB = 0xe2,
REG_CALIB_DIG_H3 = 0xe3,
REG_CALIB_DIG_H4_0 = 0xe4, // bits 8 -> 11:4
REG_CALIB_DIG_H4_1 = 0xe5, // bits 3:0 -> 3:0
REG_CALIB_DIG_H5_0 = 0xe5, // bits 7:4 -> 3:0
REG_CALIB_DIG_H5_1 = 0xe6, // bits 8 -> 11:4
REG_CALIB_DIG_H6 = 0xe7,
REG_CTRL_HUM = 0xf2,
REG_HUMIDITY_MSB = 0xfd,
REG_HUMIDITY_LSB = 0xfe
} BME280_REGS_T;
/**
* REG_CTRL_HUM bits
*/
typedef enum {
CTRL_HUM_OSRS_H0 = 0x01,
CTRL_HUM_OSRS_H1 = 0x02,
CTRL_HUM_OSRS_H2 = 0x04,
_CTRL_HUM_OSRS_H_MASK = 3,
_CTRL_HUM_OSRS_H_SHIFT = 0
// 0x08-0x80 reserved
} CTRL_HUM_T;
/**
* CTRL_HUM_OSRS_H values
*/
typedef enum {
OSRS_H_SKIPPED = 0,
OSRS_H_OVERSAMPLING_1 = 1, // x1
OSRS_H_OVERSAMPLING_2 = 2, // x2
OSRS_H_OVERSAMPLING_4 = 3,
OSRS_H_OVERSAMPLING_8 = 4,
OSRS_H_OVERSAMPLING_16 = 5
} OSRS_H_T;
/**
* BME280 constructor.
* @library bmp280
* @sensor bme280
* @comname Digital Humidity, Pressure, and Temperature Sensor
* @type pressure humidity
* @man adafruit
* @con i2c spi gpio
* @web https://www.adafruit.com/products/2652
*
* This device can support both I2C and SPI. For SPI, set the addr
* to -1, and specify a positive integer representing the Chip
* Select (CS) pin for the cs argument. If you are using a
* hardware CS pin, then you can connect the proper pin to the
* hardware CS pin on your MCU and supply -1 for cs. The default
* operating mode is I2C.
* @brief API for the BME280 Digital Humidity, Pressure, and
* Temperature Sensor
*
* @param bus I2C or SPI bus to use.
* @param address The address for this device. -1 for SPI.
* @param cs The gpio pin to use for the SPI Chip Select. -1 for
* I2C or for SPI with a hardware controlled pin.
* @param theChipID The chip ID used for validation
*/
BME280(int bus=BME280_DEFAULT_I2C_BUS, int addr=BME280_DEFAULT_ADDR,
int cs=-1, uint8_t theChipID=BME280_DEFAULT_CHIPID);
/**
* BME280 Destructor.
*/
virtual ~BME280();
/**
* Update the internal stored values from sensor data.
*/
virtual void update();
/**
* Return the current measured relative humidity. update() must
* have been called prior to calling this method.
* The BME280 is as combined digital humidity, pressure and
* temperature sensor based on proven sensing principles. The
* sensor module is housed in an extremely compact metal-lid LGA
* package with a footprint of only 2.5 * 2.5 mm2 with a height of
* 0.93 mm. Its small dimensions and its low power consumption
* allow the implementation in battery driven devices such as
* handsets, GPS modules or watches. The BME280 is register and
* performance compatible to the Bosch Sensortec BMP280 digital
* pressure sensor.
*
* @return The relative humidity in percent..
* @snippet bme280.cxx Interesting
*/
float getHumidity();
/**
* Set a general usage mode. This function can be used to
* configure the filters and oversampling for a particular use
* case. These settings are documented in the BMP280 and BME280
* datasheets.
*
* @param mode One of the USAGE_MODE_T values.
*/
virtual void setUsageMode(USAGE_MODE_T mode);
class BME280 : public BMP280, public IHumiditySensor {
public:
/**
* Set the humidity sensor oversampling parameter. See the data
* sheet for details. This value can be automatically set to a
* suitable value by using one of the predefined modes for
* setUsageMode().
*
* @param mode One of the OSRS_H_T values.
*/
void setOversampleRateHumidity(OSRS_H_T rate);
/**
* BME280 constructor.
*
* This driver supports both the BMP280 and the BME280. The
* BME280 adds a humidity sensor. The device type is detected
* automatically by querying the chip id register.
*
* This device can support both I2C and SPI. For SPI, set the addr
* to -1, and specify a positive integer representing the Chip
* Select (CS) pin for the cs argument. If you are using a
* hardware CS pin, then you can connect the proper pin to the
* hardware CS pin on your MCU and supply -1 for cs. The default
* operating mode is I2C.
*
* @param bus I2C or SPI bus to use.
* @param address The I2C address for this device. Use -1 for SPI.
* @param cs The gpio pin to use for the SPI Chip Select. Use -1
* for I2C, or for SPI with a hardware controlled pin.
* @throws std::runtime_error on failure.
*/
BME280(int bus=BME280_DEFAULT_I2C_BUS, int addr=BME280_DEFAULT_ADDR,
int cs=-1);
// Interface support
const char *getModuleName()
{
return "BME280";
/**
* BME280 Destructor.
*/
virtual ~BME280();
/**
* Return the current measured relative humidity. update()
* must have been called prior to calling this method. If the
* device is a bmp280 rather than a bme280, this method will
* always return 0.
*
* @return The relative humidity in percent.
*/
float getHumidity();
/**
* Set the humidity sensor oversampling parameter. See the data
* sheet for details. This value can be automatically set to a
* suitable value by using one of the predefined modes for
* setUsageMode().
*
* @param mode One of the OSRS_H_T values.
*/
void setOversampleRateHumidity(BME280_OSRS_H_T rate);
// Interface support
const char *getModuleName()
{
return "BME280";
};
int getHumidityRelative()
{
return int(getHumidity());
};
protected:
private:
};
int getHumidityRelative()
{
return int(getHumidity());
};
protected:
// relative humidity
float m_humidity;
// read the calibration data
virtual void readCalibrationData();
private:
// calibration data humidity
uint8_t m_dig_H1;
int16_t m_dig_H2;
uint8_t m_dig_H3;
int16_t m_dig_H4;
int16_t m_dig_H5;
int8_t m_dig_H6;
// Bosch supplied conversion/compensation functions from the
// datasheet.
uint32_t bme280_compensate_H_int32(int32_t adc_H);
};
}

778
src/bmp280/bmp280.c Normal file
View File

@ -0,0 +1,778 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016-2017 Intel Corporation.
*
* The MIT License
*
* 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 <string.h>
#include <assert.h>
#include <upm_utilities.h>
#include "bmp280.h"
// number of bytes of stored calibration data (bmp280)
#define BMP280_CALIBRATION_BYTES (26)
// BME280 has these additional calibration regs
#define BME280_CALIBRATION_BYTES (7)
// Number of bytes to get bmp280 data
#define BMP280_DATA_LEN (6)
// Number of bytes to get bme280 data
#define BME280_DATA_LEN (2)
// Uncomment the following to use test data as specified in the
// datasheet, section 3.12. This really only tests the compensation
// algorithm, and only for the bmp280 parts (temperature/pressure).
// #define BMP280_USE_TEST_DATA
// SPI CS on and off functions
static void _csOn(const bmp280_context dev)
{
assert(dev != NULL);
if (dev->gpio)
mraa_gpio_write(dev->gpio, 0);
}
static void _csOff(const bmp280_context dev)
{
assert(dev != NULL);
if (dev->gpio)
mraa_gpio_write(dev->gpio, 1);
}
// These functions come from the BMP280 datasheet, section 3.11.3
// Returns temperature in DegC, resolution is 0.01 DegC. Output value
// of "5123" equals 51.23 DegC. t_fine carries fine temperature as
// global value
static int32_t _bmp280_compensate_T_int32(const bmp280_context dev,
int32_t adc_T)
{
assert(dev != NULL);
int32_t var1, var2, T;
var1 = ((((adc_T>>3) - ((int32_t)dev->dig_T1<<1))) * ((int32_t)dev->dig_T2)) >> 11;
var2 = (((((adc_T>>4) - ((int32_t)dev->dig_T1)) * ((adc_T>>4) - ((int32_t)dev->dig_T1))) >> 12) *
((int32_t)dev->dig_T3)) >> 14;
dev->t_fine = var1 + var2;
T = (dev->t_fine * 5 + 128) >> 8;
return T;
}
// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format
// (24 integer bits and 8 fractional bits). Output value of
// “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
static uint32_t _bmp280_compensate_P_int64(const bmp280_context dev,
int32_t adc_P)
{
assert(dev != NULL);
int64_t var1, var2, p;
var1 = ((int64_t)dev->t_fine) - 128000;
var2 = var1 * var1 * (int64_t)dev->dig_P6;
var2 = var2 + ((var1*(int64_t)dev->dig_P5)<<17);
var2 = var2 + (((int64_t)dev->dig_P4)<<35);
var1 = ((var1 * var1 * (int64_t)dev->dig_P3)>>8) + ((var1 * (int64_t)dev->dig_P2)<<12);
var1 = (((((int64_t)1)<<47)+var1))*((int64_t)dev->dig_P1)>>33;
if (var1 == 0)
{
return 0; // avoid exception caused by division by zero
}
p = 1048576-adc_P;
p = (((p<<31)-var2)*3125)/var1;
var1 = (((int64_t)dev->dig_P9) * (p>>13) * (p>>13)) >> 25;
var2 = (((int64_t)dev->dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)dev->dig_P7)<<4);
return (uint32_t)p;
}
// This function comes from the BME280 datasheet, section 4.2.3
// Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format
// (22 integer and 10 fractional bits). Output value of “47445”
// represents 47445/1024 = 46.333 %RH
// BME280 only
static uint32_t _bme280_compensate_H_int32(const bmp280_context dev,
int32_t adc_H)
{
assert(dev != NULL);
int32_t v_x1_u32r;
v_x1_u32r = (dev->t_fine - ((int32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((int32_t)dev->dig_H4) << 20) - (((int32_t)dev->dig_H5) * v_x1_u32r)) +
((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)dev->dig_H6)) >> 10) * (((v_x1_u32r * ((int32_t)dev->dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * ((int32_t)dev->dig_H2) + 8192) >> 14));
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)dev->dig_H1)) >> 4));
v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
return (int32_t)(v_x1_u32r>>12);
}
// read the calibration data
static upm_result_t _read_calibration_data(const bmp280_context dev)
{
assert(dev != NULL);
#if defined(BMP280_USE_TEST_DATA)
printf("%s: WARNING: Test data is being used\n", __FUNCTIOM__);
// This data is taken from the datasheet, section 3.12
dev->dig_T1 = 27504;
dev->dig_T2 = 26435;
dev->dig_T3 = -1000;
dev->dig_P1 = 36477;
dev->dig_P2 = -10685;
dev->dig_P3 = 3024;
dev->dig_P4 = 2855;
dev->dig_P5 = 140;
dev->dig_P6 = -7;
dev->dig_P7 = 15500;
dev->dig_P8 = -14600;
dev->dig_P9 = 6000;
// BME280 does not have any test data....
dev->dig_H1 = 0;
dev->dig_H2 = 0;
dev->dig_H3 = 0;
dev->dig_H4 = 0;
dev->dig_H5 = 0;
dev->dig_H6 = 0;
#else
// bmp280...
uint8_t calibData[BMP280_CALIBRATION_BYTES];
int rv;
if ( (rv = bmp280_read_regs(dev, BMP280_REG_CALIB00, calibData,
BMP280_CALIBRATION_BYTES))
!= BMP280_CALIBRATION_BYTES)
{
printf("%s: bmp280_read_regs(BMP280) failed.",
__FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
dev->dig_T1 = (uint16_t)((calibData[1] << 8) | calibData[0]);
dev->dig_T2 = (int16_t)((calibData[3] << 8) | calibData[2]);
dev->dig_T3 = (int16_t)((calibData[5] << 8) | calibData[4]);
dev->dig_P1 = (uint16_t)((calibData[7] << 8) | calibData[6]);
dev->dig_P2 = (int16_t)((calibData[9] << 8) | calibData[8]);
dev->dig_P3 = (int16_t)((calibData[11] << 8) | calibData[10]);
dev->dig_P4 = (int16_t)((calibData[13] << 8) | calibData[12]);
dev->dig_P5 = (int16_t)((calibData[15] << 8) | calibData[14]);
dev->dig_P6 = (int16_t)((calibData[17] << 8) | calibData[16]);
dev->dig_P7 = (int16_t)((calibData[19] << 8) | calibData[18]);
dev->dig_P8 = (int16_t)((calibData[21] << 8) | calibData[20]);
dev->dig_P9 = (int16_t)((calibData[23] << 8) | calibData[22]);
// bme280... (humidity calibration data)
if (dev->isBME)
{
dev->dig_H1 = bmp280_read_reg(dev, BME280_REG_CALIB_DIG_H1);
uint8_t hCalibData[BME280_CALIBRATION_BYTES];
if ( (rv = bmp280_read_regs(dev, BME280_REG_CALIB_DIG_H2_LSB,
hCalibData,
BME280_CALIBRATION_BYTES))
!= BME280_CALIBRATION_BYTES)
{
printf("%s: bmp280_read_regs(BME280) failed.",
__FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
dev->dig_H2 = (int16_t)((hCalibData[1] << 8) | hCalibData[0]);
dev->dig_H3 = hCalibData[2];
dev->dig_H4 = (int16_t)( (hCalibData[3] << 4) |
(hCalibData[4] & 0x0f) );
dev->dig_H5 = (int16_t)( ((hCalibData[4] & 0xf0) >> 4) |
(hCalibData[5] << 4) );
dev->dig_H6 = (int8_t)(hCalibData[6]);
}
#endif // defined(BMP280_USE_TEST_DATA)
return UPM_SUCCESS;
}
bmp280_context bmp280_init(int bus, int addr, int cs)
{
bmp280_context dev =
(bmp280_context)malloc(sizeof(struct _bmp280_context));
if (!dev)
return NULL;
// zero out context
memset((void *)dev, 0, sizeof(struct _bmp280_context));
// make sure MRAA is initialized
if (mraa_init() != MRAA_SUCCESS)
{
printf("%s: mraa_init() failed.\n", __FUNCTION__);
bmp280_close(dev);
return NULL;
}
if (addr < 0)
dev->isSPI = true;
if (dev->isSPI)
{
if (!(dev->spi = mraa_spi_init(bus)))
{
printf("%s: mraa_spi_init() failed.\n", __FUNCTION__);
bmp280_close(dev);
return NULL;
}
// Only create cs context if we are actually using a valid pin.
// A hardware controlled pin should specify cs as -1.
if (cs >= 0)
{
if (!(dev->gpio = mraa_gpio_init(cs)))
{
printf("%s: mraa_gpio_init() failed.\n", __FUNCTION__);
bmp280_close(dev);
return NULL;
}
mraa_gpio_dir(dev->gpio, MRAA_GPIO_OUT);
}
mraa_spi_mode(dev->spi, MRAA_SPI_MODE0);
if (mraa_spi_frequency(dev->spi, 5000000))
{
printf("%s: mraa_spi_frequency() failed.\n", __FUNCTION__);
bmp280_close(dev);
return NULL;
}
// toggle CS on/off so chip switches into SPI mode. For a hw
// CS pin, the first SPI transaction should accomplish this.
_csOn(dev);
upm_delay_ms(10);
_csOff(dev);
}
else
{
// I2C
if (!(dev->i2c = mraa_i2c_init(bus)))
{
printf("%s: mraa_i2c_init() failed.\n", __FUNCTION__);
bmp280_close(dev);
return NULL;
}
if (mraa_i2c_address(dev->i2c, addr))
{
printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__);
bmp280_close(dev);
return NULL;
}
}
// check the chip id
uint8_t chipID = bmp280_read_reg(dev, BMP280_REG_CHIPID);
switch(chipID)
{
case BMP280_CHIPID: // BMP280
dev->isBME = false;
break;
case BME280_CHIPID: // BME280
dev->isBME = true;
break;
default: // ??
printf("%s: invalid chip id: %02x. Expected either %02x "
"(bmp280) or %02x (bme280)\n",
__FUNCTION__, chipID, BMP280_CHIPID, BME280_CHIPID);
bmp280_close(dev);
return NULL;
}
// set sleep mode for now
bmp280_set_measure_mode(dev, BMP280_MODE_SLEEP);
// read calibration data
if (_read_calibration_data(dev))
{
printf("%s: _read_calibration_data() failed.", __FUNCTION__);
bmp280_close(dev);
return NULL;
}
// set the default mode to the highest resolution mode
bmp280_set_usage_mode(dev, BMP280_USAGE_MODE_INDOOR_NAV);
// set the default sea level pressure in hPA
dev->sea_level_hPA = BMP280_SEA_LEVEL_HPA;
return dev;
}
void bmp280_close(bmp280_context dev)
{
assert(dev != NULL);
if (dev->i2c)
mraa_i2c_stop(dev->i2c);
if (dev->spi)
mraa_spi_stop(dev->spi);
if (dev->gpio)
mraa_gpio_close(dev->gpio);
}
upm_result_t bmp280_update(const bmp280_context dev)
{
assert(dev != NULL);
int32_t temp = 0;
int32_t pres = 0;
uint8_t bmp_data[BMP280_DATA_LEN];
memset(bmp_data, 0, BMP280_DATA_LEN);
// If we are using a forced mode, then we need to manually trigger
// the measurement and wait for it to complete.
if (dev->mode == BMP280_MODE_FORCED)
{
// bmp280 measure mode will return to sleep after completion...
bmp280_set_measure_mode(dev, BMP280_MODE_FORCED);
uint8_t stat;
do
{
upm_delay_ms(10);
stat = bmp280_get_status(dev);
} while (stat & BMP280_STATUS_MEASURING);
}
int rv;
if ((rv = bmp280_read_regs(dev, BMP280_REG_PRESSURE_MSB,
bmp_data, BMP280_DATA_LEN))
!= BMP280_DATA_LEN)
{
printf("%s: bmp280_read_regs() failed.", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// 20 bits unsigned stored in a 32bit signed quantity
#if defined(BMP280_USE_TEST_DATA)
// taken from datasheet, section 3.12
temp = 519888;
pres = 415148;
#else
temp = ( (bmp_data[5] >> 4) | (bmp_data[4] << 4) | (bmp_data[3] << 12) );
pres = ( (bmp_data[2] >> 4) | (bmp_data[1] << 4) | (bmp_data[0] << 12) );
#endif
dev->temperature = (float)_bmp280_compensate_T_int32(dev, temp);
dev->temperature /= 100.0;
dev->pressure = (float)_bmp280_compensate_P_int64(dev, pres);
dev->pressure /= 256.0;
// BME280?
if (dev->isBME)
{
uint8_t bme_data[BME280_DATA_LEN];
memset(bme_data, 0, BME280_DATA_LEN);
if ((rv = bmp280_read_regs(dev, BME280_REG_HUMIDITY_MSB,
bme_data, BME280_DATA_LEN))
!= BME280_DATA_LEN)
{
printf("%s: bmp280_read_regs(BME280) failed.",
__FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// 20 bits unsigned stored in a 32bit signed quantity
int32_t hum = ( (bme_data[0] << 8) | bme_data[1] );
dev->humidity = (float)_bme280_compensate_H_int32(dev, hum);
dev->humidity /= 1024.0;
}
return UPM_SUCCESS;
}
void bmp280_set_sea_level_pressure(const bmp280_context dev,
float seaLevelhPA)
{
assert(dev != NULL);
dev->sea_level_hPA = seaLevelhPA;
}
float bmp280_get_altitude(const bmp280_context dev)
{
assert(dev != NULL);
// adapted from the US NOAA pdf: pressureAltitude.pdf
return 44307.69 * (1.0 - pow((dev->pressure/100.0)
/ dev->sea_level_hPA, 0.190284));
}
uint8_t bmp280_read_reg(const bmp280_context dev, uint8_t reg)
{
assert(dev != NULL);
if (dev->isSPI)
{
reg |= 0x80; // needed for read
uint8_t pkt[2] = {reg, 0};
_csOn(dev);
if (mraa_spi_transfer_buf(dev->spi, pkt, pkt, 2))
{
_csOff(dev);
printf("%s: mraa_spi_transfer_buf() failed.",
__FUNCTION__);
return 0xff;
}
_csOff(dev);
return pkt[1];
}
else
{
return (uint8_t)mraa_i2c_read_byte_data(dev->i2c, reg);
}
}
int bmp280_read_regs(const bmp280_context dev,
uint8_t reg, uint8_t *buffer, int len)
{
assert(dev != NULL);
if (dev->isSPI)
{
reg |= 0x80; // needed for read
uint8_t sbuf[len + 1];
memset((char *)sbuf, 0, len + 1);
sbuf[0] = reg;
// We need to do it this way for edison - ie: use a single
// transfer rather than breaking it up into two like we used
// to, since we have no control over CS. This means a buffer
// copy is now required, but that's the way it goes.
_csOn(dev);
if (mraa_spi_transfer_buf(dev->spi, sbuf, sbuf, len + 1))
{
_csOff(dev);
printf("%s: mraa_spi_transfer_buf() failed.",
__FUNCTION__);
return 0;
}
_csOff(dev);
// now copy it into user buffer
for (int i=0; i<len; i++)
buffer[i] = sbuf[i + 1];
}
else
{
if (mraa_i2c_read_bytes_data(dev->i2c, reg, buffer, len) != len)
return UPM_ERROR_OPERATION_FAILED;
}
return len;
}
upm_result_t bmp280_write_reg(const bmp280_context dev,
uint8_t reg, uint8_t val)
{
assert(dev != NULL);
if (dev->isSPI)
{
reg &= 0x7f; // mask off 0x80 for writing
uint8_t pkt[2] = {reg, val};
_csOn(dev);
if (mraa_spi_transfer_buf(dev->spi, pkt, NULL, 2))
{
_csOff(dev);
printf("%s: mraa_spi_transfer_buf() failed.",
__FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
_csOff(dev);
}
else
{
if (mraa_i2c_write_byte_data(dev->i2c, val, reg))
{
printf("%s: mraa_i2c_write_byte_data() failed.",
__FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
}
return UPM_SUCCESS;
}
uint8_t bmp280_get_chip_id(const bmp280_context dev)
{
assert(dev != NULL);
return bmp280_read_reg(dev, BMP280_REG_CHIPID);
}
void bmp280_reset(const bmp280_context dev)
{
assert(dev != NULL);
bmp280_write_reg(dev, BMP280_REG_RESET, BMP280_RESET_BYTE);
upm_delay(1);
}
float bmp280_get_temperature(const bmp280_context dev)
{
assert(dev != NULL);
return dev->temperature;
}
float bmp280_get_pressure(const bmp280_context dev)
{
assert(dev != NULL);
return dev->pressure;
}
// BME280 only
float bmp280_get_humidity(const bmp280_context dev)
{
assert(dev != NULL);
if (dev->isBME)
return dev->humidity;
else
return 0.0;
}
void bmp280_set_filter(const bmp280_context dev, BMP280_FILTER_T filter)
{
assert(dev != NULL);
uint8_t reg = bmp280_read_reg(dev, BMP280_REG_CONFIG);
reg &= ~(_BMP280_CONFIG_FILTER_MASK << _BMP280_CONFIG_FILTER_SHIFT);
reg |= (filter << _BMP280_CONFIG_FILTER_SHIFT);
bmp280_write_reg(dev, BMP280_REG_CONFIG, reg);
}
void bmp280_set_timer_standby(const bmp280_context dev,
BMP280_T_SB_T tsb)
{
assert(dev != NULL);
uint8_t reg = bmp280_read_reg(dev, BMP280_REG_CONFIG);
reg &= ~(_BMP280_CONFIG_T_SB_MASK << _BMP280_CONFIG_T_SB_SHIFT);
reg |= (tsb << _BMP280_CONFIG_T_SB_SHIFT);
bmp280_write_reg(dev, BMP280_REG_CONFIG, reg);
}
void bmp280_set_measure_mode(const bmp280_context dev,
BMP280_MODES_T mode)
{
assert(dev != NULL);
uint8_t reg = bmp280_read_reg(dev, BMP280_REG_CTRL_MEAS);
reg &= ~(_BMP280_CTRL_MEAS_MODE_MASK << _BMP280_CTRL_MEAS_MODE_SHIFT);
reg |= (mode << _BMP280_CTRL_MEAS_MODE_SHIFT);
bmp280_write_reg(dev, BMP280_REG_CTRL_MEAS, reg);
dev->mode = mode;
}
void bmp280_set_oversample_rate_pressure(const bmp280_context dev,
BMP280_OSRS_P_T rate)
{
assert(dev != NULL);
uint8_t reg = bmp280_read_reg(dev, BMP280_REG_CTRL_MEAS);
reg &= ~(_BMP280_CTRL_MEAS_OSRS_P_MASK << _BMP280_CTRL_MEAS_OSRS_P_SHIFT);
reg |= (rate << _BMP280_CTRL_MEAS_OSRS_P_SHIFT);
bmp280_write_reg(dev, BMP280_REG_CTRL_MEAS, reg);
}
void bmp280_set_oversample_rate_temperature(const bmp280_context dev,
BMP280_OSRS_T_T rate)
{
assert(dev != NULL);
uint8_t reg = bmp280_read_reg(dev, BMP280_REG_CTRL_MEAS);
reg &= ~(_BMP280_CTRL_MEAS_OSRS_T_MASK << _BMP280_CTRL_MEAS_OSRS_T_SHIFT);
reg |= (rate << _BMP280_CTRL_MEAS_OSRS_T_SHIFT);
bmp280_write_reg(dev, BMP280_REG_CTRL_MEAS, reg);
}
// bme280 only
void bmp280_set_oversample_rate_humidity(const bmp280_context dev,
BME280_OSRS_H_T rate)
{
assert(dev != NULL);
if (dev->isBME)
{
uint8_t reg = bmp280_read_reg(dev, BME280_REG_CTRL_HUM);
reg &= ~(_BME280_CTRL_HUM_OSRS_H_MASK << _BME280_CTRL_HUM_OSRS_H_SHIFT);
reg |= (rate << _BME280_CTRL_HUM_OSRS_H_SHIFT);
bmp280_write_reg(dev, BME280_REG_CTRL_HUM, reg);
}
}
uint8_t bmp280_get_status(const bmp280_context dev)
{
assert(dev != NULL);
return bmp280_read_reg(dev, BMP280_REG_STATUS);
}
void bmp280_set_usage_mode(const bmp280_context dev, BMP280_USAGE_MODE_T mode)
{
assert(dev != NULL);
// set up the regs for the given usage mode. These settings come
// from the recomendations in the BMP280 datasheet, section 3.4
// Filter Selection.
dev->temperature = 0;
dev->pressure = 0;
dev->humidity = 0;
// set sleep mode first
bmp280_set_measure_mode(dev, BMP280_MODE_SLEEP);
switch (mode)
{
case BMP280_USAGE_MODE_HANDHELD_LOW_POWER:
bmp280_set_oversample_rate_pressure(dev,
BMP280_OSRS_P_OVERSAMPLING_16);
bmp280_set_oversample_rate_temperature(dev,
BMP280_OSRS_T_OVERSAMPLING_2);
bmp280_set_oversample_rate_humidity(dev,
BME280_OSRS_H_OVERSAMPLING_1);
bmp280_set_filter(dev, BMP280_FILTER_4);
bmp280_set_measure_mode(dev, BMP280_MODE_NORMAL);
break;
case BMP280_USAGE_MODE_HANDHELD_DYNAMIC:
bmp280_set_oversample_rate_pressure(dev,
BMP280_OSRS_P_OVERSAMPLING_4);
bmp280_set_oversample_rate_temperature(dev,
BMP280_OSRS_T_OVERSAMPLING_1);
bmp280_set_oversample_rate_humidity(dev,
BME280_OSRS_H_OVERSAMPLING_1);
bmp280_set_filter(dev, BMP280_FILTER_16);
bmp280_set_measure_mode(dev, BMP280_MODE_NORMAL);
break;
case BMP280_USAGE_MODE_WEATHER_MONITOR:
bmp280_set_oversample_rate_pressure(dev,
BMP280_OSRS_P_OVERSAMPLING_1);
bmp280_set_oversample_rate_temperature(dev,
BMP280_OSRS_T_OVERSAMPLING_1);
bmp280_set_oversample_rate_humidity(dev,
BME280_OSRS_H_OVERSAMPLING_1);
bmp280_set_filter(dev, BMP280_FILTER_OFF);
bmp280_set_measure_mode(dev, BMP280_MODE_FORCED);
break;
case BMP280_USAGE_MODE_FLOOR_CHG_DETECT:
bmp280_set_oversample_rate_pressure(dev,
BMP280_OSRS_P_OVERSAMPLING_4);
bmp280_set_oversample_rate_temperature(dev,
BMP280_OSRS_T_OVERSAMPLING_1);
bmp280_set_oversample_rate_humidity(dev,
BME280_OSRS_H_OVERSAMPLING_1);
bmp280_set_filter(dev, BMP280_FILTER_4);
bmp280_set_measure_mode(dev, BMP280_MODE_NORMAL);
break;
case BMP280_USAGE_MODE_DROP_DETECT:
bmp280_set_oversample_rate_pressure(dev,
BMP280_OSRS_P_OVERSAMPLING_2);
bmp280_set_oversample_rate_temperature(dev,
BMP280_OSRS_T_OVERSAMPLING_1);
bmp280_set_oversample_rate_humidity(dev,
BME280_OSRS_H_OVERSAMPLING_1);
bmp280_set_filter(dev, BMP280_FILTER_OFF);
bmp280_set_measure_mode(dev, BMP280_MODE_NORMAL);
break;
case BMP280_USAGE_MODE_INDOOR_NAV:
bmp280_set_oversample_rate_pressure(dev,
BMP280_OSRS_P_OVERSAMPLING_16);
bmp280_set_oversample_rate_temperature(dev,
BMP280_OSRS_T_OVERSAMPLING_2);
bmp280_set_oversample_rate_humidity(dev,
BME280_OSRS_H_OVERSAMPLING_1);
bmp280_set_filter(dev, BMP280_FILTER_16);
bmp280_set_measure_mode(dev, BMP280_MODE_NORMAL);
break;
default:
printf("%s: invalid usage mode specified, mode unchanged.",
__FUNCTION__);
}
}

View File

@ -1,6 +1,8 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
* Copyright (c) 2016-2017 Intel Corporation.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -26,546 +28,125 @@
#include <iostream>
#include <stdexcept>
#include <string>
#include <math.h>
#include <string.h>
#include "bmp280.hpp"
using namespace upm;
using namespace std;
// Uncomment the following to use test data as specified in the
// datasheet, section 3.12. This really only tests the compensation
// algorithm.
// #define BMP280_USE_TEST_DATA
// conversion from fahrenheit to celsius and back
// conversion from Celsius to Fahrenheit.
static float c2f(float c)
{
return (c * (9.0 / 5.0) + 32.0);
}
BMP280::BMP280(int bus, int addr, int cs, uint8_t theChipID) :
m_i2c(0), m_spi(0), m_gpioCS(0)
BMP280::BMP280(int bus, int addr, int cs) :
m_bmp280(bmp280_init(bus, addr, cs))
{
m_addr = addr;
m_temperature = 0;
m_pressure = 0;
m_isSPI = false;
clearData();
if (addr < 0)
m_isSPI = true;
mraa::Result rv;
if (m_isSPI)
{
m_spi = new mraa::Spi(bus);
// Only create cs context if we are actually using a valid pin.
// A hardware controlled pin should specify cs as -1.
if (cs >= 0)
{
m_gpioCS = new mraa::Gpio(cs);
m_gpioCS->dir(mraa::DIR_OUT);
}
m_spi->mode(mraa::SPI_MODE0);
m_spi->frequency(5000000);
// toggle it on/off so chip switches into SPI mode. For a hw CS
// pin, the first SPI transaction should accomplish this.
csOn();
usleep(10000);
csOff();
}
else
{
// I2C
m_i2c = new mraa::I2c(bus);
if ((rv = m_i2c->address(m_addr)) != mraa::SUCCESS)
{
throw std::runtime_error(string(__FUNCTION__) +
": I2c.address() failed");
}
}
// check the chip id
uint8_t chipID = readReg(REG_CHIPID);
if (chipID != theChipID)
{
throw std::runtime_error(string(__FUNCTION__)
+ ": invalid chip ID. Expected "
+ std::to_string(int(theChipID))
+ ", got "
+ std::to_string(int(chipID)));
}
// set sleep mode for now
setMeasureMode(MODE_SLEEP);
// read calibration data
readCalibrationData();
// set the default mode to the highest resolution mode
setUsageMode(USAGE_MODE_INDOOR_NAV);
if (!m_bmp280)
throw std::runtime_error(string(__FUNCTION__)
+ ": bmp280_init() failed");
}
BMP280::~BMP280()
{
if (m_i2c)
delete m_i2c;
if (m_spi)
delete m_spi;
if (m_gpioCS)
delete m_gpioCS;
bmp280_close(m_bmp280);
}
void BMP280::update()
{
int32_t temp = 0;
int32_t pres = 0;
const int dataLen = 6;
uint8_t data[dataLen];
memset(data, 0, dataLen);
// If we are using a forced mode, then we need to manually trigger
// the measurement, and wait for it to complete.
if (m_mode == MODE_FORCED)
{
// bmp280 measure mode will return to sleep after completion...
setMeasureMode(MODE_FORCED);
uint8_t stat;
do
{
usleep(10000); // 10ms
stat = readReg(REG_STATUS);
} while (stat & STATUS_MEASURING);
}
int rv;
if ((rv = readRegs(REG_PRESSURE_MSB, data, dataLen)) != dataLen)
{
throw std::runtime_error(std::string(__FUNCTION__)
+ ": readRegs() failed, returned "
+ std::to_string(rv));
}
// 20 bits unsigned stored in a 32bit signed quanty
#if defined(BMP280_USE_TEST_DATA)
// taken from datasheet, section 3.12
temp = 519888;
pres = 415148;
#else
temp = ( (data[5] >> 4) | (data[4] << 4) | (data[3] << 12) );
pres = ( (data[2] >> 4) | (data[1] << 4) | (data[0] << 12) );
#endif
m_temperature = float(bmp280_compensate_T_int32(temp));
m_temperature /= 100.0;
m_pressure = float(bmp280_compensate_P_int64(pres));
m_pressure /= 256.0;
if (bmp280_update(m_bmp280))
throw std::runtime_error(string(__FUNCTION__)
+ ": bmp280_update() failed");
}
float BMP280::getAltitude(float sealLevelhPA)
void BMP280::setSeaLevelPreassure(float seaLevelhPA)
{
// adapted from the NOAA pdf: pressureAltitude.pdf
return 44307.69 * (1.0 - pow((m_pressure/100.0) / sealLevelhPA, 0.190284));
bmp280_set_sea_level_pressure(m_bmp280, seaLevelhPA);
}
float BMP280::getAltitude()
{
return bmp280_get_altitude(m_bmp280);
}
uint8_t BMP280::readReg(uint8_t reg)
{
if (m_isSPI)
{
reg |= 0x80; // needed for read
uint8_t pkt[2] = {reg, 0};
csOn();
if (m_spi->transfer(pkt, pkt, 2))
{
csOff();
throw std::runtime_error(string(__FUNCTION__)
+ ": Spi.transfer() failed");
}
csOff();
#if 0
cerr << "readReg: " << std::hex << "p0: " << (int)pkt[0] << " p1: "
<< (int)pkt[1] << endl;
#endif // 0
return pkt[1];
}
else
return m_i2c->readReg(reg);
return bmp280_read_reg(m_bmp280, reg);
}
int BMP280::readRegs(uint8_t reg, uint8_t *buffer, int len)
{
if (m_isSPI)
{
reg |= 0x80; // needed for read
uint8_t sbuf[len + 1];
memset((char *)sbuf, 0, len + 1);
sbuf[0] = reg;
// We need to do it this way for edison - ie: use a single
// transfer rather than breaking it up into two like we used to.
// This means a buffer copy is now required, but that's the way
// it goes.
csOn();
if (m_spi->transfer(sbuf, sbuf, len + 1))
{
csOff();
throw std::runtime_error(string(__FUNCTION__)
+ ": Spi.transfer(buf) failed");
}
csOff();
// now copy it into user buffer
for (int i=0; i<len; i++)
buffer[i] = sbuf[i + 1];
// so... did this work on edison????
#if 0
cerr << "readRegs(): " << std::hex;
for (int i=0; i<len; i++)
cerr << (int)buffer[i] << " ";
cerr << endl;
#endif // 0
return len;
}
else
return m_i2c->readBytesReg(reg, buffer, len);
return bmp280_read_regs(m_bmp280, reg, buffer, len);
}
void BMP280::writeReg(uint8_t reg, uint8_t val)
{
if (m_isSPI)
{
reg &= 0x7f; // mask off 0x80 for writing
uint8_t pkt[2] = {reg, val};
csOn();
if (m_spi->transfer(pkt, NULL, 2))
{
csOff();
throw std::runtime_error(string(__FUNCTION__)
+ ": Spi.transfer() failed");
}
csOff();
}
else
{
mraa::Result rv;
if ((rv = m_i2c->writeReg(reg, val)) != mraa::SUCCESS)
{
throw std::runtime_error(std::string(__FUNCTION__)
+ ": I2c.writeReg() failed");
}
}
}
void BMP280::clearData()
{
m_t_fine = 0;
m_dig_T1 = 0;
m_dig_T2 = 0;
m_dig_T3 = 0;
m_dig_P1 = 0;
m_dig_P2 = 0;
m_dig_P3 = 0;
m_dig_P4 = 0;
m_dig_P5 = 0;
m_dig_P6 = 0;
m_dig_P7 = 0;
m_dig_P8 = 0;
m_dig_P9 = 0;
if (bmp280_write_reg(m_bmp280, reg, val))
throw std::runtime_error(string(__FUNCTION__)
+ ": bmp280_write_reg() failed");
}
uint8_t BMP280::getChipID()
{
return readReg(REG_CHIPID);
return bmp280_get_chip_id(m_bmp280);
}
void BMP280::reset()
{
writeReg(REG_RESET, BMP280_RESET_BYTE);
sleep(1);
bmp280_reset(m_bmp280);
}
void BMP280::readCalibrationData()
{
#if defined(BMP280_USE_TEST_DATA)
cerr << "WARNING: Test data is being used" << endl;
// This data is taken from the datasheet, section 3.12
m_dig_T1 = 27504;
m_dig_T2 = 26435;
m_dig_T3 = -1000;
m_dig_P1 = 36477;
m_dig_P2 = -10685;
m_dig_P3 = 3024;
m_dig_P4 = 2855;
m_dig_P5 = 140;
m_dig_P6 = -7;
m_dig_P7 = 15500;
m_dig_P8 = -14600;
m_dig_P9 = 6000;
#else
uint8_t calibData[CALIBRATION_BYTES];
readRegs(REG_CALIB00, calibData, CALIBRATION_BYTES);
m_dig_T1 = uint16_t((calibData[1] << 8) | calibData[0]);
m_dig_T2 = int16_t((calibData[3] << 8) | calibData[2]);
m_dig_T3 = int16_t((calibData[5] << 8) | calibData[4]);
# if 0
cerr << std::dec << "T1: " << (int)m_dig_T1
<< " T2: " << (int)m_dig_T2
<< " T3: " << (int)m_dig_T3
<< endl;
# endif // 0
m_dig_P1 = uint16_t((calibData[7] << 8) | calibData[6]);
m_dig_P2 = int16_t((calibData[9] << 8) | calibData[8]);
m_dig_P3 = int16_t((calibData[11] << 8) | calibData[10]);
m_dig_P4 = int16_t((calibData[13] << 8) | calibData[12]);
m_dig_P5 = int16_t((calibData[15] << 8) | calibData[14]);
m_dig_P6 = int16_t((calibData[17] << 8) | calibData[16]);
m_dig_P7 = int16_t((calibData[19] << 8) | calibData[18]);
m_dig_P8 = int16_t((calibData[21] << 8) | calibData[20]);
m_dig_P9 = int16_t((calibData[23] << 8) | calibData[22]);
# if 0
cerr << std::dec << "P1: " << (int)m_dig_P1
<< " P2: " << (int)m_dig_P2
<< " P3: " << (int)m_dig_P3
<< " P4: " << (int)m_dig_P4
<< " P5: " << (int)m_dig_P5
<< endl;
cerr << std::dec << "P6: " << (int)m_dig_P6
<< " P7: " << (int)m_dig_P7
<< " P8: " << (int)m_dig_P8
<< " P9: " << (int)m_dig_P9
<< endl;
# endif // 0
#endif
}
float BMP280::getTemperature(bool fahrenheit)
{
if (fahrenheit)
return c2f(m_temperature);
else
return m_temperature;
float temperature = bmp280_get_temperature(m_bmp280);
if (fahrenheit)
return c2f(temperature);
else
return temperature;
}
float BMP280::getPressure()
{
return m_pressure;
return bmp280_get_pressure(m_bmp280);
}
void BMP280::setFilter(FILTER_T filter)
void BMP280::setFilter(BMP280_FILTER_T filter)
{
uint8_t reg = readReg(REG_CONFIG);
reg &= ~(_CONFIG_FILTER_MASK << _CONFIG_FILTER_SHIFT);
reg |= (filter << _CONFIG_FILTER_SHIFT);
writeReg(REG_CONFIG, reg);
bmp280_set_filter(m_bmp280, filter);
}
void BMP280::setTimerStandby(T_SB_T tsb)
void BMP280::setTimerStandby(BMP280_T_SB_T tsb)
{
uint8_t reg = readReg(REG_CONFIG);
reg &= ~(_CONFIG_T_SB_MASK << _CONFIG_T_SB_SHIFT);
reg |= (tsb << _CONFIG_T_SB_SHIFT);
writeReg(REG_CONFIG, reg);
bmp280_set_timer_standby(m_bmp280, tsb);
}
void BMP280::setMeasureMode(MODES_T mode)
void BMP280::setMeasureMode(BMP280_MODES_T mode)
{
uint8_t reg = readReg(REG_CTRL_MEAS);
reg &= ~(_CTRL_MEAS_MODE_MASK << _CTRL_MEAS_MODE_SHIFT);
reg |= (mode << _CTRL_MEAS_MODE_SHIFT);
writeReg(REG_CTRL_MEAS, reg);
m_mode = mode;
bmp280_set_measure_mode(m_bmp280, mode);
}
void BMP280::setOversampleRatePressure(OSRS_P_T rate)
void BMP280::setOversampleRatePressure(BMP280_OSRS_P_T rate)
{
uint8_t reg = readReg(REG_CTRL_MEAS);
reg &= ~(_CTRL_MEAS_OSRS_P_MASK << _CTRL_MEAS_OSRS_P_SHIFT);
reg |= (rate << _CTRL_MEAS_OSRS_P_SHIFT);
writeReg(REG_CTRL_MEAS, reg);
bmp280_set_oversample_rate_pressure(m_bmp280, rate);
}
void BMP280::setOversampleRateTemperature(OSRS_T_T rate)
void BMP280::setOversampleRateTemperature(BMP280_OSRS_T_T rate)
{
uint8_t reg = readReg(REG_CTRL_MEAS);
reg &= ~(_CTRL_MEAS_OSRS_T_MASK << _CTRL_MEAS_OSRS_T_SHIFT);
reg |= (rate << _CTRL_MEAS_OSRS_T_SHIFT);
writeReg(REG_CTRL_MEAS, reg);
bmp280_set_oversample_rate_temperature(m_bmp280, rate);
}
uint8_t BMP280::getStatus()
{
return readReg(REG_STATUS);
return bmp280_get_status(m_bmp280);
}
void BMP280::setUsageMode(USAGE_MODE_T mode)
void BMP280::setUsageMode(BMP280_USAGE_MODE_T mode)
{
// set up the regs for the given usage mode. These settings come
// from the recomendations in the BMP280 datasheet, section 3.4
// Filter Selection.
m_temperature = 0;
m_pressure = 0;
// set sleep mode first
setMeasureMode(MODE_SLEEP);
switch (mode)
{
case USAGE_MODE_HANDHELD_LOW_POWER:
setOversampleRatePressure(OSRS_P_OVERSAMPLING_16);
setOversampleRateTemperature(OSRS_T_OVERSAMPLING_2);
setFilter(FILTER_4);
setMeasureMode(MODE_NORMAL);
break;
case USAGE_MODE_HANDHELD_DYNAMIC:
setOversampleRatePressure(OSRS_P_OVERSAMPLING_4);
setOversampleRateTemperature(OSRS_T_OVERSAMPLING_1);
setFilter(FILTER_16);
setMeasureMode(MODE_NORMAL);
break;
case USAGE_MODE_WEATHER_MONITOR:
setOversampleRatePressure(OSRS_P_OVERSAMPLING_1);
setOversampleRateTemperature(OSRS_T_OVERSAMPLING_1);
setFilter(FILTER_OFF);
setMeasureMode(MODE_FORCED);
break;
case USAGE_MODE_FLOOR_CHG_DETECT:
setOversampleRatePressure(OSRS_P_OVERSAMPLING_4);
setOversampleRateTemperature(OSRS_T_OVERSAMPLING_1);
setFilter(FILTER_4);
setMeasureMode(MODE_NORMAL);
break;
case USAGE_MODE_DROP_DETECT:
setOversampleRatePressure(OSRS_P_OVERSAMPLING_2);
setOversampleRateTemperature(OSRS_T_OVERSAMPLING_1);
setFilter(FILTER_OFF);
setMeasureMode(MODE_NORMAL);
break;
case USAGE_MODE_INDOOR_NAV:
setOversampleRatePressure(OSRS_P_OVERSAMPLING_16);
setOversampleRateTemperature(OSRS_T_OVERSAMPLING_2);
setFilter(FILTER_16);
setMeasureMode(MODE_NORMAL);
break;
default:
throw std::logic_error(string(__FUNCTION__)
+ ": invalid mode specified");
}
bmp280_set_usage_mode(m_bmp280, mode);
}
void BMP280::csOn()
{
if (m_gpioCS)
m_gpioCS->write(0);
}
void BMP280::csOff()
{
if (m_gpioCS)
m_gpioCS->write(1);
}
// These functions come from the BMP280 datasheet, section 3.11.3
// Returns temperature in DegC, resolution is 0.01 DegC. Output value
// of "5123" equals 51.23 DegC. t_fine carries fine temperature as
// global value
int32_t BMP280::bmp280_compensate_T_int32(int32_t adc_T)
{
int32_t var1, var2, T;
var1 = ((((adc_T>>3) - ((int32_t)m_dig_T1<<1))) * ((int32_t)m_dig_T2)) >> 11;
var2 = (((((adc_T>>4) - ((int32_t)m_dig_T1)) * ((adc_T>>4) - ((int32_t)m_dig_T1))) >> 12) *
((int32_t)m_dig_T3)) >> 14;
m_t_fine = var1 + var2;
T = (m_t_fine * 5 + 128) >> 8;
return T;
}
// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format
// (24 integer bits and 8 fractional bits). Output value of
// “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
uint32_t BMP280::bmp280_compensate_P_int64(int32_t adc_P)
{
int64_t var1, var2, p;
var1 = ((int64_t)m_t_fine) - 128000;
var2 = var1 * var1 * (int64_t)m_dig_P6;
var2 = var2 + ((var1*(int64_t)m_dig_P5)<<17);
var2 = var2 + (((int64_t)m_dig_P4)<<35);
var1 = ((var1 * var1 * (int64_t)m_dig_P3)>>8) + ((var1 * (int64_t)m_dig_P2)<<12);
var1 = (((((int64_t)1)<<47)+var1))*((int64_t)m_dig_P1)>>33;
if (var1 == 0)
{
return 0; // avoid exception caused by division by zero
}
p = 1048576-adc_P;
p = (((p<<31)-var2)*3125)/var1;
var1 = (((int64_t)m_dig_P9) * (p>>13) * (p>>13)) >> 25;
var2 = (((int64_t)m_dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)m_dig_P7)<<4);
return (uint32_t)p;
}

346
src/bmp280/bmp280.h Normal file
View File

@ -0,0 +1,346 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016-2017 Intel Corporation.
*
* The MIT License
*
* 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.
*/
#pragma once
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <upm.h>
#include <mraa/i2c.h>
#include <mraa/spi.h>
#include <mraa/gpio.h>
#include "bmp280_regs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file bmp280.h
* @library bmp280
* @brief C API for the bmp280 and bme280 driver
*
* @include bmp280.c
*/
/**
* Device context
*/
typedef struct _bmp280_context {
mraa_i2c_context i2c;
mraa_gpio_context gpio;
mraa_spi_context spi;
// are we doing SPI?
bool isSPI;
// are we using a bme280?
bool isBME;
// always stored in C
float temperature;
// pressure in Pa
float pressure;
// humidity (relative)
float humidity;
// sea level pressure in hectoPascals (hPa)
float sea_level_hPA;
// shared calibration data - set in temp conversion, used in
// pressure conversion.
int32_t t_fine;
// current operating mode. BMP280_MODE_FORCED requires
// special attention in update()
BMP280_MODES_T mode;
// calibration data temperature
uint16_t dig_T1;
int16_t dig_T2;
int16_t dig_T3;
// calibration data pressure
uint16_t dig_P1;
int16_t dig_P2;
int16_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int16_t dig_P6;
int16_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;
// calibration data humidity (BME280 only)
uint8_t dig_H1;
int16_t dig_H2;
uint8_t dig_H3;
int16_t dig_H4;
int16_t dig_H5;
int8_t dig_H6;
} *bmp280_context;
/**
* BMP280 initialization.
*
* This driver supports both the BMP280 and the BME280. The
* BME280 adds a humidity sensor. The device type is detected
* automatically by querying the chip id register.
*
* Both I2C and SPI accesses are supported. For SPI, set the addr
* to -1, and specify a positive integer representing the Chip
* Select (CS) pin for the cs argument. If you are using a
* hardware CS pin you cannot control (Intel Edison), then you can
* connect the proper pin to the hardware CS pin on your MCU and
* supply -1 for cs. The default operating mode is I2C.
*
* @param bus I2C or SPI bus to use.
* @param address The I2C address for this device. Use -1 for SPI.
* @param cs The gpio pin to use for the SPI Chip Select. Use -1
* for I2C, or for SPI with a hardware controlled pin.
* @return Device context, or NULL on error.
*/
bmp280_context bmp280_init(int bus, int addr, int cs);
/**
* BMP280 close function.
*
* @param dev Device context.
*/
void bmp280_close(bmp280_context dev);
/**
* Update the internal stored values from sensor data.
*
* @param dev Device context.
* @return UPM result.
*/
upm_result_t bmp280_update(const bmp280_context dev);
/**
* Return the chip ID.
*
* @param dev Device context.
* @return The chip ID (BMP280_CHIPID).
*/
uint8_t bmp280_get_chip_id(const bmp280_context dev);
/**
* Reset the sensor, as if by a power-on-reset.
*
* @param dev Device context.
*/
void bmp280_reset(const bmp280_context dev);
/**
* Return the current measured temperature. Note, this is not
* ambient temperature - this is the temperature used to fine tune
* the pressure measurement. bmp280_update() must have been called prior
* to calling this method.
*
* @param dev Device context.
* @return The temperature in degrees Celsius.
*/
float bmp280_get_temperature(const bmp280_context dev);
/**
* Return the current measured relative humidity (bme280 only).
* bmp280_update() must have been called prior to calling this
* method. For a bmp280, the returned value will always be 0.
*
* @param dev Device context.
* @return The relative humidity in percent.
*/
float bmp280_get_humidity(const bmp280_context dev);
/**
* Return the current measured pressure in Pascals (Pa).
* bmp280_update() must have been called prior to calling this
* method.
*
* @param dev Device context.
* @return The pressure in Pascals (Pa).
*/
float bmp280_get_pressure(const bmp280_context dev);
/**
* Set the default Sea Level Pressure in hectoPascals (hPA). A
* default of 1013.25 (101325 Pa) is set during bmp280_init().
* This value is used for altitude computation.
*
* @param dev Device context.
* @param seaLevelhPA The pressure at sea level in hectoPascals
* (hPa).
*/
void bmp280_set_sea_level_pressure(const bmp280_context dev,
float seaLevelhPA);
/**
* Return the current computed altitude in meters.
* bmp280_update() must have been called prior to calling this
* method.
*
* Computing this value requires knowing the pressure at sea
* level. bmp280_init() sets this by default to 1013.25 hPA. Use
* bmp280_set_sea_level_pressure() to change this value.
*
* @param dev Device context.
* @return The computed altitude in meters.
*/
float bmp280_get_altitude(const bmp280_context dev);
/**
* Set a general usage mode. This function can be used to
* configure the filters and oversampling for a particular use
* case. These setting are documented in the BMP280 datasheet.
* The default mode set in the bmp280_init() function is
* BMP280_USAGE_MODE_INDOOR_NAV, the highest resolution mode.
*
* @param dev Device context.
* @param mode One of the BMP280_USAGE_MODE_T values.
*/
void bmp280_set_usage_mode(const bmp280_context dev,
BMP280_USAGE_MODE_T mode);
/**
* Set the temperature sensor oversampling parameter. See the
* data sheet for details. This value can be automatically set to
* a suitable value by using one of the predefined modes for
* bmp280_set_usage_mode().
*
* @param dev Device context.
* @param mode One of the BMP280_OSRS_T_T values.
*/
void bmp280_set_oversample_rate_temperature(const bmp280_context dev,
BMP280_OSRS_T_T rate);
/**
* Set the pressure sensor oversampling parameter. See the
* data sheet for details. This value can be automatically set to
* a suitable value by using one of the predefined modes for
* bmp280_set_usage_mode().
*
* @param dev Device context.
* @param mode One of the BMP280_OSRS_P_T values.
*/
void bmp280_set_oversample_rate_pressure(const bmp280_context dev,
BMP280_OSRS_P_T rate);
/**
* Set the humidity sensor oversampling parameter (BME280 only).
* See the data sheet for details. This value can be
* automatically set to a suitable value by using one of the
* predefined modes for bmp280_set_usage_mode().
*
* @param dev Device context.
* @param mode One of the BME280_OSRS_H_T values.
*/
void bmp280_set_oversample_rate_humidity(const bmp280_context dev,
BME280_OSRS_H_T rate);
/**
* Set the timer standby value. When in NORMAL operating mode,
* this timer governs how long the chip will wait before
* performing a measurement. See the data sheet for details.
*
* @param dev Device context.
* @param mode One of the BMP280_T_SB_T values.
*/
void bmp280_set_timer_standby(const bmp280_context dev,
BMP280_T_SB_T tsb);
/**
* Set the IIR filtering parameter. See the data sheet for
* details. This value can be automatically set to a suitable
* value by using one of the predefined modes for
* bmp280_set_usage_mode().
*
* @param dev Device context.
* @param mode One of the BMP280_FILTER_T values.
*/
void bmp280_set_filter(const bmp280_context dev, BMP280_FILTER_T filter);
/**
* Set the default measuring mode. Basic values are forced,
* sleep, and normal. See the data sheet for details. This value
* can be automatically set to a suitable value by using one of
* the predefined modes for bmp280_set_usage_mode().
*
* @param dev Device context.
* @param mode One of the BMP280_MODES_T values.
*/
void bmp280_set_measure_mode(const bmp280_context dev,
BMP280_MODES_T mode);
/**
* Return the value of the BMP280_REG_STATUS register.
*
* @param dev Device context.
* @return Contents of the status register.
*/
uint8_t bmp280_get_status(const bmp280_context dev);
/**
* Read a register.
*
* @param dev Device context.
* @param reg The register to read
* @return The value of the register
*/
uint8_t bmp280_read_reg(const bmp280_context dev, uint8_t reg);
/**
* Read contiguous registers into a buffer. This is a low level
* function, and should not be used unless you know what you are
* doing.
*
* @param dev Device context.
* @param buffer The buffer to store the results
* @param len The number of registers to read
* @return The number of bytes read, or -1 on error
*/
int bmp280_read_regs(const bmp280_context dev,
uint8_t reg, uint8_t *buffer, int len);
/**
* Write to a register. This is a low level function, and should
* not be used unless you know what you are doing.
*
* @param dev Device context.
* @param reg The register to write to
* @param val The value to write
* @return UPM result.
*/
upm_result_t bmp280_write_reg(const bmp280_context dev,
uint8_t reg, uint8_t val);
#ifdef __cplusplus
}
#endif

View File

@ -1,6 +1,8 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
* Copyright (c) 2016-2017 Intel Corporation.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -24,467 +26,249 @@
#pragma once
#include <string>
#include <mraa/i2c.hpp>
#include <mraa/spi.hpp>
#include <mraa/gpio.hpp>
#include "bmp280.h"
#include "interfaces/iPressureSensor.hpp"
#include "interfaces/iTemperatureSensor.hpp"
#define BMP280_DEFAULT_I2C_BUS 0
#define BMP280_DEFAULT_SPI_BUS 0
#define BMP280_DEFAULT_ADDR 0x77
#define BMP280_DEFAULT_CHIPID 0x58
namespace upm {
/**
* @brief BMP280 Digital Pressure Sensor
* @defgroup bmp280 libupm-bmp280
* @ingroup i2c spi gpio pressure
*/
/**
* @library bmp280
* @sensor bmp280
* @comname Digital Pressure Sensor
* @type pressure
* @man adafruit
* @con i2c spi gpio
* @web https://www.adafruit.com/products/2651
*
* @brief API for the BMP280 Digital Pressure Sensor
*
* The BMP280 is an absolute barometric pressure sensor especially
* designed for mobile applications. The sensor module is housed in
* an extremely compact 8-pin metal-lid LGA package with a footprint
* of only 2.0 * 2.5 mm2 and 0.95 mm package height. Its small
* dimensions and its low power consumption of 2.7 uA @1Hz allow the
* implementation in battery driven devices such as mobile phones,
* GPS modules or watches.
*
* As the successor to the widely adopted BMP180, the BMP280
* delivers high performance in all applications that require
* precise pressure measurement. The BMP280 operates at lower noise,
* supports new filter modes and an SPI interface within a footprint
* 63% smaller than the BMP180.
*
* @snippet bmp280.cxx Interesting
*/
class BMP280 : public ITemperatureSensor, public IPressureSensor {
public:
// special reset byte
const uint8_t BMP280_RESET_BYTE = 0xb6;
// number of bytes of stored calibration data
const int CALIBRATION_BYTES = 26;
/**
* BMP280 registers
* @brief BMP280 Digital Pressure Sensor
* @defgroup bmp280 libupm-bmp280
* @ingroup i2c spi gpio pressure
*/
typedef enum : uint8_t {
// Do not write into reserved bits.
// read-only factory calibration data
REG_CALIB00 = 0x88,
REG_CALIB01 = 0x89,
REG_CALIB02 = 0x8a,
REG_CALIB03 = 0x8b,
REG_CALIB04 = 0x8c,
REG_CALIB05 = 0x8d,
REG_CALIB06 = 0x8e,
REG_CALIB07 = 0x8f,
REG_CALIB08 = 0x90,
REG_CALIB09 = 0x91,
REG_CALIB10 = 0x92,
REG_CALIB11 = 0x93,
REG_CALIB12 = 0x94,
REG_CALIB13 = 0x95,
REG_CALIB14 = 0x96,
REG_CALIB15 = 0x97,
REG_CALIB16 = 0x98,
REG_CALIB17 = 0x99,
REG_CALIB18 = 0x9a,
REG_CALIB19 = 0x9b,
REG_CALIB20 = 0x9c,
REG_CALIB21 = 0x9d,
REG_CALIB22 = 0x9e,
REG_CALIB23 = 0x9f,
REG_CALIB24 = 0xa0,
REG_CALIB25 = 0xa1,
REG_CHIPID = 0xd0,
REG_RESET = 0xe0,
REG_STATUS = 0xf3,
REG_CTRL_MEAS = 0xf4,
REG_CONFIG = 0xf5,
REG_PRESSURE_MSB = 0xf7,
REG_PRESSURE_LSB = 0xf8,
REG_PRESSURE_XLSB = 0xf9,
REG_TEMPERATURE_MSB = 0xfa,
REG_TEMPERATURE_LSB = 0xfb,
REG_TEMPERATURE_XLSB = 0xfc
} BMP280_REGS_T;
/**
* REG_CONFIG bits
*/
typedef enum {
CONFIG_SPI3W_EN = 0x01,
// 0x02 reserved
CONFIG_FILTER0 = 0x04,
CONFIG_FILTER1 = 0x08,
CONFIG_FILTER2 = 0x10,
_CONFIG_FILTER_MASK = 7,
_CONFIG_FILTER_SHIFT = 2,
CONFIG_T_SB0 = 0x20,
CONFIG_T_SB1 = 0x40,
CONFIG_T_SB2 = 0x80,
_CONFIG_T_SB_MASK = 7,
_CONFIG_T_SB_SHIFT = 5
} CONFIG_BITS_T;
/**
* FILTER values (samples to reach >= 75% of step response)
*/
typedef enum {
FILTER_OFF = 0, // 1 samples
FILTER_2 = 1, // 2
FILTER_4 = 2, // 5
FILTER_8 = 3, // 11
FILTER_16 = 4 // 22
} FILTER_T;
/**
* T_SB values (timer standby)
*/
typedef enum {
T_SB_0_5 = 0, // 0.5ms
T_SB_62_5 = 1, // 62.5ms
T_SB_125 = 2, // 125ms
T_SB_250 = 3,
T_SB_500 = 4,
T_SB_1000 = 5,
T_SB_2000 = 6, // bme280 - 10ms
T_SB_4000 = 7 // bme280 - 20ms
} T_SB_T;
/**
* REG_CTRL_MEAS bits
*/
typedef enum {
CTRL_MEAS_MODE0 = 0x01,
CTRL_MEAS_MODE1 = 0x02,
_CTRL_MEAS_MODE_MASK = 3,
_CTRL_MEAS_MODE_SHIFT = 0,
CTRL_MEAS_OSRS_P0 = 0x04,
CTRL_MEAS_OSRS_P1 = 0x08,
CTRL_MEAS_OSRS_P2 = 0x10,
_CTRL_MEAS_OSRS_P_MASK = 7,
_CTRL_MEAS_OSRS_P_SHIFT = 2,
CTRL_MEAS_OSRS_T0 = 0x04,
CTRL_MEAS_OSRS_T1 = 0x08,
CTRL_MEAS_OSRS_T2 = 0x10,
_CTRL_MEAS_OSRS_T_MASK = 7,
_CTRL_MEAS_OSRS_T_SHIFT = 5
} CTRL_MEAS_T;
/**
* CTRL_MEAS_MODE values
*/
typedef enum {
MODE_SLEEP = 0,
MODE_FORCED = 1,
// 2 is also FORCED mode
MODE_NORMAL = 3
} MODES_T;
/**
* CTRL_MEAS_OSRS_P values
*/
typedef enum {
OSRS_P_SKIPPED = 0,
OSRS_P_OVERSAMPLING_1 = 1, // x1
OSRS_P_OVERSAMPLING_2 = 2, // x2
OSRS_P_OVERSAMPLING_4 = 3,
OSRS_P_OVERSAMPLING_8 = 4,
OSRS_P_OVERSAMPLING_16 = 5
} OSRS_P_T;
/**
* CTRL_MEAS_OSRS_T values
*/
typedef enum {
OSRS_T_SKIPPED = 0,
OSRS_T_OVERSAMPLING_1 = 1, // x1
OSRS_T_OVERSAMPLING_2 = 2, // x2
OSRS_T_OVERSAMPLING_4 = 3,
OSRS_T_OVERSAMPLING_8 = 4,
OSRS_T_OVERSAMPLING_16 = 5
} OSRS_T_T;
/**
* REG_STATUS bits
*/
typedef enum {
STATUS_IM_UPDATE = 0x01,
// 0x02-0x04 reserved
STATUS_MEASURING = 0x08
// 0x10-0x80 reserved
} STATUS_T;
/**
* USAGE_MODE values. This is a fake specification to configure
* the various knobs based on their typical use modes, as
* recommended by Bosch.
*/
typedef enum {
USAGE_MODE_HANDHELD_LOW_POWER = 0,
USAGE_MODE_HANDHELD_DYNAMIC = 1,
USAGE_MODE_WEATHER_MONITOR = 2, // lowest power consumption
USAGE_MODE_FLOOR_CHG_DETECT = 3,
USAGE_MODE_DROP_DETECT = 4,
USAGE_MODE_INDOOR_NAV = 5 // highest resolution
} USAGE_MODE_T;
/**
* BMP280 constructor.
* @library bmp280
* @sensor bmp280
* @comname Digital Pressure Sensor
* @type pressure
* @man adafruit
* @con i2c spi gpio
* @web https://www.adafruit.com/products/2651
*
* This device can support both I2C and SPI. For SPI, set the addr
* to -1, and specify a positive integer representing the Chip
* Select (CS) pin for the cs argument. If you are using a
* hardware CS pin, then you can connect the proper pin to the
* hardware CS pin on your MCU and supply -1 for cs. The default
* operating mode is I2C.
* @brief API for the BMP280 Digital Pressure Sensor
*
* @param bus I2C or SPI bus to use.
* @param address The address for this device. -1 for SPI.
* @param cs The gpio pin to use for the SPI Chip Select. -1 for
* I2C or for SPI with a hardware controlled pin.
* @param theChipID The chip ID to use for validation
*/
BMP280(int bus=BMP280_DEFAULT_I2C_BUS, int addr=BMP280_DEFAULT_ADDR,
int cs=-1, uint8_t theChipID=BMP280_DEFAULT_CHIPID);
/**
* BMP280 Destructor.
*/
virtual ~BMP280();
/**
* Update the internal stored values from sensor data.
*/
virtual void update();
/**
* Return the chip ID.
* The BMP280 is an absolute barometric pressure sensor especially
* designed for mobile applications. The sensor module is housed in
* an extremely compact 8-pin metal-lid LGA package with a footprint
* of only 2.0 * 2.5 mm2 and 0.95 mm package height. Its small
* dimensions and its low power consumption of 2.7 uA @1Hz allow the
* implementation in battery driven devices such as mobile phones,
* GPS modules or watches.
*
* @return The chip ID (BMP280_CHIPID).
*/
uint8_t getChipID();
/**
* Reset the sensor, as if by a power-on-reset.
*/
void reset();
/**
* Return the current measured temperature. Note, this is not
* ambient temperature - this is the temperature used to fine tune
* the pressure measurement. update() must have been called prior
* to calling this method.
* As the successor to the widely adopted BMP180, the BMP280
* delivers high performance in all applications that require
* precise pressure measurement. The BMP280 operates at lower noise,
* supports new filter modes and an SPI interface within a footprint
* 63% smaller than the BMP180.
*
* @param fahrenheit true to return data in Fahrenheit, false for
* Celicus. Celsius is the default.
* @return The temperature in degrees Celsius or Fahrenheit.
* @snippet bmp280.cxx Interesting
*/
float getTemperature(bool fahrenheit=false);
/**
* Return the current measured pressure in Pascals (Pa). update()
* must have been called prior to calling this method.
*
* @return The pressure in Pascals (Pa).
*/
float getPressure();
class BMP280 : public ITemperatureSensor, public IPressureSensor {
public:
/**
* Return the current computed altitude in meters. update()
* must have been called prior to calling this method.
*
* @param seaLevelhPA The pressure at sea level in hectoPascals
* (hPa). The default is 1013.25 hPA, (101325 Pa).
* @return The computed altitude in meters.
*/
float getAltitude(float seaLevelhPA=1013.25);
/**
* BMP280 constructor.
*
* This driver supports both the BMP280 and the BME280. The
* BME280 adds a humidity sensor. The device type is detected
* automatically by querying the chip id register.
*
* This device can support both I2C and SPI. For SPI, set the addr
* to -1, and specify a positive integer representing the Chip
* Select (CS) pin for the cs argument. If you are using a
* hardware CS pin, then you can connect the proper pin to the
* hardware CS pin on your MCU and supply -1 for cs. The default
* operating mode is I2C.
*
* @param bus I2C or SPI bus to use.
* @param address The I2C address for this device. Use -1 for SPI.
* @param cs The gpio pin to use for the SPI Chip Select. Use -1
* for I2C, or for SPI with a hardware controlled pin.
* @throws std::runtime_error on failure.
*/
BMP280(int bus=BMP280_DEFAULT_I2C_BUS, int addr=BMP280_DEFAULT_ADDR,
int cs=-1);
/**
* Set a general usage mode. This function can be used to
* configure the filters and oversampling for a particular use
* case. These setting are documented in the BMP280 datasheet.
* The default mode set in the constructor is
* USAGE_MODE_INDOOR_NAV, the highest resolution mode.
*
* @param mode One of the USAGE_MODE_T values.
*/
virtual void setUsageMode(USAGE_MODE_T mode);
/**
* BMP280 Destructor.
*/
virtual ~BMP280();
/**
* Set the temperature sensor oversampling parameter. See the
* data sheet for details. This value can be automatically set to
* a suitable value by using one of the predefined modes for
* setUsageMode().
*
* @param mode One of the OSRS_T_T values.
*/
void setOversampleRateTemperature(OSRS_T_T rate);
/**
* Update the internal stored values from sensor data.
*
* @throws std::runtime_error on failure.
*/
virtual void update();
/**
* Set the pressure sensor oversampling parameter. See the
* data sheet for details. This value can be automatically set to
* a suitable value by using one of the predefined modes for
* setUsageMode().
*
* @param mode One of the OSRS_P_T values.
*/
void setOversampleRatePressure(OSRS_P_T rate);
/**
* Return the chip ID.
*
* @return The chip ID (BMP280_CHIPID).
*/
uint8_t getChipID();
/**
* Set the timer standby value. When in NORMAL operating mode,
* this timer governs how long the chip will wait before
* performing a measurement. See the data sheet for details.
*
* @param mode One of the T_SB_T values.
*/
void setTimerStandby(T_SB_T tsb);
/**
* Reset the sensor, as if by a power-on-reset.
*/
void reset();
/**
* Set the IIR filtering parameter. See the data sheet for
* details. This value can be automatically set to a suitable
* value by using one of the predefined modes for setUsageMode().
*
* @param mode One of the FILTER_T values.
*/
void setFilter(FILTER_T filter);
/**
* Return the current measured temperature. Note, this is not
* ambient temperature - this is the temperature used to fine tune
* the pressure measurement. update() must have been called prior
* to calling this method.
*
* @param fahrenheit true to return data in Fahrenheit, false for
* Celicus. Celsius is the default.
* @return The temperature in degrees Celsius or Fahrenheit.
*/
float getTemperature(bool fahrenheit=false);
/**
* Set the default measuring mode. Basic values are forced,
* sleep, and normal. See the data sheet for details. This value
* can be automatically set to a suitable value by using one of
* the predefined modes for setUsageMode().
*
* @param mode One of the MODES_T values.
*/
void setMeasureMode(MODES_T mode);
/**
* Return the current measured pressure in Pascals (Pa). update()
* must have been called prior to calling this method.
*
* @return The pressure in Pascals (Pa).
*/
float getPressure();
/**
* Set the pressure at sea level in hecto-Pascals (hPA). This
* value is used to compute the altitude based on the
* pressure. At driver initialization time, this value is set
* to 1013.25 hPA.
*
* @param seaLevelhPA The pressure at sea level in hectoPascals
* (hPa). The default is 1013.25 hPA, (101325 Pa).
* @return The computed altitude in meters.
*/
void setSeaLevelPreassure(float seaLevelhPA=1013.25);
/**
* Return the current computed altitude in meters. update()
* must have been called prior to calling this method.
*
* @return The computed altitude in meters.
*/
float getAltitude();
/**
* Set a general usage mode. This function can be used to
* configure the filters and oversampling for a particular use
* case. These setting are documented in the BMP280 datasheet.
* The default mode set in the constructor is
* USAGE_MODE_INDOOR_NAV, the highest resolution mode.
*
* @param mode One of the BMP280_USAGE_MODE_T values.
*/
virtual void setUsageMode(BMP280_USAGE_MODE_T mode);
/**
* Set the temperature sensor oversampling parameter. See the
* data sheet for details. This value can be automatically set to
* a suitable value by using one of the predefined modes for
* setUsageMode().
*
* @param mode One of the BMP280_OSRS_T_T values.
*/
void setOversampleRateTemperature(BMP280_OSRS_T_T rate);
/**
* Set the pressure sensor oversampling parameter. See the
* data sheet for details. This value can be automatically set to
* a suitable value by using one of the predefined modes for
* setUsageMode().
*
* @param mode One of the BMP280_OSRS_P_T values.
*/
void setOversampleRatePressure(BMP280_OSRS_P_T rate);
/**
* Set the timer standby value. When in NORMAL operating mode,
* this timer governs how long the chip will wait before
* performing a measurement. See the data sheet for details.
*
* @param mode One of the BMP280_T_SB_T values.
*/
void setTimerStandby(BMP280_T_SB_T tsb);
/**
* Set the IIR filtering parameter. See the data sheet for
* details. This value can be automatically set to a suitable
* value by using one of the predefined modes for setUsageMode().
*
* @param mode One of the BMP280_FILTER_T values.
*/
void setFilter(BMP280_FILTER_T filter);
/**
* Set the default measuring mode. Basic values are forced,
* sleep, and normal. See the data sheet for details. This value
* can be automatically set to a suitable value by using one of
* the predefined modes for setUsageMode().
*
* @param mode One of the BMP280_MODES_T values.
*/
void setMeasureMode(BMP280_MODES_T mode);
// Interface support
const char *getModuleName()
{
return "BMP280";
// Interface support
const char *getModuleName()
{
return "BMP280";
};
int getTemperatureCelsius()
{
return int(getTemperature(false));
};
int getPressurePa()
{
return int(getPressure());
};
protected:
bmp280_context m_bmp280;
/**
* Return the value of the BMP280_REG_STATUS register.
*
* @return Contents of the status register.
*/
uint8_t getStatus();
/**
* Read a register.
*
* @param reg The register to read
* @return The value of the register
*/
uint8_t readReg(uint8_t reg);
/**
* Read contiguous registers into a buffer.
*
* @param buffer The buffer to store the results
* @param len The number of registers to read
* @return The number of bytes read, or -1 on error
*/
int readRegs(uint8_t reg, uint8_t *buffer, int len);
/**
* Write to a register
*
* @param reg The register to write to
* @param val The value to write
* @throws std::runtime_error on failure.
*/
void writeReg(uint8_t reg, uint8_t val);
private:
};
int getTemperatureCelsius()
{
return int(getTemperature(false));
};
int getPressurePa()
{
return int(getPressure());
};
protected:
mraa::I2c *m_i2c;
mraa::Spi *m_spi;
mraa::Gpio *m_gpioCS;
uint8_t m_addr;
// always stored in C
float m_temperature;
// pressure in Pa
float m_pressure;
// shared calibration data - set in temp conversion, used in
// pressure conversion.
int32_t m_t_fine;
// current operating mode. MODE_FORCED requires special attention
// in update()
MODES_T m_mode;
// return the status register
uint8_t getStatus();
/**
* Read a register.
*
* @param reg The register to read
* @return The value of the register
*/
uint8_t readReg(uint8_t reg);
/**
* Read contiguous registers into a buffer.
*
* @param buffer The buffer to store the results
* @param len The number of registers to read
* @return The number of bytes read, or -1 on error
*/
int readRegs(uint8_t reg, uint8_t *buffer, int len);
/**
* Write to a register
*
* @param reg The register to write to
* @param val The value to write
*/
void writeReg(uint8_t reg, uint8_t val);
// clear member data...
void clearData();
// read the calibration data
virtual void readCalibrationData();
// SPI chip select
void csOn();
void csOff();
private:
// are we doing SPI?
bool m_isSPI;
// calibration data temperature
uint16_t m_dig_T1;
int16_t m_dig_T2;
int16_t m_dig_T3;
// calibration data pressure
uint16_t m_dig_P1;
int16_t m_dig_P2;
int16_t m_dig_P3;
int16_t m_dig_P4;
int16_t m_dig_P5;
int16_t m_dig_P6;
int16_t m_dig_P7;
int16_t m_dig_P8;
int16_t m_dig_P9;
// Bosch supplied conversion/compensation functions from the
// datasheet.
int32_t bmp280_compensate_T_int32(int32_t adc_T);
uint32_t bmp280_compensate_P_int64(int32_t adc_P);
};
}

290
src/bmp280/bmp280_regs.h Normal file
View File

@ -0,0 +1,290 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016-2017 Intel Corporation.
*
* The MIT License
*
* 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.
*/
#pragma once
// BMP280
#define BMP280_DEFAULT_I2C_BUS 0
#define BMP280_DEFAULT_SPI_BUS 0
#define BMP280_DEFAULT_ADDR 0x77
#define BMP280_CHIPID 0x58
// BME280
#define BME280_DEFAULT_I2C_BUS 0
#define BME280_DEFAULT_SPI_BUS 0
#define BME280_DEFAULT_ADDR 0x77
#define BME280_CHIPID 0x60
// default sea level pressure in hPA
#define BMP280_SEA_LEVEL_HPA (1013.25)
// special reset byte, same for bme280
#define BMP280_RESET_BYTE 0xb6
#ifdef __cplusplus
extern "C" {
#endif
/**
* BMP280 registers
*/
typedef enum {
// Do not write into reserved bits.
// read-only factory calibration data
BMP280_REG_CALIB00 = 0x88,
BMP280_REG_CALIB01 = 0x89,
BMP280_REG_CALIB02 = 0x8a,
BMP280_REG_CALIB03 = 0x8b,
BMP280_REG_CALIB04 = 0x8c,
BMP280_REG_CALIB05 = 0x8d,
BMP280_REG_CALIB06 = 0x8e,
BMP280_REG_CALIB07 = 0x8f,
BMP280_REG_CALIB08 = 0x90,
BMP280_REG_CALIB09 = 0x91,
BMP280_REG_CALIB10 = 0x92,
BMP280_REG_CALIB11 = 0x93,
BMP280_REG_CALIB12 = 0x94,
BMP280_REG_CALIB13 = 0x95,
BMP280_REG_CALIB14 = 0x96,
BMP280_REG_CALIB15 = 0x97,
BMP280_REG_CALIB16 = 0x98,
BMP280_REG_CALIB17 = 0x99,
BMP280_REG_CALIB18 = 0x9a,
BMP280_REG_CALIB19 = 0x9b,
BMP280_REG_CALIB20 = 0x9c,
BMP280_REG_CALIB21 = 0x9d,
BMP280_REG_CALIB22 = 0x9e,
BMP280_REG_CALIB23 = 0x9f,
BMP280_REG_CALIB24 = 0xa0,
BMP280_REG_CALIB25 = 0xa1,
BMP280_REG_CHIPID = 0xd0,
BMP280_REG_RESET = 0xe0,
BMP280_REG_STATUS = 0xf3,
BMP280_REG_CTRL_MEAS = 0xf4,
BMP280_REG_CONFIG = 0xf5,
BMP280_REG_PRESSURE_MSB = 0xf7,
BMP280_REG_PRESSURE_LSB = 0xf8,
BMP280_REG_PRESSURE_XLSB = 0xf9,
BMP280_REG_TEMPERATURE_MSB = 0xfa,
BMP280_REG_TEMPERATURE_LSB = 0xfb,
BMP280_REG_TEMPERATURE_XLSB = 0xfc
} BMP280_REGS_T;
/**
* BMP280_REG_CONFIG bits
*/
typedef enum {
BMP280_CONFIG_SPI3W_EN = 0x01,
// 0x02 reserved
BMP280_CONFIG_FILTER0 = 0x04,
BMP280_CONFIG_FILTER1 = 0x08,
BMP280_CONFIG_FILTER2 = 0x10,
_BMP280_CONFIG_FILTER_MASK = 7,
_BMP280_CONFIG_FILTER_SHIFT = 2,
BMP280_CONFIG_T_SB0 = 0x20,
BMP280_CONFIG_T_SB1 = 0x40,
BMP280_CONFIG_T_SB2 = 0x80,
_BMP280_CONFIG_T_SB_MASK = 7,
_BMP280_CONFIG_T_SB_SHIFT = 5
} BMP280_CONFIG_BITS_T;
/**
* BMP280_FILTER values (samples to reach >= 75% of step response)
*/
typedef enum {
BMP280_FILTER_OFF = 0, // 1 samples
BMP280_FILTER_2 = 1, // 2
BMP280_FILTER_4 = 2, // 5
BMP280_FILTER_8 = 3, // 11
BMP280_FILTER_16 = 4 // 22
} BMP280_FILTER_T;
/**
* BMP280_T_SB values (timer standby)
*/
typedef enum {
BMP280_T_SB_0_5 = 0, // 0.5ms
BMP280_T_SB_62_5 = 1, // 62.5ms
BMP280_T_SB_125 = 2, // 125ms
BMP280_T_SB_250 = 3,
BMP280_T_SB_500 = 4,
BMP280_T_SB_1000 = 5,
BMP280_T_SB_2000 = 6, // bme280 - 10ms
BMP280_T_SB_4000 = 7 // bme280 - 20ms
} BMP280_T_SB_T;
/**
* BMP280_REG_CTRL_MEAS bits
*/
typedef enum {
BMP280_CTRL_MEAS_MODE0 = 0x01,
BMP280_CTRL_MEAS_MODE1 = 0x02,
_BMP280_CTRL_MEAS_MODE_MASK = 3,
_BMP280_CTRL_MEAS_MODE_SHIFT = 0,
BMP280_CTRL_MEAS_OSRS_P0 = 0x04,
BMP280_CTRL_MEAS_OSRS_P1 = 0x08,
BMP280_CTRL_MEAS_OSRS_P2 = 0x10,
_BMP280_CTRL_MEAS_OSRS_P_MASK = 7,
_BMP280_CTRL_MEAS_OSRS_P_SHIFT = 2,
BMP280_CTRL_MEAS_OSRS_T0 = 0x04,
BMP280_CTRL_MEAS_OSRS_T1 = 0x08,
BMP280_CTRL_MEAS_OSRS_T2 = 0x10,
_BMP280_CTRL_MEAS_OSRS_T_MASK = 7,
_BMP280_CTRL_MEAS_OSRS_T_SHIFT = 5
} BMP280_CTRL_MEAS_T;
/**
* BMP280_CTRL_MEAS_MODE values
*/
typedef enum {
BMP280_MODE_SLEEP = 0,
BMP280_MODE_FORCED = 1,
// 2 is also FORCED mode
BMP280_MODE_NORMAL = 3
} BMP280_MODES_T;
/**
* BMP280_CTRL_MEAS_OSRS_P values
*/
typedef enum {
BMP280_OSRS_P_SKIPPED = 0,
BMP280_OSRS_P_OVERSAMPLING_1 = 1, // x1
BMP280_OSRS_P_OVERSAMPLING_2 = 2, // x2
BMP280_OSRS_P_OVERSAMPLING_4 = 3,
BMP280_OSRS_P_OVERSAMPLING_8 = 4,
BMP280_OSRS_P_OVERSAMPLING_16 = 5
} BMP280_OSRS_P_T;
/**
* BMP280_CTRL_MEAS_OSRS_T values
*/
typedef enum {
BMP280_OSRS_T_SKIPPED = 0,
BMP280_OSRS_T_OVERSAMPLING_1 = 1, // x1
BMP280_OSRS_T_OVERSAMPLING_2 = 2, // x2
BMP280_OSRS_T_OVERSAMPLING_4 = 3,
BMP280_OSRS_T_OVERSAMPLING_8 = 4,
BMP280_OSRS_T_OVERSAMPLING_16 = 5
} BMP280_OSRS_T_T;
/**
* BMP280_REG_STATUS bits
*/
typedef enum {
BMP280_STATUS_IM_UPDATE = 0x01,
// 0x02-0x04 reserved
BMP280_STATUS_MEASURING = 0x08
// 0x10-0x80 reserved
} BMP280_STATUS_T;
/**
* BMP280_USAGE_MODE values. This is a fake specification to
* configure the various knobs based on their typical use modes,
* as recommended by Bosch.
*/
typedef enum {
BMP280_USAGE_MODE_HANDHELD_LOW_POWER = 0,
BMP280_USAGE_MODE_HANDHELD_DYNAMIC = 1,
BMP280_USAGE_MODE_WEATHER_MONITOR = 2, // lowest power consumption
BMP280_USAGE_MODE_FLOOR_CHG_DETECT = 3,
BMP280_USAGE_MODE_DROP_DETECT = 4,
BMP280_USAGE_MODE_INDOOR_NAV = 5 // highest resolution
} BMP280_USAGE_MODE_T;
// The following are registers specific to the BME280. The BME280
// is identical to the BMP280 with the exception of humidity
// sensor support and the corresponding registers needed to
// support it.
/**
* BME280 registers
*/
typedef enum {
// Do not write into reserved bits.
// We only specify those registers specific to the BME280. The
// rest of them can be found in the BMP280 header file.
// read-only factory calibration data for humidity
BME280_REG_CALIB_DIG_H1 = 0xa1,
BME280_REG_CALIB_DIG_H2_LSB = 0xe1,
BME280_REG_CALIB_DIG_H2_MSB = 0xe2,
BME280_REG_CALIB_DIG_H3 = 0xe3,
BME280_REG_CALIB_DIG_H4_0 = 0xe4, // bits 8 -> 11:4
BME280_REG_CALIB_DIG_H4_1 = 0xe5, // bits 3:0 -> 3:0
BME280_REG_CALIB_DIG_H5_0 = 0xe5, // bits 7:4 -> 3:0
BME280_REG_CALIB_DIG_H5_1 = 0xe6, // bits 8 -> 11:4
BME280_REG_CALIB_DIG_H6 = 0xe7,
BME280_REG_CTRL_HUM = 0xf2,
BME280_REG_HUMIDITY_MSB = 0xfd,
BME280_REG_HUMIDITY_LSB = 0xfe
} BME280_REGS_T;
/**
* BME280_REG_CTRL_HUM bits
*/
typedef enum {
BME280_CTRL_HUM_OSRS_H0 = 0x01,
BME280_CTRL_HUM_OSRS_H1 = 0x02,
BME280_CTRL_HUM_OSRS_H2 = 0x04,
_BME280_CTRL_HUM_OSRS_H_MASK = 3,
_BME280_CTRL_HUM_OSRS_H_SHIFT = 0
// 0x08-0x80 reserved
} BME280_CTRL_HUM_T;
/**
* BME280_CTRL_HUM_OSRS_H values
*/
typedef enum {
BME280_OSRS_H_SKIPPED = 0,
BME280_OSRS_H_OVERSAMPLING_1 = 1, // x1
BME280_OSRS_H_OVERSAMPLING_2 = 2, // x2
BME280_OSRS_H_OVERSAMPLING_4 = 3,
BME280_OSRS_H_OVERSAMPLING_8 = 4,
BME280_OSRS_H_OVERSAMPLING_16 = 5
} BME280_OSRS_H_T;
#ifdef __cplusplus
}
#endif

View File

@ -5,11 +5,7 @@
%include "../interfaces/javaupm_iHumiditySensor.i"
%include "../interfaces/javaupm_iPressureSensor.i"
%include "cpointer.i"
%include "typemaps.i"
%include "arrays_java.i";
%include "../java_buffer.i"
%include "bmp280_regs.h"
%include "bmp280.hpp"
%{
#include "bmp280.hpp"

View File

@ -6,6 +6,8 @@
%include "iHumiditySensor.hpp"
%include "iPressureSensor.hpp"
%include "iTemperatureSensor.hpp"
%include "bmp280_regs.h"
%include "bmp280.hpp"
%{
#include "bmp280.hpp"

View File

@ -16,6 +16,8 @@
%include "iHumiditySensor.hpp"
%include "iPressureSensor.hpp"
%include "iTemperatureSensor.hpp"
%include "bmp280_regs.h"
%include "bmp280.hpp"
%{
#include "bmp280.hpp"