/* * Author: Jon Trulson * Copyright (c) 2016 Intel Corporation. * * 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 #include #include #include #include "upm/iPressureSensor.hpp" #include "upm/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 BMP280 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 μA @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 */ 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. * * 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 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. * * @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. * * @param fahrenheit true to return data in Fahrenheit, false for * Celicus. Celcius is the default. * @return The temperature in degrees Celcius or Fahrenheit. */ 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(); /** * 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); /** * 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 contructor 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); /** * 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); /** * 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); /** * 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); /** * 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); /** * 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); // Interface support const char *getModuleName() { return "BMP280"; }; int getTemperatureCelcius() { 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); }; }