mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
drivers/bmx280: significant driver rework
bugs fixed: - move global variables into device descriptor - guard bus access (use acquire and release) added functionality: - enable SPI mode structural improvements: - reduce stack usage - simplify the driver's structure - centralize bus access code - use assertions - cleanup includes - use shortcuts for bus access style changes: - fix line length - cleanup and improve doxygen - unify pointer notation (char *var over char* var) - unify (error) return messages - use `#ifdef MODULE_BME280` instead of `#if defined(BME..)` - unify debug messages -> using `[bmx28] x: msg` scheme
This commit is contained in:
parent
e90dd16347
commit
b7f33bd84f
@ -75,16 +75,25 @@ ifneq (,$(filter bmp180,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter bmx055,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_i2c
|
||||
ifneq (,$(filter bm%280_spi,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_spi
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
USEMODULE += bmx280
|
||||
endif
|
||||
|
||||
ifneq (,$(filter bm%280,$(USEMODULE)))
|
||||
ifneq (,$(filter bm%280_i2c,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_i2c
|
||||
USEMODULE += xtimer
|
||||
USEMODULE += bmx280
|
||||
endif
|
||||
|
||||
ifneq (,$(filter bmx280,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter bmx055,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_i2c
|
||||
endif
|
||||
|
||||
ifneq (,$(filter cc110%,$(USEMODULE)))
|
||||
USEMODULE += cc110x
|
||||
USEMODULE += cc1xxx_common
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kees Bakker, SODAQ
|
||||
* 2017 Inria
|
||||
* 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -12,9 +13,10 @@
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Device driver implementation for sensors BMX280 (BME280 and BMP280).
|
||||
* @brief Device driver implementation for BME280 and BMP280 sensors
|
||||
*
|
||||
* @author Kees Bakker <kees@sodaq.com>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
@ -23,93 +25,322 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "assert.h"
|
||||
#include "bmx280.h"
|
||||
#include "bmx280_internals.h"
|
||||
#include "bmx280_params.h"
|
||||
#include "periph/i2c.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static int read_calibration_data(bmx280_t* dev);
|
||||
static int do_measurement(const bmx280_t* dev);
|
||||
static uint8_t get_ctrl_meas(const bmx280_t* dev);
|
||||
static uint8_t get_status(const bmx280_t* dev);
|
||||
static uint8_t read_u8_reg(const bmx280_t* dev, uint8_t reg);
|
||||
static void write_u8_reg(const bmx280_t* dev, uint8_t reg, uint8_t b);
|
||||
static uint16_t get_uint16_le(const uint8_t *buffer, size_t offset);
|
||||
static int16_t get_int16_le(const uint8_t *buffer, size_t offset);
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
static void dump_buffer(const char *txt, uint8_t *buffer, size_t size);
|
||||
#define DUMP_BUFFER(txt, buffer, size) dump_buffer(txt, buffer, size)
|
||||
#ifdef BMX280_USE_SPI
|
||||
#define BUS (dev->params.spi)
|
||||
#define CS (dev->params.cs)
|
||||
#define CLK (dev->params.clk)
|
||||
#define MODE SPI_MODE_0
|
||||
#define WRITE_MASK (0x7F)
|
||||
#else
|
||||
#define DUMP_BUFFER(txt, buffer, size)
|
||||
#define BUS (dev->params.i2c_dev)
|
||||
#define ADDR (dev->params.i2c_addr)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Fine resolution temperature value, also needed for pressure and humidity.
|
||||
*/
|
||||
static int32_t t_fine;
|
||||
/* shortcut for accessing byte x of the latest sensor reading */
|
||||
#define RAW_DATA (dev->last_reading)
|
||||
|
||||
/**
|
||||
* @brief The measurement registers, including temperature, pressure and humidity
|
||||
*
|
||||
* A temporary buffer for the memory map 0xF7..0xFE
|
||||
* These are read all at once and then used to compute the three sensor values.
|
||||
*/
|
||||
static uint8_t measurement_regs[8];
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* BMX280 Core API *
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int bmx280_init(bmx280_t* dev, const bmx280_params_t* params)
|
||||
/* implementation for the driver's configured bus interface (I2C vs SPI) */
|
||||
#ifdef BMX280_USE_SPI /* using SPI mode */
|
||||
static inline int _acquire(const bmx280_t *dev)
|
||||
{
|
||||
uint8_t chip_id;
|
||||
if (spi_acquire(BUS, CS, MODE, CLK) != SPI_OK) {
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
dev->params = *params;
|
||||
static inline void _release(const bmx280_t *dev)
|
||||
{
|
||||
spi_release(BUS);
|
||||
}
|
||||
|
||||
/* Read chip ID */
|
||||
chip_id = read_u8_reg(dev, BMX280_CHIP_ID_REG);
|
||||
if ((chip_id != BME280_CHIP_ID) && (chip_id != BMP280_CHIP_ID)) {
|
||||
DEBUG("[Error] Did not detect a BMX280 at address %02x (%02x != %02x or %02x)\n",
|
||||
dev->params.i2c_addr, chip_id, BME280_CHIP_ID, BMP280_CHIP_ID);
|
||||
return BMX280_ERR_NODEV;
|
||||
static int _read_reg(const bmx280_t *dev, uint8_t reg, uint8_t *data)
|
||||
{
|
||||
*data = spi_transfer_reg(BUS, CS, reg, 0);
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
static int _write_reg(const bmx280_t *dev, uint8_t reg, uint8_t data)
|
||||
{
|
||||
(void)spi_transfer_reg(BUS, CS, (reg & WRITE_MASK), data);
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
static int _read_burst(const bmx280_t *dev, uint8_t reg, void *buf, size_t len)
|
||||
{
|
||||
spi_transfer_regs(BUS, CS, reg, NULL, buf, len);
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
#else /* using I2C mode */
|
||||
|
||||
static inline int _acquire(const bmx280_t *dev)
|
||||
{
|
||||
if (i2c_acquire(BUS) != 0) {
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
static inline void _release(const bmx280_t *dev)
|
||||
{
|
||||
i2c_release(BUS);
|
||||
}
|
||||
|
||||
static int _read_reg(const bmx280_t *dev, uint8_t reg, uint8_t *data)
|
||||
{
|
||||
if (i2c_read_reg(BUS, ADDR, reg, data, 0) != 0) {
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
static int _write_reg(const bmx280_t *dev, uint8_t reg, uint8_t data)
|
||||
{
|
||||
if (i2c_write_reg(BUS, ADDR, reg, data, 0) != 0) {
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
static int _read_burst(const bmx280_t *dev, uint8_t reg, void *buf, size_t len)
|
||||
{
|
||||
if (i2c_read_regs(BUS, ADDR, reg, buf, len, 0) != 0) {
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
#endif /* bus mode selection */
|
||||
|
||||
static uint16_t _to_u16_le(const uint8_t *buffer, size_t offset)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return (((uint16_t)buffer[offset + 1]) << 8) + buffer[offset];
|
||||
#else
|
||||
return (((uint16_t)buffer[offset]) << 8) + buffer[offset + 1];
|
||||
#endif
|
||||
}
|
||||
|
||||
static int16_t _to_i16_le(const uint8_t *buffer, size_t offset)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return (((int16_t)buffer[offset + 1]) << 8) + buffer[offset];
|
||||
#else
|
||||
return (((int16_t)buffer[offset]) << 8) + buffer[offset + 1];
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the calibration data from sensor ROM, it is in registers
|
||||
* 0x88..0x9F, 0xA1, and 0xE1..0xE7
|
||||
*/
|
||||
static int _read_calibration_data(bmx280_t *dev)
|
||||
{
|
||||
/* no need to acquire a bus here, as this is done in the init function */
|
||||
|
||||
/* allocate some memory to store the largest block of calibration data */
|
||||
uint8_t buf[CALIB_T_P_LEN];
|
||||
|
||||
/* read humidity and temperature calibration data */
|
||||
if (_read_burst(dev, CALIB_T_P_BASE, buf, CALIB_T_P_LEN) != BMX280_OK) {
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
|
||||
/* Read compensation data, 0x88..0x9F, 0xA1, 0xE1..0xE7 */
|
||||
if (read_calibration_data(dev)) {
|
||||
DEBUG("[Error] Could not read calibration data\n");
|
||||
return BMX280_ERR_NOCAL;
|
||||
/* convert calibration values to little endian format and save them */
|
||||
dev->calibration.dig_T1 = _to_u16_le(buf, OFFSET_T_P(BMX280_DIG_T1_LSB_REG));
|
||||
dev->calibration.dig_T2 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_T2_LSB_REG));
|
||||
dev->calibration.dig_T3 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_T3_LSB_REG));
|
||||
|
||||
dev->calibration.dig_P1 = _to_u16_le(buf, OFFSET_T_P(BMX280_DIG_P1_LSB_REG));
|
||||
dev->calibration.dig_P2 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_P2_LSB_REG));
|
||||
dev->calibration.dig_P3 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_P3_LSB_REG));
|
||||
dev->calibration.dig_P4 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_P4_LSB_REG));
|
||||
dev->calibration.dig_P5 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_P5_LSB_REG));
|
||||
dev->calibration.dig_P6 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_P6_LSB_REG));
|
||||
dev->calibration.dig_P7 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_P7_LSB_REG));
|
||||
dev->calibration.dig_P8 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_P8_LSB_REG));
|
||||
dev->calibration.dig_P9 = _to_i16_le(buf, OFFSET_T_P(BMX280_DIG_P9_LSB_REG));
|
||||
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
/* read dig_H1 in a single read, as this value is not in the block with the
|
||||
* rest of the humidity calibration values */
|
||||
if (_read_reg(dev, BME280_DIG_H1_REG, &dev->calibration.dig_H1) != BMX280_OK) {
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
|
||||
/* read the block with the rest of the values */
|
||||
if (_read_burst(dev, CALIB_H_BASE, buf, CALIB_H_LEN) != BMX280_OK) {
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
|
||||
/* parse the humidity compensation and store in device descriptor */
|
||||
dev->calibration.dig_H2 = _to_i16_le(buf, OFFSET_H(BME280_DIG_H2_LSB_REG));
|
||||
dev->calibration.dig_H3 = buf[OFFSET_H(BME280_DIG_H3_REG)];
|
||||
dev->calibration.dig_H4 = ((((int16_t)buf[OFFSET_H(BME280_DIG_H4_MSB_REG)]) << 4) +
|
||||
(buf[OFFSET_H(BME280_DIG_H4_H5_REG)] & 0x0F));
|
||||
dev->calibration.dig_H5 = ((((int16_t)buf[OFFSET_H(BME280_DIG_H5_MSB_REG)]) << 4) +
|
||||
((buf[OFFSET_H(BME280_DIG_H4_H5_REG)] & 0xF0) >> 4));
|
||||
dev->calibration.dig_H6 = buf[OFFSET_H(BME280_DIG_H6_REG)];
|
||||
#endif
|
||||
|
||||
return BMX280_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns temperature in DegC, resolution is 0.01 DegC.
|
||||
* t_fine carries fine temperature as global value
|
||||
/**
|
||||
* @brief Trigger a new measurement (if applicable) and read raw data
|
||||
*/
|
||||
int16_t bmx280_read_temperature(const bmx280_t* dev)
|
||||
static int _do_measurement(bmx280_t *dev)
|
||||
{
|
||||
if (do_measurement(dev) < 0) {
|
||||
uint8_t reg;
|
||||
|
||||
/* get access to the bus */
|
||||
if (_acquire(dev) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* if in FORCED mode, we need to manually trigger a measurement */
|
||||
if (dev->params.run_mode != BMX280_MODE_NORMAL) {
|
||||
reg = ((dev->params.temp_oversample << MEAS_OSRS_T_POS) |
|
||||
(dev->params.press_oversample << MEAS_OSRS_P_POS) |
|
||||
BMX280_MODE_FORCED);
|
||||
if (_write_reg(dev, BMX280_CTRL_MEAS_REG, reg) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
do {
|
||||
if (_read_reg(dev, BMX280_STAT_REG, ®) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
} while (reg & STAT_MEASURING);
|
||||
/* results are ready now */
|
||||
DEBUG("[bmx280] _do_measurement: measurement data ready\n");
|
||||
}
|
||||
|
||||
/* read all raw data registers into data buffer */
|
||||
if (_read_burst(dev, DATA_BASE, RAW_DATA, BMX280_RAW_LEN) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* we are done reading from the device, so release the bus again */
|
||||
_release(dev);
|
||||
return BMX280_OK;
|
||||
|
||||
err:
|
||||
_release(dev);
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
|
||||
int bmx280_init(bmx280_t *dev, const bmx280_params_t *params)
|
||||
{
|
||||
assert(dev && params);
|
||||
|
||||
dev->params = *params;
|
||||
uint8_t reg;
|
||||
|
||||
|
||||
#ifdef BMX280_USE_SPI
|
||||
/* configure the chip-select pin */
|
||||
if (spi_init_cs(BUS, CS) != SPI_OK) {
|
||||
DEBUG("[bmx280] error: unable to configure chip the select pin\n");
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* acquire bus bus, this also tests the bus parameters in SPI mode */
|
||||
if (_acquire(dev) != BMX280_OK) {
|
||||
DEBUG("[bmx280] error: unable to acquire bus\n");
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
|
||||
/* test the connection to the device by reading and verifying its chip ID */
|
||||
if (_read_reg(dev, BMX280_CHIP_ID_REG, ®) != BMX280_OK) {
|
||||
DEBUG("[bmx280] error: unable to read chip ID from device\n");
|
||||
return BMX280_ERR_NODEV;
|
||||
}
|
||||
if (reg != BMX280_CHIP_ID_VAL) {
|
||||
DEBUG("[bmx280] error: invalid chip ID (0x%02x)\n", (int)reg);
|
||||
_release(dev);
|
||||
return BMX280_ERR_NODEV;
|
||||
}
|
||||
|
||||
/* trigger a power-on reset sequence to reset all registers */
|
||||
if (_write_reg(dev, BMEX80_RST_REG, RESET_WORD) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
/* wait for reset sequence to finish */
|
||||
do {
|
||||
if (_read_reg(dev, BMX280_STAT_REG, ®) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
} while (reg != 0);
|
||||
|
||||
/* read the compensation data from the sensor's ROM */
|
||||
if (_read_calibration_data(dev) != BMX280_OK) {
|
||||
DEBUG("[bmx280] error: could not read calibration data\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* write basic device configuration: t_sb and filter values */
|
||||
reg = (dev->params.t_sb | dev->params.filter);
|
||||
if (_write_reg(dev, BMX280_CONFIG_REG, reg) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
/* ctrl_hum must be written before ctrl_meas for changes to become
|
||||
* effective */
|
||||
reg = dev->params.humid_oversample;
|
||||
if (_write_reg(dev, BME280_CTRL_HUM_REG, reg) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* finally apply the temperature and pressure oversampling configuration and
|
||||
* configure the run mode */
|
||||
reg = ((dev->params.temp_oversample << MEAS_OSRS_T_POS) |
|
||||
(dev->params.press_oversample << MEAS_OSRS_P_POS) |
|
||||
(dev->params.run_mode));
|
||||
if (_write_reg(dev, BMX280_CTRL_MEAS_REG, reg) != BMX280_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
_release(dev);
|
||||
return BMX280_OK;
|
||||
|
||||
err:
|
||||
_release(dev);
|
||||
DEBUG("[bmx280] init: bus error while initializing device\n");
|
||||
return BMX280_ERR_BUS;
|
||||
}
|
||||
|
||||
int16_t bmx280_read_temperature(bmx280_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
|
||||
if (_do_measurement(dev) < 0) {
|
||||
return INT16_MIN;
|
||||
}
|
||||
|
||||
const bmx280_calibration_t *cal = &dev->calibration; /* helper variable */
|
||||
|
||||
/* Read the uncompensated temperature */
|
||||
int32_t adc_T = (((uint32_t)measurement_regs[3 + 0]) << 12) |
|
||||
(((uint32_t)measurement_regs[3 + 1]) << 4) |
|
||||
((((uint32_t)measurement_regs[3 + 2]) >> 4) & 0x0F);
|
||||
int32_t adc_T = (((uint32_t)RAW_DATA[3 + 0]) << 12) |
|
||||
(((uint32_t)RAW_DATA[3 + 1]) << 4) |
|
||||
((((uint32_t)RAW_DATA[3 + 2]) >> 4) & 0x0F);
|
||||
|
||||
/*
|
||||
* Compensate the temperature value.
|
||||
* The following is code from Bosch's BME280_driver bme280_compensate_temperature_int32()
|
||||
* The variable names and the many defines have been modified to make the code
|
||||
* more readable.
|
||||
* The following is code from Bosch's BME280_driver
|
||||
* bme280_compensate_temperature_int32(). The variable names and the many
|
||||
* defines have been modified to make the code more readable.
|
||||
*/
|
||||
int32_t var1;
|
||||
int32_t var2;
|
||||
@ -119,22 +350,21 @@ int16_t bmx280_read_temperature(const bmx280_t* dev)
|
||||
((int32_t)cal->dig_T3)) >> 14;
|
||||
|
||||
/* calculate t_fine (used for pressure and humidity too) */
|
||||
t_fine = var1 + var2;
|
||||
dev->t_fine = var1 + var2;
|
||||
|
||||
return (t_fine * 5 + 128) >> 8;
|
||||
return (dev->t_fine * 5 + 128) >> 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns pressure in Pa
|
||||
*/
|
||||
uint32_t bmx280_read_pressure(const bmx280_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
|
||||
const bmx280_calibration_t *cal = &dev->calibration; /* helper variable */
|
||||
|
||||
/* Read the uncompensated pressure */
|
||||
int32_t adc_P = (((uint32_t)measurement_regs[0 + 0]) << 12) |
|
||||
(((uint32_t)measurement_regs[0 + 1]) << 4) |
|
||||
((((uint32_t)measurement_regs[0 + 2]) >> 4) & 0x0F);
|
||||
int32_t adc_P = (((uint32_t)RAW_DATA[0 + 0]) << 12) |
|
||||
(((uint32_t)RAW_DATA[0 + 1]) << 4) |
|
||||
((((uint32_t)RAW_DATA[0 + 2]) >> 4) & 0x0F);
|
||||
|
||||
int64_t var1;
|
||||
int64_t var2;
|
||||
@ -142,11 +372,11 @@ uint32_t bmx280_read_pressure(const bmx280_t *dev)
|
||||
|
||||
/*
|
||||
* Compensate the pressure value.
|
||||
* The following is code from Bosch's BME280_driver bme280_compensate_pressure_int64()
|
||||
* The variable names and the many defines have been modified to make the code
|
||||
* more readable.
|
||||
* The following is code from Bosch's BME280_driver
|
||||
* bme280_compensate_pressure_int64(). The variable names and the many
|
||||
* defines have been modified to make the code more readable.
|
||||
*/
|
||||
var1 = ((int64_t)t_fine) - 128000;
|
||||
var1 = ((int64_t)dev->t_fine) - 128000;
|
||||
var2 = var1 * var1 * (int64_t)cal->dig_P6;
|
||||
var2 = var2 + ((var1 * (int64_t)cal->dig_P5) << 17);
|
||||
var2 = var2 + (((int64_t)cal->dig_P4) << 35);
|
||||
@ -166,27 +396,29 @@ uint32_t bmx280_read_pressure(const bmx280_t *dev)
|
||||
return p_acc >> 8;
|
||||
}
|
||||
|
||||
#if defined(MODULE_BME280)
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
uint16_t bme280_read_humidity(const bmx280_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
|
||||
const bmx280_calibration_t *cal = &dev->calibration; /* helper variable */
|
||||
|
||||
/* Read the uncompensated pressure */
|
||||
int32_t adc_H = (((uint32_t)measurement_regs[6 + 0]) << 8) |
|
||||
(((uint32_t)measurement_regs[6 + 1]));
|
||||
int32_t adc_H = (((uint32_t)RAW_DATA[6 + 0]) << 8) |
|
||||
(((uint32_t)RAW_DATA[6 + 1]));
|
||||
|
||||
/*
|
||||
* Compensate the humidity value.
|
||||
* The following is code from Bosch's BME280_driver bme280_compensate_humidity_int32()
|
||||
* The variable names and the many defines have been modified to make the code
|
||||
* more readable.
|
||||
* The following is code from Bosch's BME280_driver
|
||||
* bme280_compensate_humidity_int32(). The variable names and the many
|
||||
* defines have been modified to make the code more readable.
|
||||
* The value is first computed as a value in %rH as unsigned 32bit integer
|
||||
* in Q22.10 format(22 integer 10 fractional bits).
|
||||
*/
|
||||
int32_t var1;
|
||||
|
||||
/* calculate x1*/
|
||||
var1 = (t_fine - ((int32_t)76800));
|
||||
var1 = (dev->t_fine - ((int32_t)76800));
|
||||
/* calculate x1*/
|
||||
var1 = (((((adc_H << 14) - (((int32_t)cal->dig_H4) << 20) - (((int32_t)cal->dig_H5) * var1)) +
|
||||
((int32_t)16384)) >> 15) *
|
||||
@ -194,190 +426,9 @@ uint16_t bme280_read_humidity(const bmx280_t *dev)
|
||||
(((var1 * ((int32_t)cal->dig_H3)) >> 11) + ((int32_t)32768))) >> 10) +
|
||||
((int32_t)2097152)) * ((int32_t)cal->dig_H2) + 8192) >> 14));
|
||||
var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * ((int32_t)cal->dig_H1)) >> 4));
|
||||
var1 = (var1 < 0 ? 0 : var1);
|
||||
var1 = (var1 > 419430400 ? 419430400 : var1);
|
||||
var1 = (var1 < 0) ? 0 : var1;
|
||||
var1 = (var1 > 419430400) ? 419430400 : var1;
|
||||
/* First multiply to avoid losing the accuracy after the shift by ten */
|
||||
return (100 * ((uint32_t)var1 >> 12)) >> 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Read compensation data, 0x88..0x9F, 0xA1, 0xE1..0xE7
|
||||
*
|
||||
* This function reads all calibration bytes at once. These are
|
||||
* the registers DIG_T1_LSB (0x88) upto and including DIG_H6 (0xE7).
|
||||
*/
|
||||
static int read_calibration_data(bmx280_t* dev)
|
||||
{
|
||||
uint8_t buffer[128]; /* 128 should be enough to read all calibration bytes */
|
||||
int result;
|
||||
#ifdef MODULE_BME280
|
||||
int nr_bytes_to_read = (BME280_DIG_H6_REG - BMX280_DIG_T1_LSB_REG) + 1;
|
||||
#else
|
||||
int nr_bytes_to_read = (BMX280_DIG_P9_MSB_REG - BMX280_DIG_T1_LSB_REG) + 1;
|
||||
#endif
|
||||
uint8_t offset = 0x88;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
result = i2c_read_regs(dev->params.i2c_dev, dev->params.i2c_addr, offset,
|
||||
buffer, nr_bytes_to_read, 0);
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
if (result != 0) {
|
||||
LOG_ERROR("Unable to read calibration data\n");
|
||||
return -1;
|
||||
}
|
||||
DUMP_BUFFER("Raw Calibration Data", buffer, nr_bytes_to_read);
|
||||
|
||||
/* All little endian */
|
||||
dev->calibration.dig_T1 = get_uint16_le(buffer, BMX280_DIG_T1_LSB_REG - offset);
|
||||
dev->calibration.dig_T2 = get_int16_le(buffer, BMX280_DIG_T2_LSB_REG - offset);
|
||||
dev->calibration.dig_T3 = get_int16_le(buffer, BMX280_DIG_T3_LSB_REG - offset);
|
||||
|
||||
dev->calibration.dig_P1 = get_uint16_le(buffer, BMX280_DIG_P1_LSB_REG - offset);
|
||||
dev->calibration.dig_P2 = get_int16_le(buffer, BMX280_DIG_P2_LSB_REG - offset);
|
||||
dev->calibration.dig_P3 = get_int16_le(buffer, BMX280_DIG_P3_LSB_REG - offset);
|
||||
dev->calibration.dig_P4 = get_int16_le(buffer, BMX280_DIG_P4_LSB_REG - offset);
|
||||
dev->calibration.dig_P5 = get_int16_le(buffer, BMX280_DIG_P5_LSB_REG - offset);
|
||||
dev->calibration.dig_P6 = get_int16_le(buffer, BMX280_DIG_P6_LSB_REG - offset);
|
||||
dev->calibration.dig_P7 = get_int16_le(buffer, BMX280_DIG_P7_LSB_REG - offset);
|
||||
dev->calibration.dig_P8 = get_int16_le(buffer, BMX280_DIG_P8_LSB_REG - offset);
|
||||
dev->calibration.dig_P9 = get_int16_le(buffer, BMX280_DIG_P9_LSB_REG - offset);
|
||||
|
||||
#if defined(MODULE_BME280)
|
||||
dev->calibration.dig_H1 = buffer[BME280_DIG_H1_REG - offset];
|
||||
dev->calibration.dig_H2 = get_int16_le(buffer, BME280_DIG_H2_LSB_REG - offset);
|
||||
dev->calibration.dig_H3 = buffer[BME280_DIG_H3_REG - offset];
|
||||
dev->calibration.dig_H4 = (((int16_t)buffer[BME280_DIG_H4_MSB_REG - offset]) << 4) +
|
||||
(buffer[BME280_DIG_H4_H5_REG - offset] & 0x0F);
|
||||
dev->calibration.dig_H5 = (((int16_t)buffer[BME280_DIG_H5_MSB_REG - offset]) << 4) +
|
||||
((buffer[BME280_DIG_H4_H5_REG - offset] & 0xF0) >> 4);
|
||||
dev->calibration.dig_H6 = buffer[BME280_DIG_H6_REG - offset];
|
||||
#endif
|
||||
|
||||
DEBUG("[INFO] Chip ID = 0x%02X\n", buffer[BMX280_CHIP_ID_REG - offset]);
|
||||
|
||||
/* Config is only writable in sleep mode */
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
(void)i2c_write_reg(dev->params.i2c_dev, dev->params.i2c_addr,
|
||||
BMX280_CTRL_MEAS_REG, 0, 0);
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
|
||||
uint8_t b;
|
||||
|
||||
/* Config Register */
|
||||
/* spi3w_en unused */
|
||||
b = ((dev->params.t_sb & 7) << 5) | ((dev->params.filter & 7) << 2);
|
||||
write_u8_reg(dev, BMX280_CONFIG_REG, b);
|
||||
|
||||
#if defined(MODULE_BME280)
|
||||
/*
|
||||
* Note from the datasheet about ctrl_hum: "Changes to this register only become effective
|
||||
* after a write operation to "ctrl_meas".
|
||||
* So, set ctrl_hum first.
|
||||
*/
|
||||
b = dev->params.humid_oversample & 7;
|
||||
write_u8_reg(dev, BME280_CTRL_HUMIDITY_REG, b);
|
||||
#endif
|
||||
|
||||
b = ((dev->params.temp_oversample & 7) << 5) |
|
||||
((dev->params.press_oversample & 7) << 2) |
|
||||
(dev->params.run_mode & 3);
|
||||
write_u8_reg(dev, BMX280_CTRL_MEAS_REG, b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start a measurement and read the registers
|
||||
*/
|
||||
static int do_measurement(const bmx280_t* dev)
|
||||
{
|
||||
/*
|
||||
* If settings has FORCED mode, then the device go to sleep after
|
||||
* it finished the measurement. To read again we have to set the
|
||||
* run_mode back to FORCED.
|
||||
*/
|
||||
uint8_t ctrl_meas = get_ctrl_meas(dev);
|
||||
uint8_t run_mode = ctrl_meas & 3;
|
||||
if (run_mode != dev->params.run_mode) {
|
||||
/* Set the run_mode back to what we want. */
|
||||
ctrl_meas &= ~3;
|
||||
ctrl_meas |= dev->params.run_mode;
|
||||
write_u8_reg(dev, BMX280_CTRL_MEAS_REG, ctrl_meas);
|
||||
|
||||
/* Wait for measurement ready? */
|
||||
size_t count = 0;
|
||||
while (count < 10 && (get_status(dev) & 0x08) != 0) {
|
||||
++count;
|
||||
}
|
||||
/* What to do when measuring is still on? */
|
||||
}
|
||||
int result;
|
||||
int nr_bytes_to_read = sizeof(measurement_regs);
|
||||
uint8_t offset = BMX280_PRESSURE_MSB_REG;
|
||||
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
result = i2c_read_regs(dev->params.i2c_dev, dev->params.i2c_addr,
|
||||
offset, measurement_regs, nr_bytes_to_read, 0);
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
if (result != 0) {
|
||||
LOG_ERROR("Unable to read temperature data\n");
|
||||
return -1;
|
||||
}
|
||||
DUMP_BUFFER("Raw Sensor Data", measurement_regs, nr_bytes_to_read);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t get_ctrl_meas(const bmx280_t* dev)
|
||||
{
|
||||
return read_u8_reg(dev, BMX280_CTRL_MEAS_REG);
|
||||
}
|
||||
|
||||
static uint8_t get_status(const bmx280_t* dev)
|
||||
{
|
||||
return read_u8_reg(dev, BMX280_STAT_REG);
|
||||
}
|
||||
|
||||
static uint8_t read_u8_reg(const bmx280_t* dev, uint8_t reg)
|
||||
{
|
||||
uint8_t b;
|
||||
/* Assuming device is correct, it should return 1 (nr bytes) */
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
(void)i2c_read_reg(dev->params.i2c_dev, dev->params.i2c_addr, reg, &b, 0);
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
return b;
|
||||
}
|
||||
|
||||
static void write_u8_reg(const bmx280_t* dev, uint8_t reg, uint8_t b)
|
||||
{
|
||||
/* Assuming device is correct, it should return 1 (nr bytes) */
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
(void)i2c_write_reg(dev->params.i2c_dev, dev->params.i2c_addr, reg, b, 0);
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
static uint16_t get_uint16_le(const uint8_t *buffer, size_t offset)
|
||||
{
|
||||
return (((uint16_t)buffer[offset + 1]) << 8) + buffer[offset];
|
||||
}
|
||||
|
||||
static int16_t get_int16_le(const uint8_t *buffer, size_t offset)
|
||||
{
|
||||
return (((int16_t)buffer[offset + 1]) << 8) + buffer[offset];
|
||||
}
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
static void dump_buffer(const char *txt, uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t ix;
|
||||
DEBUG("%s\n", txt);
|
||||
for (ix = 0; ix < size; ix++) {
|
||||
DEBUG("%02X", buffer[ix]);
|
||||
if ((ix + 1) == size || (((ix + 1) % 16) == 0)) {
|
||||
DEBUG("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
static int read_temperature(const void *dev, phydat_t *res)
|
||||
{
|
||||
res->val[0] = bmx280_read_temperature((const bmx280_t *)dev);
|
||||
res->val[0] = bmx280_read_temperature((bmx280_t *)dev);
|
||||
res->unit = UNIT_TEMP_C;
|
||||
res->scale = -2;
|
||||
|
||||
@ -42,7 +42,7 @@ static int read_pressure(const void *dev, phydat_t *res)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef MODULE_BME280
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
static int read_relative_humidity(const void *dev, phydat_t *res)
|
||||
{
|
||||
res->val[0] = bme280_read_humidity((const bmx280_t *)dev);
|
||||
@ -65,7 +65,7 @@ const saul_driver_t bmx280_pressure_saul_driver = {
|
||||
.type = SAUL_SENSE_PRESS,
|
||||
};
|
||||
|
||||
#ifdef MODULE_BME280
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
const saul_driver_t bme280_relative_humidity_saul_driver = {
|
||||
.read = read_relative_humidity,
|
||||
.write = saul_notsup,
|
||||
|
@ -25,61 +25,101 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Device specific chip ID
|
||||
* @{
|
||||
*/
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
#define BMX280_CHIP_ID_VAL (0x60)
|
||||
#else
|
||||
#define BMX280_CHIP_ID_VAL (0x58)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name BME280 registers
|
||||
* @{
|
||||
*/
|
||||
#define BME280_CHIP_ID 0x60 /* The identifier of the BME280 */
|
||||
#define BMP280_CHIP_ID 0x58 /* The identifier of the BMP280 */
|
||||
#define BMX280_CHIP_ID_REG 0xD0
|
||||
#define BMEX80_RST_REG 0xE0 /* Softreset Reg */
|
||||
#define BMX280_CHIP_ID_REG (0xD0)
|
||||
#define BMEX80_RST_REG (0xE0) /* Softreset Reg */
|
||||
|
||||
#define BMX280_DIG_T1_LSB_REG 0x88
|
||||
#define BMX280_DIG_T1_MSB_REG 0x89
|
||||
#define BMX280_DIG_T2_LSB_REG 0x8A
|
||||
#define BMX280_DIG_T2_MSB_REG 0x8B
|
||||
#define BMX280_DIG_T3_LSB_REG 0x8C
|
||||
#define BMX280_DIG_T3_MSB_REG 0x8D
|
||||
#define BMX280_DIG_P1_LSB_REG 0x8E
|
||||
#define BMX280_DIG_P1_MSB_REG 0x8F
|
||||
#define BMX280_DIG_P2_LSB_REG 0x90
|
||||
#define BMX280_DIG_P2_MSB_REG 0x91
|
||||
#define BMX280_DIG_P3_LSB_REG 0x92
|
||||
#define BMX280_DIG_P3_MSB_REG 0x93
|
||||
#define BMX280_DIG_P4_LSB_REG 0x94
|
||||
#define BMX280_DIG_P4_MSB_REG 0x95
|
||||
#define BMX280_DIG_P5_LSB_REG 0x96
|
||||
#define BMX280_DIG_P5_MSB_REG 0x97
|
||||
#define BMX280_DIG_P6_LSB_REG 0x98
|
||||
#define BMX280_DIG_P6_MSB_REG 0x99
|
||||
#define BMX280_DIG_P7_LSB_REG 0x9A
|
||||
#define BMX280_DIG_P7_MSB_REG 0x9B
|
||||
#define BMX280_DIG_P8_LSB_REG 0x9C
|
||||
#define BMX280_DIG_P8_MSB_REG 0x9D
|
||||
#define BMX280_DIG_P9_LSB_REG 0x9E
|
||||
#define BMX280_DIG_P9_MSB_REG 0x9F
|
||||
#define BMX280_DIG_T1_LSB_REG (0x88)
|
||||
#define BMX280_DIG_T1_MSB_REG (0x89)
|
||||
#define BMX280_DIG_T2_LSB_REG (0x8A)
|
||||
#define BMX280_DIG_T2_MSB_REG (0x8B)
|
||||
#define BMX280_DIG_T3_LSB_REG (0x8C)
|
||||
#define BMX280_DIG_T3_MSB_REG (0x8D)
|
||||
#define BMX280_DIG_P1_LSB_REG (0x8E)
|
||||
#define BMX280_DIG_P1_MSB_REG (0x8F)
|
||||
#define BMX280_DIG_P2_LSB_REG (0x90)
|
||||
#define BMX280_DIG_P2_MSB_REG (0x91)
|
||||
#define BMX280_DIG_P3_LSB_REG (0x92)
|
||||
#define BMX280_DIG_P3_MSB_REG (0x93)
|
||||
#define BMX280_DIG_P4_LSB_REG (0x94)
|
||||
#define BMX280_DIG_P4_MSB_REG (0x95)
|
||||
#define BMX280_DIG_P5_LSB_REG (0x96)
|
||||
#define BMX280_DIG_P5_MSB_REG (0x97)
|
||||
#define BMX280_DIG_P6_LSB_REG (0x98)
|
||||
#define BMX280_DIG_P6_MSB_REG (0x99)
|
||||
#define BMX280_DIG_P7_LSB_REG (0x9A)
|
||||
#define BMX280_DIG_P7_MSB_REG (0x9B)
|
||||
#define BMX280_DIG_P8_LSB_REG (0x9C)
|
||||
#define BMX280_DIG_P8_MSB_REG (0x9D)
|
||||
#define BMX280_DIG_P9_LSB_REG (0x9E)
|
||||
#define BMX280_DIG_P9_MSB_REG (0x9F)
|
||||
|
||||
#define BME280_DIG_H1_REG 0xA1
|
||||
#define BME280_DIG_H2_LSB_REG 0xE1
|
||||
#define BME280_DIG_H2_MSB_REG 0xE2
|
||||
#define BME280_DIG_H3_REG 0xE3
|
||||
#define BME280_DIG_H4_MSB_REG 0xE4 /* H4[11:4] */
|
||||
#define BME280_DIG_H4_H5_REG 0xE5 /* H5[3:0] H4[3:0] */
|
||||
#define BME280_DIG_H5_MSB_REG 0xE6 /* H5[11:4] */
|
||||
#define BME280_DIG_H6_REG 0xE7
|
||||
#define BME280_DIG_H1_REG (0xA1)
|
||||
#define BME280_DIG_H2_LSB_REG (0xE1)
|
||||
#define BME280_DIG_H2_MSB_REG (0xE2)
|
||||
#define BME280_DIG_H3_REG (0xE3)
|
||||
#define BME280_DIG_H4_MSB_REG (0xE4) /* H4[11:4] */
|
||||
#define BME280_DIG_H4_H5_REG (0xE5) /* H5[3:0] H4[3:0] */
|
||||
#define BME280_DIG_H5_MSB_REG (0xE6) /* H5[11:4] */
|
||||
#define BME280_DIG_H6_REG (0xE7)
|
||||
|
||||
#define BMX280_STAT_REG 0xF3 /* Status Reg */
|
||||
#define BMX280_CTRL_MEAS_REG 0xF4 /* Ctrl Measure Reg */
|
||||
#define BMX280_CONFIG_REG 0xF5 /* Configuration Reg */
|
||||
#define BMX280_PRESSURE_MSB_REG 0xF7 /* Pressure MSB */
|
||||
#define BMX280_PRESSURE_LSB_REG 0xF8 /* Pressure LSB */
|
||||
#define BMX280_PRESSURE_XLSB_REG 0xF9 /* Pressure XLSB */
|
||||
#define BMX280_TEMPERATURE_MSB_REG 0xFA /* Temperature MSB */
|
||||
#define BMX280_TEMPERATURE_LSB_REG 0xFB /* Temperature LSB */
|
||||
#define BMX280_TEMPERATURE_XLSB_REG 0xFC /* Temperature XLSB */
|
||||
#define BME280_CTRL_HUMIDITY_REG 0xF2 /* Ctrl Humidity Reg */
|
||||
#define BME280_HUMIDITY_MSB_REG 0xFD /* Humidity MSB */
|
||||
#define BME280_HUMIDITY_LSB_REG 0xFE /* Humidity LSB */
|
||||
#define BMX280_STAT_REG (0xF3) /* Status Reg */
|
||||
#define BMX280_CTRL_MEAS_REG (0xF4) /* Ctrl Measure Reg */
|
||||
#define BMX280_CONFIG_REG (0xF5) /* Configuration Reg */
|
||||
#define BMX280_PRESSURE_MSB_REG (0xF7) /* Pressure MSB */
|
||||
#define BMX280_PRESSURE_LSB_REG (0xF8) /* Pressure LSB */
|
||||
#define BMX280_PRESSURE_XLSB_REG (0xF9) /* Pressure XLSB */
|
||||
#define BMX280_TEMPERATURE_MSB_REG (0xFA) /* Temperature MSB */
|
||||
#define BMX280_TEMPERATURE_LSB_REG (0xFB) /* Temperature LSB */
|
||||
#define BMX280_TEMPERATURE_XLSB_REG (0xFC) /* Temperature XLSB */
|
||||
#define BME280_CTRL_HUM_REG (0xF2) /* Ctrl Humidity Reg */
|
||||
#define BME280_HUMIDITY_MSB_REG (0xFD) /* Humidity MSB */
|
||||
#define BME280_HUMIDITY_LSB_REG (0xFE) /* Humidity LSB */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Bitmasks for selected registers
|
||||
* @{
|
||||
*/
|
||||
#define MEAS_OSRS_T_POS (5U)
|
||||
#define MEAS_OSRS_P_POS (2U)
|
||||
#define STAT_MEASURING (1 << 3)
|
||||
#define RESET_WORD (0xB6)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name The base address for the row of data registers
|
||||
* @{
|
||||
*/
|
||||
#define DATA_BASE BMX280_PRESSURE_MSB_REG
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Calibration data base addresses, block sizes, and offsets
|
||||
* @{
|
||||
*/
|
||||
#define CALIB_T_P_BASE (BMX280_DIG_T1_LSB_REG)
|
||||
#define CALIB_T_P_LEN (17U)
|
||||
#define OFFSET_T_P(x) (x - CALIB_T_P_BASE)
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
#define CALIB_H_BASE (BME280_DIG_H2_LSB_REG)
|
||||
#define CALIB_H_LEN (7U)
|
||||
#define OFFSET_H(x) (x - CALIB_H_BASE)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kees Bakker, SODAQ
|
||||
* 2017 Inria
|
||||
* 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -16,6 +17,7 @@
|
||||
*
|
||||
* @author Kees Bakker <kees@sodaq.com>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef BMX280_PARAMS_H
|
||||
@ -33,25 +35,54 @@ extern "C" {
|
||||
* @name Set default configuration parameters for the BMX280
|
||||
* @{
|
||||
*/
|
||||
#ifdef BMX280_USE_SPI
|
||||
/* SPI configuration */
|
||||
#ifndef BMX280_PARAM_SPI
|
||||
#define BMX280_PARAM_SPI SPI_DEV(0)
|
||||
#endif
|
||||
#ifndef BMX280_PARAM_CLK
|
||||
#define BMX280_PARAM_CLK SPI_CLK_5MHZ
|
||||
#endif
|
||||
#ifndef BMX280_PARAM_CS
|
||||
#define BMX280_PARAM_CS GPIO_PIN(0, 0)
|
||||
#endif
|
||||
#else
|
||||
/* I2C configuration */
|
||||
#ifndef BMX280_PARAM_I2C_DEV
|
||||
#define BMX280_PARAM_I2C_DEV I2C_DEV(0)
|
||||
#define BMX280_PARAM_I2C_DEV I2C_DEV(0)
|
||||
#endif
|
||||
#ifndef BMX280_PARAM_I2C_ADDR
|
||||
#define BMX280_PARAM_I2C_ADDR (0x77)
|
||||
#define BMX280_PARAM_I2C_ADDR (0x77)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Defaults for Weather Monitoring */
|
||||
#define BMX280_PARAMS_DEFAULT \
|
||||
{ \
|
||||
.i2c_dev = BMX280_PARAM_I2C_DEV, \
|
||||
.i2c_addr = BMX280_PARAM_I2C_ADDR, \
|
||||
.t_sb = BMX280_SB_0_5, \
|
||||
.filter = BMX280_FILTER_OFF, \
|
||||
#define BMX280_PARAM_MISC \
|
||||
.t_sb = BMX280_SB_0_5, \
|
||||
.filter = BMX280_FILTER_OFF, \
|
||||
.run_mode = BMX280_MODE_FORCED, \
|
||||
.temp_oversample = BMX280_OSRS_X1, \
|
||||
.press_oversample = BMX280_OSRS_X1, \
|
||||
.humid_oversample = BMX280_OSRS_X1, \
|
||||
|
||||
/* Defaults for Weather Monitoring */
|
||||
#ifndef BMX280_PARAMS
|
||||
#ifdef BMX280_USE_SPI
|
||||
#define BMX280_PARAMS \
|
||||
{ \
|
||||
.spi = BMX280_PARAM_SPI, \
|
||||
.clk = BMX280_PARAM_CLK, \
|
||||
.cs = BMX280_PARAM_CS, \
|
||||
BMX280_PARAM_MISC \
|
||||
}
|
||||
#else
|
||||
#define BMX280_PARAMS \
|
||||
{ \
|
||||
.i2c_dev = BMX280_PARAM_I2C_DEV, \
|
||||
.i2c_addr = BMX280_PARAM_I2C_ADDR, \
|
||||
BMX280_PARAM_MISC \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
@ -59,11 +90,7 @@ extern "C" {
|
||||
*/
|
||||
static const bmx280_params_t bmx280_params[] =
|
||||
{
|
||||
#ifdef BMX280_PARAMS_BOARD
|
||||
BMX280_PARAMS_BOARD,
|
||||
#else
|
||||
BMX280_PARAMS_DEFAULT
|
||||
#endif
|
||||
BMX280_PARAMS
|
||||
};
|
||||
|
||||
/**
|
||||
@ -80,7 +107,7 @@ static const bmx280_params_t bmx280_params[] =
|
||||
*/
|
||||
static const saul_reg_info_t bmx280_saul_reg_info[BMX280_NUMOF] =
|
||||
{
|
||||
#if defined(MODULE_BME280)
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
{ .name = "bme280" }
|
||||
#else
|
||||
{ .name = "bmp280" }
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kees Bakker, SODAQ
|
||||
* 2017 Inria
|
||||
* 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -8,10 +9,10 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_bmx280 BMP280/BME280 temperature, pressure and humidity sensor
|
||||
* @defgroup drivers_bmx280 BMP280/BME280 temperature, pressure and humidity
|
||||
* sensor
|
||||
* @ingroup drivers_sensors
|
||||
* @ingroup drivers_saul
|
||||
* @brief Device driver interface for the Bosch BMP280 and BME280 sensors.
|
||||
* @brief Device driver interface for the Bosch BMP280 and BME280 sensors
|
||||
*
|
||||
* BMP280 and BME280 measure temperature in centi °C and pressure in Pa. BME280
|
||||
* can also measure relative humidity in %.
|
||||
@ -42,7 +43,7 @@
|
||||
*
|
||||
* @{
|
||||
* @file
|
||||
* @brief Device driver interface for the BMX280 sensors (BMP280 and BME280).
|
||||
* @brief Device driver interface for the BMP280 and BME280 sensors
|
||||
*
|
||||
* @details There are three sensor values that can be read: temperature,
|
||||
* pressure and humidity. The BME280 device usually measures them
|
||||
@ -55,19 +56,35 @@
|
||||
*
|
||||
* @author Kees Bakker <kees@sodaq.com>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef BMX280_H
|
||||
#define BMX280_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include "saul.h"
|
||||
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BMP280_SPI)
|
||||
#define BMX280_USE_SPI
|
||||
#include "periph/spi.h"
|
||||
#else
|
||||
#include "periph/i2c.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Select the number or raw data bytes depending on the device type
|
||||
*/
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
#define BMX280_RAW_LEN (8U)
|
||||
#else
|
||||
#define BMX280_RAW_LEN (6U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Calibration struct for the BMX280 sensor
|
||||
*
|
||||
@ -100,35 +117,34 @@ typedef struct {
|
||||
* @brief Values for t_sb field of the BMX280 config register
|
||||
*/
|
||||
typedef enum {
|
||||
BMX280_SB_0_5 = 0,
|
||||
BMX280_SB_62_5 = 1,
|
||||
BMX280_SB_125 = 2,
|
||||
BMX280_SB_250 = 3,
|
||||
BMX280_SB_500 = 4,
|
||||
BMX280_SB_1000 = 5,
|
||||
BMX280_SB_10 = 6,
|
||||
BMX280_SB_20 = 7
|
||||
BMX280_SB_0_5 = 0x00,
|
||||
BMX280_SB_62_5 = 0x20,
|
||||
BMX280_SB_125 = 0x40,
|
||||
BMX280_SB_250 = 0x60,
|
||||
BMX280_SB_500 = 0x80,
|
||||
BMX280_SB_1000 = 0xa0,
|
||||
BMX280_SB_10 = 0xc0,
|
||||
BMX280_SB_20 = 0xe0,
|
||||
} bmx280_t_sb_t;
|
||||
|
||||
/**
|
||||
* @brief Values for filter field of the BMX280 config register
|
||||
*/
|
||||
typedef enum {
|
||||
BMX280_FILTER_OFF = 0,
|
||||
BMX280_FILTER_2 = 1,
|
||||
BMX280_FILTER_4 = 2,
|
||||
BMX280_FILTER_8 = 3,
|
||||
BMX280_FILTER_16 = 4,
|
||||
BMX280_FILTER_OFF = 0x00,
|
||||
BMX280_FILTER_2 = 0x04,
|
||||
BMX280_FILTER_4 = 0x08,
|
||||
BMX280_FILTER_8 = 0x0c,
|
||||
BMX280_FILTER_16 = 0x10,
|
||||
} bmx280_filter_t;
|
||||
|
||||
/**
|
||||
* @brief Values for mode field of the BMX280 ctrl_meas register
|
||||
*/
|
||||
typedef enum {
|
||||
BMX280_MODE_SLEEP = 0,
|
||||
BMX280_MODE_FORCED = 1,
|
||||
BMX280_MODE_FORCED2 = 2, /* Same as FORCED */
|
||||
BMX280_MODE_NORMAL = 3
|
||||
BMX280_MODE_SLEEP = 0x00,
|
||||
BMX280_MODE_FORCED = 0x01,
|
||||
BMX280_MODE_NORMAL = 0x03,
|
||||
} bmx280_mode_t;
|
||||
|
||||
/**
|
||||
@ -140,12 +156,12 @@ typedef enum {
|
||||
* - osrs_p field of the BMX280 ctrl_meas register
|
||||
*/
|
||||
typedef enum {
|
||||
BMX280_OSRS_SKIPPED = 0,
|
||||
BMX280_OSRS_X1 = 1,
|
||||
BMX280_OSRS_X2 = 2,
|
||||
BMX280_OSRS_X4 = 3,
|
||||
BMX280_OSRS_X8 = 4,
|
||||
BMX280_OSRS_X16 = 5,
|
||||
BMX280_OSRS_SKIPPED = 0x00,
|
||||
BMX280_OSRS_X1 = 0x01,
|
||||
BMX280_OSRS_X2 = 0x02,
|
||||
BMX280_OSRS_X4 = 0x03,
|
||||
BMX280_OSRS_X8 = 0x04,
|
||||
BMX280_OSRS_X16 = 0x05,
|
||||
} bmx280_osrs_t;
|
||||
|
||||
/**
|
||||
@ -154,9 +170,16 @@ typedef enum {
|
||||
* These parameters are needed to configure the device at startup.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifdef BMX280_USE_SPI
|
||||
/* SPI configuration */
|
||||
spi_t spi; /**< SPI bus */
|
||||
spi_clk_t clk; /**< clock speed for the SPI bus */
|
||||
gpio_t cs; /**< chip select pin */
|
||||
#else
|
||||
/* I2C details */
|
||||
i2c_t i2c_dev; /**< I2C device which is used */
|
||||
uint8_t i2c_addr; /**< I2C address */
|
||||
#endif
|
||||
|
||||
/* Config Register */
|
||||
bmx280_t_sb_t t_sb; /**< standby */
|
||||
@ -178,6 +201,8 @@ typedef struct {
|
||||
typedef struct {
|
||||
bmx280_params_t params; /**< Device Parameters */
|
||||
bmx280_calibration_t calibration; /**< Calibration Data */
|
||||
int32_t t_fine; /**< temperature compensation value */
|
||||
uint8_t last_reading[BMX280_RAW_LEN]; /**< cache the RAW data */
|
||||
} bmx280_t;
|
||||
|
||||
/**
|
||||
@ -185,55 +210,85 @@ typedef struct {
|
||||
*/
|
||||
enum {
|
||||
BMX280_OK = 0, /**< everything was fine */
|
||||
BMX280_ERR_NODEV = -1, /**< did not detect BME280 or BMP280 */
|
||||
BMX280_ERR_NOCAL = -2, /**< could not read calibration data */
|
||||
BMX280_ERR_BUS = -1, /**< bus error */
|
||||
BMX280_ERR_NODEV = -2, /**< did not detect BME280 or BMP280 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Export of SAUL interface for temperature sensor
|
||||
*/
|
||||
extern const saul_driver_t bmx280_temperature_saul_driver;
|
||||
|
||||
/**
|
||||
* @brief Export of SAUL interface for pressure sensor
|
||||
*/
|
||||
extern const saul_driver_t bmx280_pressure_saul_driver;
|
||||
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
/**
|
||||
* @brief Export of SAUL interface for humidity sensor
|
||||
*/
|
||||
extern const saul_driver_t bme280_relative_humidity_saul_driver;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize the given BMX280 device
|
||||
*
|
||||
* @param[out] dev Initialized device descriptor of BMX280 device
|
||||
* @param[in] params The parameters for the BMX280 device (sampling rate, etc)
|
||||
* @param[out] dev device descriptor of the given BMX280 device
|
||||
* @param[in] params static configuration parameters
|
||||
*
|
||||
* @return BMX280_OK on success
|
||||
* @return BMX280_ERR_I2C
|
||||
* @return BMX280_ERR_NODEV
|
||||
* @return BMX280_ERR_NOCAL
|
||||
* @return BMX280_OK on success
|
||||
* @return BMX280_ERR_BUS on bus error
|
||||
* @return BMX280_ERR_NODEV if no corresponding device was found on the bus
|
||||
*/
|
||||
int bmx280_init(bmx280_t* dev, const bmx280_params_t* params);
|
||||
|
||||
/**
|
||||
* @brief Read temperature value from the given BMX280 device, returned in centi °C
|
||||
* @brief Read temperature value from the given BMX280 device
|
||||
*
|
||||
* @param[in] dev Device descriptor of BMX280 device to read from
|
||||
* The measured temperature is returned in centi °C (x.xx°C).
|
||||
*
|
||||
* @returns The temperature in centi Celsius. In case of an error
|
||||
* it returns INT16_MIN.
|
||||
* @param[in] dev device to read from
|
||||
*
|
||||
* @return measured temperature in centi Celsius
|
||||
* @return INT16_MIN on error
|
||||
*/
|
||||
int16_t bmx280_read_temperature(const bmx280_t* dev);
|
||||
int16_t bmx280_read_temperature(bmx280_t* dev);
|
||||
|
||||
/**
|
||||
* @brief Read air pressure value from the given BMX280 device, returned in PA
|
||||
* @brief Read air pressure value from the given BMX280 device
|
||||
*
|
||||
* @details This function should only be called after doing bmx280_read_temperature
|
||||
* first.
|
||||
* The air pressure is returned in PA (Pascal).
|
||||
*
|
||||
* @param[in] dev Device descriptor of BMX280 device to read from
|
||||
* This function returns the pressure data that was measured when
|
||||
* bmx280_read_temperature() has been called last. So bmx280_read_temperature()
|
||||
* has to be called before.
|
||||
*
|
||||
* @returns The air pressure in Pa
|
||||
* If bmx280_read_temperatue() did not succeed in acquiring a new set of sensor
|
||||
* data, the result of this function is undefined.
|
||||
*
|
||||
* @param[in] dev device to read from
|
||||
*
|
||||
* @return air pressure in PA
|
||||
*/
|
||||
uint32_t bmx280_read_pressure(const bmx280_t *dev);
|
||||
|
||||
#if defined(MODULE_BME280) || defined(DOXYGEN)
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief Read humidity value from the given BME280 device, returned in centi %RH
|
||||
* @brief Read humidity value from the given BME280 device
|
||||
*
|
||||
* @details This function should only be called after doing bmx280_read_temperature
|
||||
* first. It's only available with BME280 sensor.
|
||||
* The humidity is returned in centi %RH (x.xx% relative humidity).
|
||||
*
|
||||
* @param[in] dev Device descriptor of BME280 device to read from
|
||||
* This function returns the pressure data that was measured when
|
||||
* bmx280_read_temperature() has been called last. So bmx280_read_temperature()
|
||||
* has to be called before.
|
||||
*
|
||||
* @returns Humidity in centi %RH (i.e. the percentage times 100)
|
||||
* If bmx280_read_temperatue() did not succeed in acquiring a new set of sensor
|
||||
* data, the result of this function is undefined.
|
||||
*
|
||||
* @param[in] dev device to read from
|
||||
*
|
||||
* @return humidity in centi %RH (i.e. the percentage times 100)
|
||||
*/
|
||||
uint16_t bme280_read_humidity(const bmx280_t *dev);
|
||||
#endif
|
||||
|
@ -102,8 +102,10 @@ PSEUDOMODULES += at86rfa1
|
||||
PSEUDOMODULES += at86rfr2
|
||||
|
||||
# include variants of the BMX280 drivers as pseudo modules
|
||||
PSEUDOMODULES += bmp280
|
||||
PSEUDOMODULES += bme280
|
||||
PSEUDOMODULES += bmp280_i2c
|
||||
PSEUDOMODULES += bmp280_spi
|
||||
PSEUDOMODULES += bme280_i2c
|
||||
PSEUDOMODULES += bme280_spi
|
||||
|
||||
# variants of TI ADCXX1C
|
||||
PSEUDOMODULES += adc081c
|
||||
|
@ -382,7 +382,7 @@ void auto_init(void)
|
||||
extern void auto_init_bmp180(void);
|
||||
auto_init_bmp180();
|
||||
#endif
|
||||
#if defined(MODULE_BME280) || defined(MODULE_BMP280)
|
||||
#ifdef MODULE_BMX280
|
||||
extern void auto_init_bmx280(void);
|
||||
auto_init_bmx280();
|
||||
#endif
|
||||
|
@ -20,7 +20,7 @@
|
||||
* @}
|
||||
*/
|
||||
|
||||
#if defined(MODULE_BME280) || defined(MODULE_BMP280)
|
||||
#ifdef MODULE_BMX280
|
||||
|
||||
#include "log.h"
|
||||
#include "saul_reg.h"
|
||||
@ -33,21 +33,10 @@
|
||||
*/
|
||||
static bmx280_t bmx280_devs[BMX280_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief Reference the driver structs.
|
||||
* @{
|
||||
*/
|
||||
extern const saul_driver_t bmx280_temperature_saul_driver;
|
||||
extern const saul_driver_t bmx280_pressure_saul_driver;
|
||||
#if defined(MODULE_BME280)
|
||||
extern const saul_driver_t bme280_relative_humidity_saul_driver;
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Memory for the SAUL registry entries
|
||||
*/
|
||||
#if defined(MODULE_BME280)
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
#define SENSORS_NUMOF 3
|
||||
#else
|
||||
#define SENSORS_NUMOF 2
|
||||
@ -79,7 +68,7 @@ void auto_init_bmx280(void)
|
||||
saul_reg_add(&saul_entries[se_ix]);
|
||||
se_ix++;
|
||||
|
||||
#if defined(MODULE_BME280)
|
||||
#if defined(MODULE_BME280_SPI) || defined(MODULE_BME280_I2C)
|
||||
/* relative humidity */
|
||||
saul_entries[se_ix].dev = &bmx280_devs[i];
|
||||
saul_entries[se_ix].name = bmx280_saul_reg_info[i].name;
|
||||
|
Loading…
Reference in New Issue
Block a user