nuttx/drivers/sensors/bme680.c
Petro Karashchenko 1651bb476c c89: move variable declaration out from the for loop
Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
2023-08-08 11:58:29 -03:00

1759 lines
44 KiB
C

/****************************************************************************
* drivers/sensors/bme680.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/nuttx.h>
#include <stdio.h>
#include <stdlib.h>
#include <fixedmath.h>
#include <errno.h>
#include <debug.h>
#include <string.h>
#include <nuttx/kmalloc.h>
#include <nuttx/kthread.h>
#include <nuttx/signal.h>
#include <nuttx/fs/fs.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/sensors/bme680.h>
#include <nuttx/sensors/sensor.h>
#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_BME680)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define BME680_ADDR 0x76 /* I2C Slave Address */
#define BME680_FREQ CONFIG_BME680_I2C_FREQUENCY
#define BME680_DEVID 0x61
/* Sub-sensor definitions */
#ifdef CONFIG_BME680_DISABLE_PRESS_MEAS
# define BME680_TEMP_IDX (0)
#else
# define BME680_TEMP_IDX (-1)
#endif
#define BME680_TEMP_IDX_OFF BME680_TEMP_IDX
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
# define BME680_PRESS_IDX (BME680_TEMP_IDX_OFF + (1))
# define BME680_PRESS_IDX_OFF BME680_PRESS_IDX
#else
# define BME680_PRESS_IDX (-1)
# define BME680_PRESS_IDX_OFF BME680_TEMP_IDX_OFF
#endif
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
# define BME680_HUM_IDX (BME680_PRESS_IDX_OFF + (1))
# define BME680_HUM_IDX_OFF BME680_HUM_IDX
#else
# define BME680_HUM_IDX (-1)
# define BME680_HUM_IDX_OFF BME680_PRESS_IDX_OFF
#endif
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
# define BME680_GAS_IDX (BME680_HUM_IDX_OFF + (1))
# define BME680_GAS_IDX_OFF BME680_GAS_IDX
#else
# define BME680_GAS_IDX (-1)
# define BME680_GAS_IDX_OFF BME680_HUM_IDX_OFF
#endif
#define BME680_SENSORS_COUNT (BME680_GAS_IDX_OFF + (1))
/* Register addresses */
#define BME680_STATUS_REG_ADDR 0X73
#define BME680_RESET_REG_ADDR 0xE0
#define BME680_ID_REG_ADDR 0xD0
/* Registers controlling oversampling */
#define BME680_CTRL_HUM_ADDR 0x72
#define BME680_CTRL_MEAS_ADDR 0x74
#define BME680_CONFIG_REG_ADDR 0x75
/* Gas control register */
#define BME680_CTRL_GAS0 0x70
#define BME680_CTRL_GAS1 0x71
/* Data registers */
/* Pressure data */
#define BME680_PRESS_MSB 0x1F
#define BME680_PRESS_LSB 0x20
#define BME680_PRESS_XLSB 0x21
/* Temperature data */
#define BME680_TEMP_MSB 0x22
#define BME680_TEMP_LSB 0x23
#define BME680_TEMP_XLSB 0x24
/* Humidity data */
#define BME680_HUM_MSB 0x25
#define BME680_HUM_LSB 0x26
/* Gas sensor resistance data */
#define BME680_GAS_R_MSB 0x2A
#define BME680_GAS_R_LSB 0x2B
#define BME680_IDAC_HEAT_ADDR 0x50
#define BME680_RES_HEAT_ADDR 0x5A
#define BME680_GAS_WAIT_ADDR 0x64
/* Status registers */
#define BME680_MEAS_STAT0 0x1D
/* nbconv boundaries */
#define BME680_NBCONV_MIN (0)
#define BME680_NBCONV_MAX (9)
/* Power modes */
#define BME680_SLEEP_MODE (0x00)
#define BME680_FORCED_MODE (0x01)
/* Soft reset, same effect as a power-on reset */
#define BME680_SOFT_RESET (0xB6)
/* Start addresses for coefficient arrays */
#define BME680_COEFF_ADDR1 (0x89)
#define BME680_COEFF_ADDR2 (0xE1)
#define BME680_COEFF_SIZE (41)
#define BME680_COEFF_ADDR1_LEN (25)
#define BME680_COEFF_ADDR2_LEN (16)
/* Start address for measurements and status regs */
#define BME680_DATA_ADDR (0x1D)
#define BME680_DATA_LEN (15)
/* Gas coefficients */
#define BME680_RES_HEAT_RANGE_ADDR (0x02)
#define BME680_RES_HEAT_VAL_ADDR (0x00)
#define BME680_RANGE_SW_ERR_ADDR (0x04)
/* Array index for mapping calibration data */
#define BME680_T2_LSB_REG (1)
#define BME680_T2_MSB_REG (2)
#define BME680_T3_REG (3)
#define BME680_P1_LSB_REG (5)
#define BME680_P1_MSB_REG (6)
#define BME680_P2_LSB_REG (7)
#define BME680_P2_MSB_REG (8)
#define BME680_P3_REG (9)
#define BME680_P4_LSB_REG (11)
#define BME680_P4_MSB_REG (12)
#define BME680_P5_LSB_REG (13)
#define BME680_P5_MSB_REG (14)
#define BME680_P7_REG (15)
#define BME680_P6_REG (16)
#define BME680_P8_LSB_REG (19)
#define BME680_P8_MSB_REG (20)
#define BME680_P9_LSB_REG (21)
#define BME680_P9_MSB_REG (22)
#define BME680_P10_REG (23)
#define BME680_H2_MSB_REG (25)
#define BME680_H2_LSB_REG (26)
#define BME680_H1_LSB_REG (26)
#define BME680_H1_MSB_REG (27)
#define BME680_H3_REG (28)
#define BME680_H4_REG (29)
#define BME680_H5_REG (30)
#define BME680_H6_REG (31)
#define BME680_H7_REG (32)
#define BME680_T1_LSB_REG (33)
#define BME680_T1_MSB_REG (34)
#define BME680_GH2_LSB_REG (35)
#define BME680_GH2_MSB_REG (36)
#define BME680_GH1_REG (37)
#define BME680_GH3_REG (38)
/* Masks for register values */
#define BME680_GAS_MEAS_MSK (0x30)
#define BME680_NBCONV_MSK (0X0F)
#define BME680_FILTER_MSK (0X1C)
#define BME680_OST_MSK (0XE0)
#define BME680_OSP_MSK (0X1C)
#define BME680_OSH_MSK (0X07)
#define BME680_HCTRL_MSK (0x08)
#define BME680_RUN_GAS_MSK (0x10)
#define BME680_MODE_MSK (0x03)
#define BME680_RHRANGE_MSK (0x30)
#define BME680_RSERROR_MSK (0xF0)
#define BME680_NEW_DATA_MSK (0x80)
#define BME680_GAS_INDEX_MSK (0x0F)
#define BME680_GAS_RANGE_MSK (0x0F)
#define BME680_GASM_VALID_MSK (0x20)
#define BME680_HEAT_STAB_MSK (0x10)
#define BME680_MEM_PAGE_MSK (0x10)
#define BME680_BIT_H1_DATA_MSK (0x0F)
/* Bounds for tpg */
#define MIN_HOT_PLATE_TEMP (200) /* Celsius */
#define MAX_HOT_PLATE_TEMP (400) /* Celsius */
#define BME680_MAX_OVERFLOW_VAL (0x40000000ULL)
/* Possible gas range values */
const uint32_t const_array1_int[16] =
{
2147483647, 2147483647, 2147483647, 2147483647,
2147483647, 2126008810, 2147483647, 2130303777,
2147483647, 2147483647, 2143188679, 2136746228,
2147483647, 2126008810, 2147483647, 2147483647
};
const uint32_t const_array2_int[16] =
{
4096000000, 2048000000, 1024000000, 512000000,
255744255, 127110228, 64000000, 32258064, 16016016,
8000000, 4000000, 2000000, 1000000, 500000,
250000, 125000
};
const float const_array1[16] =
{
1.0, 1.0, 1.0, 1.0, 1.0, 0.99, 1.0, 0.992, 1.0, 1.0,
0.998, 0.995, 1.0, 0.99, 1.0, 1.0
};
const float const_array2[16] =
{
8000000.0, 4000000.0, 2000000.0, 1000000.0, 499500.4995,
248262.1648, 125000.0, 63004.03226, 31281.28128, 15625.0,
7812.5, 3906.25, 1953.125, 976.5625, 488.28125, 244.140625
};
#define CHECK_OS_BOUNDS(type) \
((type) >= BME680_OS_SKIPPED && (type) <= BME680_OS_16X)
/****************************************************************************
* Private Type Definitions
****************************************************************************/
struct bme680_data_s
{
uint64_t timestamp; /* Units is microseconds */
float temperature; /* Temperature in degrees Celsius */
float pressure; /* Pressure in millibar or hPa */
float humidity; /* Relative humidity in rH */
float gas_resistance; /* Gas resistance in Ohm */
};
struct bme680_calib_s
{
/* Temperature coefficients */
uint16_t t1;
int16_t t2;
int8_t t3;
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
/* Pressure coefficients */
uint16_t p1;
int16_t p2;
int8_t p3;
int16_t p4;
int16_t p5;
int8_t p6;
int8_t p7;
int16_t p8;
int16_t p9;
uint8_t p10;
#endif /* !CONFIG_BME680_DISABLE_PRESS_MEAS */
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
/* Humidity coefficients */
uint16_t h1;
uint16_t h2;
int8_t h3;
int8_t h4;
int8_t h5;
uint8_t h6;
int8_t h7;
#endif /* !CONFIG_BME680_DISABLE_PRESS_MEAS */
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
/* Gas heater coefficients */
int8_t gh1;
int16_t gh2;
int8_t gh3;
uint8_t res_heat_range; /* Heater resistance range */
int8_t res_heat_val; /* Heater resistance value */
int8_t range_sw_err; /* Error switching range */
#endif /* !CONFIG_BME680_DISABLE_GAS_MEAS */
int32_t t_fine;
};
struct bme680_sensor_s
{
/* Lowerhalfs for every sub-sensor */
struct sensor_lowerhalf_s lower[BME680_SENSORS_COUNT];
struct bme680_calib_s calib; /* Calibration data */
struct bme680_config_s config; /* Configuration data */
bool calibrated; /* Is the device set up? */
};
struct bme680_dev_s
{
struct bme680_sensor_s dev; /* Sensor private data */
FAR struct i2c_master_s *i2c; /* I2C interface */
mutex_t dev_lock; /* Manages exclusive access to the device */
sem_t run; /* Locks sensor thread */
bool enabled; /* Enable/Disable BME680 */
};
typedef int (*push_data_func)(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data);
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static uint8_t bme680_getreg8(FAR struct bme680_dev_s *priv,
uint8_t regaddr);
static int bme680_putreg8(FAR struct bme680_dev_s *priv, uint8_t regaddr,
uint8_t regval);
static int bme680_getregs(FAR struct bme680_dev_s *priv, uint8_t regaddr,
uint8_t *rxbuffer, uint8_t length);
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
static int bme680_push_press_data(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data);
#else
static int bme680_push_temp_data(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data);
#endif
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
static int bme680_push_hum_data(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data);
#endif
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
static int bme680_push_gas_data(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data);
#endif
/* Sensor methods */
static int bme680_activate(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
bool enable);
static int bme680_calibrate(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
unsigned long arg);
static int bme680_control(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
int cmd, unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
static const push_data_func deliver_data[BME680_SENSORS_COUNT] =
{
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
bme680_push_press_data
#else
bme680_push_temp_data
#endif
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
, bme680_push_hum_data
#endif
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
, bme680_push_gas_data
#endif
};
static const struct sensor_ops_s g_sensor_ops =
{
NULL, /* open */
NULL, /* close */
bme680_activate, /* activate */
NULL, /* set_interval */
NULL, /* batch */
NULL, /* fetch */
NULL, /* selftest */
NULL, /* set_calibvalue */
bme680_calibrate, /* calibrate */
bme680_control /* control */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: bme680_getreg8
*
* Description:
* Read from an 8-bit BME680 register
*
****************************************************************************/
static uint8_t bme680_getreg8(FAR struct bme680_dev_s *priv, uint8_t regaddr)
{
struct i2c_msg_s msg[2];
uint8_t regval = 0;
int ret;
msg[0].frequency = BME680_FREQ;
msg[0].addr = BME680_ADDR;
msg[0].flags = 0;
msg[0].buffer = &regaddr;
msg[0].length = 1;
msg[1].frequency = BME680_FREQ;
msg[1].addr = BME680_ADDR;
msg[1].flags = I2C_M_READ;
msg[1].buffer = &regval;
msg[1].length = 1;
ret = I2C_TRANSFER(priv->i2c, msg, 2);
if (ret < 0)
{
snerr("I2C_TRANSFER failed: %d\n", ret);
return 0;
}
return regval;
}
/****************************************************************************
* Name: bme680_getregs
*
* Description:
* Read <length> bytes starting from a BME680 register addr
*
****************************************************************************/
static int bme680_getregs(FAR struct bme680_dev_s *priv, uint8_t regaddr,
uint8_t *rxbuffer, uint8_t length)
{
struct i2c_msg_s msg[2];
int ret;
msg[0].frequency = BME680_FREQ;
msg[0].addr = BME680_ADDR;
msg[0].flags = 0;
msg[0].buffer = &regaddr;
msg[0].length = 1;
msg[1].frequency = BME680_FREQ;
msg[1].addr = BME680_ADDR;
msg[1].flags = I2C_M_READ;
msg[1].buffer = rxbuffer;
msg[1].length = length;
ret = I2C_TRANSFER(priv->i2c, msg, 2);
if (ret < 0)
{
snerr("I2C_TRANSFER failed: %d\n", ret);
return -1;
}
return OK;
}
/****************************************************************************
* Name: bme680_putreg8
*
* Description:
* Write to an 8-bit BME680 register
*
****************************************************************************/
static int bme680_putreg8(FAR struct bme680_dev_s *priv, uint8_t regaddr,
uint8_t regval)
{
struct i2c_msg_s msg[2];
uint8_t txbuffer[2];
int ret;
txbuffer[0] = regaddr;
txbuffer[1] = regval;
msg[0].frequency = BME680_FREQ;
msg[0].addr = BME680_ADDR;
msg[0].flags = 0;
msg[0].buffer = txbuffer;
msg[0].length = 2;
ret = I2C_TRANSFER(priv->i2c, msg, 1);
if (ret < 0)
{
snerr("I2C_TRANSFER failed: %d\n", ret);
}
return ret;
}
/****************************************************************************
* Name: bme680_checkid
*
* Description:
* Read and verify the BME680 chip ID
*
****************************************************************************/
static int bme680_checkid(FAR struct bme680_dev_s *priv)
{
uint8_t devid = 0;
/* Read device ID */
devid = bme680_getreg8(priv, BME680_ID_REG_ADDR);
up_mdelay(1);
sninfo("devid: 0x%02x\n", devid);
if (devid != (uint8_t)BME680_DEVID)
{
/* ID is not Correct */
snerr("Wrong Device ID! %02x\n", devid);
return -ENODEV;
}
return OK;
}
/****************************************************************************
* Name: bme680_get_calib_data
*
* Description:
* Read sensor-specific parameters and store them for later
* use in computing the compensated values.
*
****************************************************************************/
static int bme680_get_calib_data(FAR struct bme680_dev_s *priv)
{
uint8_t coeff[BME680_COEFF_SIZE];
uint8_t temp_val;
int ret;
/* Get first part of the calibration data. */
ret = bme680_getregs(priv, BME680_COEFF_ADDR1, coeff,
BME680_COEFF_ADDR1_LEN);
if (ret < 0)
{
return ret;
}
/* Concatenate the second part of the data to coeff */
ret = bme680_getregs(priv, BME680_COEFF_ADDR2,
&coeff[BME680_COEFF_ADDR1_LEN],
BME680_COEFF_ADDR2_LEN);
if (ret < 0)
{
return ret;
}
/* Get data */
priv->dev.calib.t1 = coeff[BME680_T1_MSB_REG] << 8
| coeff[BME680_T1_LSB_REG];
priv->dev.calib.t2 = coeff[BME680_T2_MSB_REG] << 8
| coeff[BME680_T2_LSB_REG];
priv->dev.calib.t3 = coeff[BME680_T3_REG];
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
priv->dev.calib.p1 = coeff[BME680_P1_MSB_REG] << 8
| coeff[BME680_P1_LSB_REG];
priv->dev.calib.p2 = coeff[BME680_P2_MSB_REG] << 8
| coeff[BME680_P2_LSB_REG];
priv->dev.calib.p3 = coeff[BME680_P3_REG];
priv->dev.calib.p4 = coeff[BME680_P4_MSB_REG] << 8
| coeff[BME680_P4_LSB_REG];
priv->dev.calib.p5 = coeff[BME680_P5_MSB_REG] << 8
| coeff[BME680_P5_LSB_REG];
priv->dev.calib.p6 = coeff[BME680_P6_REG];
priv->dev.calib.p7 = coeff[BME680_P7_REG];
priv->dev.calib.p8 = coeff[BME680_P8_MSB_REG] << 8
| coeff[BME680_P8_LSB_REG];
priv->dev.calib.p9 = coeff[BME680_P9_MSB_REG] << 8
| coeff[BME680_P9_LSB_REG];
priv->dev.calib.p10 = coeff[BME680_P10_REG];
#endif /* !CONFIG_BME680_DISABLE_PRESS_MEAS */
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
priv->dev.calib.h1 = (uint16_t)(((uint16_t)coeff[BME680_H1_MSB_REG] << 4)
| (coeff[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK));
priv->dev.calib.h2 = (uint16_t)(((uint16_t)coeff[BME680_H2_MSB_REG] << 4)
| ((coeff[BME680_H2_LSB_REG]) >> 4));
priv->dev.calib.h3 = coeff[BME680_H3_REG];
priv->dev.calib.h4 = coeff[BME680_H4_REG];
priv->dev.calib.h5 = coeff[BME680_H5_REG];
priv->dev.calib.h6 = coeff[BME680_H6_REG];
priv->dev.calib.h7 = coeff[BME680_H7_REG];
#endif /* !CONFIG_BME680_DISABLE_HUM_MEAS */
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
/* Gas-related coefficients */
priv->dev.calib.gh1 = coeff[BME680_GH1_REG];
priv->dev.calib.gh2 = coeff[BME680_GH2_MSB_REG] << 8
| coeff[BME680_GH2_LSB_REG];
priv->dev.calib.gh3 = coeff[BME680_GH3_REG];
ret = bme680_getregs(priv, BME680_RES_HEAT_RANGE_ADDR, &temp_val, 1);
if (ret < 0)
{
return ret;
}
priv->dev.calib.res_heat_range = ((temp_val & BME680_RHRANGE_MSK)) / 16;
ret = bme680_getregs(priv, BME680_RES_HEAT_VAL_ADDR, &temp_val, 1);
if (ret < 0)
{
return ret;
}
priv->dev.calib.res_heat_val = (int8_t)temp_val;
ret = bme680_getregs(priv, BME680_RANGE_SW_ERR_ADDR, &temp_val, 1);
if (ret < 0)
{
return ret;
}
priv->dev.calib.range_sw_err = ((int8_t)temp_val
& (int8_t)BME680_RSERROR_MSK) / 16;
#endif /* !CONFIG_BME680_DISABLE_GAS_MEAS */
return ret;
}
/****************************************************************************
* Name: bme680_set_mode
*
* Description:
* Set sensor mode and wait for it to change accordingly.
*
****************************************************************************/
static int bme680_set_mode(FAR struct bme680_dev_s *priv, uint8_t mode)
{
int ret;
uint8_t power_mode;
uint8_t regval;
/* Get current sensor mode */
ret = bme680_getregs(priv, BME680_CTRL_MEAS_ADDR, &regval, 1);
if (ret < 0)
{
return ret;
}
power_mode = regval & BME680_MODE_MSK;
if (power_mode != mode)
{
regval &= (uint8_t)(~BME680_MODE_MSK);
regval |= (mode & BME680_MODE_MSK);
ret = bme680_putreg8(priv, BME680_CTRL_MEAS_ADDR, regval);
if (ret < 0)
{
return ret;
}
ret = bme680_getregs(priv, BME680_CTRL_MEAS_ADDR, &regval, 1);
/* Check if the mode has changed and wait if it hasn't */
while ((regval & BME680_MODE_MSK) != mode)
{
up_mdelay(100);
ret = bme680_getregs(priv, BME680_CTRL_MEAS_ADDR, &regval, 1);
}
}
return OK;
}
/****************************************************************************
* Name: bme680_set_oversamp
*
* Description:
* Set temperature, pressure and humidity oversampling.
*
****************************************************************************/
static int bme680_set_oversamp(FAR struct bme680_dev_s *priv)
{
struct bme680_config_s config = priv->dev.config;
int ret;
uint8_t regval;
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
/* Set humidity oversampling */
regval = config.hum_os & BME680_OSH_MSK;
ret = bme680_putreg8(priv, BME680_CTRL_HUM_ADDR, regval);
#endif
/* Set temperature and pressure oversampling */
regval = 0;
ret = bme680_getregs(priv, BME680_CTRL_MEAS_ADDR, &regval, 1);
if (ret < 0)
{
return ret;
}
regval &= BME680_MODE_MSK;
regval |= ((config.temp_os << 5) & BME680_OST_MSK);
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
regval |= ((config.press_os << 2) & BME680_OSP_MSK);
#endif
ret = bme680_putreg8(priv, BME680_CTRL_MEAS_ADDR, regval);
if (ret < 0)
{
return ret;
}
return OK;
}
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
static int bme680_push_press_data(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data)
{
struct sensor_baro press_data;
int ret;
struct sensor_lowerhalf_s lower = priv->dev.lower[BME680_PRESS_IDX];
press_data.timestamp = data->timestamp;
press_data.temperature = data->temperature;
press_data.pressure = data->pressure / 100.f;
ret = lower.push_event(lower.priv, &press_data,
sizeof(struct sensor_baro));
if (ret < 0)
{
snerr("Pushing baro data failed\n");
return ret;
}
return OK;
}
#else
static int bme680_push_temp_data(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data)
{
struct sensor_temp temp_data;
int ret;
struct sensor_lowerhalf_s lower = priv->dev.lower[BME680_TEMP_IDX];
temp_data.timestamp = data->timestamp;
temp_data.temperature = data->temperature;
ret = lower.push_event(lower.priv, &temp_data, sizeof(struct sensor_temp));
if (ret < 0)
{
snerr("Pushing temperature data failed\n");
return ret;
}
return OK;
}
#endif /* !CONFIG_BME680_DISABLE_PRESS_MEAS */
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
static int bme680_push_hum_data(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data)
{
struct sensor_humi hum_data;
int ret;
struct sensor_lowerhalf_s lower = priv->dev.lower[BME680_HUM_IDX];
hum_data.timestamp = data->timestamp;
hum_data.humidity = data->humidity;
ret = lower.push_event(lower.priv, &hum_data, sizeof(struct sensor_humi));
if (ret < 0)
{
snerr("Pushing humidity data failed\n");
return ret;
}
return OK;
}
#endif /* !CONFIG_BME680_DISABLE_HUM_MEAS */
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
static int bme680_push_gas_data(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data)
{
struct sensor_gas gas_data;
int ret;
struct sensor_lowerhalf_s lower = priv->dev.lower[BME680_GAS_IDX];
gas_data.timestamp = data->timestamp;
gas_data.gas_resistance = data->gas_resistance / 1000.f;
ret = lower.push_event(lower.priv, &gas_data, sizeof(struct sensor_gas));
if (ret < 0)
{
snerr("Pushing gas data failed\n");
return ret;
}
return OK;
}
/****************************************************************************
* Name: calc_heater_res
*
* Description:
* Compute the heater resistance using the target temperature.
*
****************************************************************************/
static uint8_t calc_heater_res(FAR const struct bme680_dev_s *priv)
{
uint8_t res_heat;
int32_t var1;
int32_t var2;
int32_t var3;
int32_t var4;
int32_t var5;
int32_t res_heat_x100;
int16_t temp;
int16_t amb_temp;
struct bme680_sensor_s dev = priv->dev;
temp = dev.config.target_temp;
if (temp > 400)
{
temp = 400;
}
amb_temp = dev.config.amb_temp;
var1 = (((int32_t)amb_temp * dev.calib.gh3) / 10) * 256;
var2 = (dev.calib.gh1 + 784) * (((((dev.calib.gh2 + 154009)
* temp * 5) / 100) + 3276800) / 10);
var3 = var1 + (var2 / 2);
var4 = (var3 / (dev.calib.res_heat_range + 4));
var5 = (131 * dev.calib.res_heat_val) + 65536;
res_heat_x100 = (int32_t)(((var4 / var5) - 250) * 34);
res_heat = (uint8_t)((res_heat_x100 + 50) / 100);
return res_heat;
}
/****************************************************************************
* Name: calc_heater_dur
*
* Description:
* Compute the heater duration to be written to heat_dur register.
*
****************************************************************************/
static uint8_t calc_heater_dur(FAR const struct bme680_dev_s *priv)
{
uint16_t heat_dur = priv->dev.config.heater_duration;
uint8_t gas_wait_val;
uint8_t factor;
/* Max value of duration is 4032 ms */
if (heat_dur > 0xfc0)
{
heat_dur = 0xfc0;
}
/* Compute multiplication factor */
factor = 0;
while (heat_dur > 0x3f)
{
heat_dur = heat_dur / 4;
factor++;
}
gas_wait_val = (factor << 6) | heat_dur;
return gas_wait_val;
}
static int bme680_set_gas_config(FAR struct bme680_dev_s *priv)
{
int ret;
uint8_t heat_res;
uint8_t heat_dur;
uint8_t run_gas;
uint8_t regval;
uint8_t nb_conv = priv->dev.config.nb_conv;
/* Set heater resistance */
heat_res = calc_heater_res(priv);
ret = bme680_putreg8(priv, (BME680_RES_HEAT_ADDR + nb_conv), heat_res);
if (ret < 0)
{
return ret;
}
/* Set heater duration */
heat_dur = calc_heater_dur(priv);
ret = bme680_putreg8(priv, (BME680_GAS_WAIT_ADDR + nb_conv), heat_dur);
if (ret < 0)
{
return ret;
}
/* Set nbconv and run_gas */
run_gas = priv->dev.config.target_temp ? 1 : 0;
regval = (run_gas << 4) | nb_conv;
ret = bme680_putreg8(priv, BME680_CTRL_GAS1, regval);
if (ret < 0)
{
return ret;
}
return OK;
}
#endif /* !CONFIG_BME680_DISABLE_GAS_MEAS */
/****************************************************************************
* Name: bme680_write_config
*
* Description:
* Write the configuration of the sensor into its registers
* (oversampling, heater temp, heater duration, etc).
*
****************************************************************************/
static int bme680_write_config(FAR struct bme680_dev_s *priv)
{
int ret;
#ifdef CONFIG_BME680_ENABLE_IIR_FILTER
uint8_t regval;
#endif /* CONFIG_BME680_ENABLE_IIR_FILTER */
nxmutex_lock(&priv->dev_lock);
/* Before anything is written, make sure it is in sleep mode */
ret = bme680_set_mode(priv, BME680_SLEEP_MODE);
if (ret < 0)
{
goto err_out;
}
/* Set oversampling */
ret = bme680_set_oversamp(priv);
if (ret < 0)
{
goto err_out;
}
#ifdef CONFIG_BME680_ENABLE_IIR_FILTER
/* Set filter */
regval = priv->dev.config.filter_coef << 2;
ret = bme680_putreg8(priv, BME680_CONFIG_REG_ADDR, regval);
if (ret < 0)
{
goto err_out;
}
#endif /* CONFIG_ENABLE_IIR_FILTER */
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
/* Set gas configs */
ret = bme680_set_gas_config(priv);
if (ret < 0)
{
goto err_out;
}
#endif /* !CONFIG_BME680_DISABLE_GAS_MEAS */
nxmutex_unlock(&priv->dev_lock);
return OK;
err_out:
snerr("Failed to calibrate sensor.\n");
nxmutex_unlock(&priv->dev_lock);
return ret;
}
static float bme680_comp_temp(FAR struct bme680_dev_s *priv,
uint32_t adc_temp)
{
float var1 = 0.0f;
float var2 = 0.0f;
float calc_temp = 0.0f;
struct bme680_sensor_s dev = priv->dev;
var1 = ((((float)adc_temp / 16384.0f) - ((float)dev.calib.t1 / 1024.0f))
* ((float)dev.calib.t2));
var2 = (((((float)adc_temp / 131072.0f) - ((float)dev.calib.t1 / 8192.0f))
* (((float)adc_temp / 131072.0f) - ((float)dev.calib.t1 / 8192.0f)))
* ((float)dev.calib.t3 * 16.0f));
priv->dev.calib.t_fine = (var1 + var2);
/* Compensated temperature data */
calc_temp = (priv->dev.calib.t_fine) / 5120.0f;
return calc_temp;
}
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
static float bme680_comp_press(FAR struct bme680_dev_s *priv,
uint32_t adc_press)
{
float var1 = 0.0f;
float var2 = 0.0f;
float var3 = 0.0f;
float calc_pres = 0.0f;
struct bme680_sensor_s dev = priv->dev;
var1 = (((float)dev.calib.t_fine / 2.0f) - 64000.0f);
var2 = var1 * var1 * (((float)dev.calib.p6) / (131072.0f));
var2 = var2 + (var1 * ((float)dev.calib.p5) * 2.0f);
var2 = (var2 / 4.0f) + (((float)dev.calib.p4) * 65536.0f);
var1 = (((((float)dev.calib.p3 * var1 * var1) / 16384.0f)
+ ((float)dev.calib.p2 * var1)) / 524288.0f);
var1 = ((1.0f + (var1 / 32768.0f)) * ((float)dev.calib.p1));
calc_pres = (1048576.0f - ((float)adc_press));
/* Avoid exception caused by division by zero */
if ((int)var1 != 0)
{
calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1);
var1 = (((float)dev.calib.p9) * calc_pres * calc_pres) / 2147483648.0f;
var2 = calc_pres * (((float)dev.calib.p8) / 32768.0f);
var3 = ((calc_pres / 256.0f) * (calc_pres / 256.0f)
* (calc_pres / 256.0f) * (dev.calib.p10 / 131072.0f));
calc_pres = (calc_pres + (var1 + var2 + var3
+ ((float)dev.calib.p7 * 128.0f)) / 16.0f);
}
return calc_pres;
}
#endif /* !CONFIG_BME680_DISABLE_PRESS_MEAS */
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
static float bme680_comp_hum(FAR struct bme680_dev_s *priv,
uint16_t adc_hum)
{
float calc_hum = 0.0f;
float var1 = 0.0f;
float var2 = 0.0f;
float var3 = 0.0f;
float var4 = 0.0f;
float temp_comp;
struct bme680_sensor_s dev = priv->dev;
/* Compensated temperature data */
temp_comp = ((dev.calib.t_fine) / 5120.0f);
var1 = (float)((float)adc_hum) - (((float)dev.calib.h1 * 16.0f)
+ (((float)dev.calib.h3 / 2.0f) * temp_comp));
var2 = var1 * ((float)(((float)dev.calib.h2 / 262144.0f)
* (1.0f + (((float)dev.calib.h4 / 16384.0f) * temp_comp)
+ (((float)dev.calib.h5 / 1048576.0f) * temp_comp * temp_comp))));
var3 = (float)dev.calib.h6 / 16384.0f;
var4 = (float)dev.calib.h7 / 2097152.0f;
calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2);
if (calc_hum > 100.0f)
{
calc_hum = 100.0f;
}
else if (calc_hum < 0.0f)
{
calc_hum = 0.0f;
}
return calc_hum;
}
#endif /* !CONFIG_BME680_DISABLE_HUM_MEAS */
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
static float bme680_calc_gas_res(FAR struct bme680_dev_s *priv,
uint16_t adc_gas_res, uint8_t gas_range)
{
float calc_gas_res;
float var1 = 0.0f;
struct bme680_sensor_s dev = priv->dev;
var1 = (1340.0f + (5.0f * dev.calib.range_sw_err))
* const_array1[gas_range];
calc_gas_res = var1 * const_array2[gas_range]
/ (adc_gas_res - 512.0f + var1);
return calc_gas_res;
}
#endif /* !CONFIG_BME680_DISABLE_GAS_MEAS */
/****************************************************************************
* Name: bme680_read_measurements
*
* Description:
* Reads the raw data from the sensor and computes the compensated
* values, storing them in the data struct.
*
****************************************************************************/
static int bme680_read_measurements(FAR struct bme680_dev_s *priv,
FAR struct bme680_data_s *data)
{
uint8_t status;
uint32_t adc_temp;
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
uint32_t adc_press;
#endif /* !CONFIG_BME680_DISABLE_PRESS_MEAS */
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
uint16_t adc_hum;
#endif /* !CONFIG_BME680_DISABLE_HUM_MEAS */
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
uint16_t adc_gas_res;
uint8_t gas_range;
uint8_t gas_valid;
uint8_t heat_stab;
#endif /* !CONFIG_BME680_DISABLE_GAS_MEAS */
int ret;
uint8_t data_regs[BME680_DATA_LEN];
ret = bme680_getregs(priv, BME680_DATA_ADDR, data_regs, BME680_DATA_LEN);
if (ret < 0)
{
snerr("Failed to read data registers.\n");
return ret;
}
status = data_regs[0] & BME680_NEW_DATA_MSK;
/* No new data, return */
if (!status)
{
sninfo("No new data\n");
return -ENODATA;
}
adc_temp = (uint32_t)(((uint32_t)data_regs[5] << 12)
| ((uint32_t)data_regs[6] << 4)
| ((uint32_t)data_regs[7] >> 4));
data->temperature = bme680_comp_temp(priv, adc_temp);
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
adc_press = (uint32_t)(((uint32_t)data_regs[2] << 12)
| ((uint32_t)data_regs[3] << 4)
| ((uint32_t)data_regs[4] >> 4));
data->pressure = bme680_comp_press(priv, adc_press);
#endif /* !CONFIG_BME680_DISABLE_PRESS_MEAS */
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
adc_hum = (uint16_t)(((uint32_t)data_regs[8] << 8)
| (uint32_t)data_regs[9]);
data->humidity = bme680_comp_hum(priv, adc_hum);
#endif /* !CONFIG_BME680_DISABLE_HUM_MEAS */
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
adc_gas_res = (uint16_t)((uint32_t)data_regs[13] << 2
| (((uint32_t)data_regs[14]) >> 6));
gas_range = data_regs[14] & BME680_GAS_RANGE_MSK;
/* Is measured gas valid? */
gas_valid = data_regs[14] & BME680_GASM_VALID_MSK;
if (!gas_valid)
{
sninfo("Invalid gas measurement.\n");
return -1;
}
heat_stab = data_regs[14] & BME680_HEAT_STAB_MSK;
if (!heat_stab)
{
sninfo("The heater did not stabilize.\n");
return -1;
}
priv->dev.config.amb_temp = data->temperature; /* Update ambient temp */
data->gas_resistance = bme680_calc_gas_res(priv, adc_gas_res, gas_range);
#endif /* !CONFIG_BME680_DISABLE_GAS_MEAS */
return OK;
}
/****************************************************************************
* Name: bme680_get_tphg_dur
*
* Description:
* Compute the duration of a tphg cycle in us, taking into consideration
* the settings of the sensor.
*
****************************************************************************/
static uint16_t bme680_get_tphg_dur(FAR struct bme680_dev_s *priv)
{
uint32_t tph_dur; /* Calculate in us */
uint32_t meas_cycles;
uint16_t duration;
uint8_t os_to_meas_cycles[6] =
{
0, 1, 2, 4, 8, 16
};
meas_cycles = os_to_meas_cycles[priv->dev.config.temp_os];
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
meas_cycles += os_to_meas_cycles[priv->dev.config.press_os];
#endif
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
meas_cycles += os_to_meas_cycles[priv->dev.config.hum_os];
#endif
/* TPH measurement duration */
tph_dur = meas_cycles * 1963;
tph_dur += 477 * 4; /* TPH switching duration */
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
tph_dur += 477 * 5; /* Gas measurement duration */
#endif
tph_dur += 500;
tph_dur /= 1000; /* Convert to ms */
tph_dur += 1; /* Wake up duration of 1ms */
duration = (uint16_t)tph_dur;
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
/* The remaining time should be used for heating */
duration += priv->dev.config.heater_duration;
#endif
return duration;
}
static int bme680_activate(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep, bool enable)
{
int offset;
FAR struct bme680_sensor_s *dev;
FAR struct bme680_dev_s *priv;
/* Get offset inside array of lowerhalfs */
switch (lower->type)
{
case SENSOR_TYPE_AMBIENT_TEMPERATURE:
offset = BME680_TEMP_IDX;
break;
case SENSOR_TYPE_BAROMETER:
offset = BME680_PRESS_IDX;
break;
case SENSOR_TYPE_RELATIVE_HUMIDITY:
offset = BME680_HUM_IDX;
break;
case SENSOR_TYPE_GAS:
offset = BME680_GAS_IDX;
break;
default:
offset = 0;
break;
}
dev = (FAR struct bme680_sensor_s *)
((uintptr_t)lower - offset * sizeof(*lower));
priv = container_of(dev, FAR struct bme680_dev_s, dev);
/* Wake the thread only once (the activate method will be called
* multiple times for the bme680 sub-sensors)
*/
if (!priv->enabled && enable)
{
dev->calibrated = false;
priv->enabled = enable;
/* Wake up the polling thread */
nxsem_post(&priv->run);
return OK;
}
priv->enabled = enable;
return OK;
}
static int bme680_calibrate(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep, unsigned long arg)
{
int offset;
FAR struct bme680_sensor_s *dev;
FAR struct bme680_dev_s *priv;
FAR struct bme680_config_s *calibval = (FAR struct bme680_config_s *)arg;
int ret;
/* Get offset inside array of lowerhalfs */
switch (lower->type)
{
case SENSOR_TYPE_AMBIENT_TEMPERATURE:
offset = BME680_TEMP_IDX;
break;
case SENSOR_TYPE_BAROMETER:
offset = BME680_PRESS_IDX;
break;
case SENSOR_TYPE_RELATIVE_HUMIDITY:
offset = BME680_HUM_IDX;
break;
case SENSOR_TYPE_GAS:
offset = BME680_GAS_IDX;
break;
default:
offset = 0;
break;
}
dev = (FAR struct bme680_sensor_s *)
((uintptr_t)lower - offset * sizeof(*lower));
priv = container_of(dev, FAR struct bme680_dev_s, dev);
/* Sanity checks */
if (!CHECK_OS_BOUNDS(calibval->temp_os))
{
return -EINVAL;
}
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
if (!CHECK_OS_BOUNDS(calibval->press_os))
{
return -EINVAL;
}
#endif
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
if (!CHECK_OS_BOUNDS(calibval->hum_os))
{
return -EINVAL;
}
#endif
#ifdef CONFIG_BME680_ENABLE_IIR_FILTER
if (calibval->filter_coef < BME680_FILTER_COEF0 ||
calibval->filter_coef > BME680_FILTER_COEF127)
{
return -EINVAL;
}
#endif
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
if (calibval->target_temp < MIN_HOT_PLATE_TEMP ||
calibval->target_temp > MAX_HOT_PLATE_TEMP)
{
return -EINVAL;
}
if (calibval->nb_conv > 9)
{
return -EINVAL;
}
#endif
/* Update config in priv */
memcpy(&priv->dev.config, calibval, sizeof(struct bme680_config_s));
ret = bme680_write_config(priv);
if (ret < 0)
{
snerr("Failed to calibrate sensor.\n");
return ret;
}
priv->dev.calibrated = true;
return ret;
}
static int bme680_control(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
int cmd, unsigned long arg)
{
FAR struct bme680_sensor_s *dev = container_of(lower,
FAR struct bme680_sensor_s,
lower);
FAR struct bme680_dev_s *priv = container_of(dev,
FAR struct bme680_dev_s,
dev);
int ret;
switch (cmd)
{
case SNIOC_RESET:
{
/* Perform Soft Reset */
uint8_t regval = 0xb6;
ret = bme680_putreg8(priv, BME680_RESET_REG_ADDR, regval);
if (ret < 0)
{
return ret;
}
/* Wait for the device to reset */
up_mdelay(100);
}
break;
default:
break;
}
return OK;
}
static int bme680_thread(int argc, char **argv)
{
FAR struct bme680_dev_s *priv =
(FAR struct bme680_dev_s *)((uintptr_t)strtoul(argv[1], NULL, 16));
struct bme680_data_s data;
int ret;
while (true)
{
int sensor;
if (!priv->enabled)
{
/* Wait for the sensor to be enabled */
nxsem_wait(&priv->run);
}
/* No measurements are done unless the sensor is calibrated */
if (!priv->dev.calibrated)
{
sninfo("The sensor is not calibrated!\n");
goto thread_sleep;
}
/* Trigger a measurement */
ret = bme680_set_mode(priv, BME680_FORCED_MODE);
/* Wait for the TPHG cycle to complete */
uint16_t cycle_duration = bme680_get_tphg_dur(priv);
up_mdelay(cycle_duration);
ret = bme680_read_measurements(priv, &data);
if (ret < 0)
{
goto thread_sleep;
}
data.timestamp = sensor_get_timestamp();
for (sensor = 0; sensor < BME680_SENSORS_COUNT; sensor++)
{
deliver_data[sensor](priv, &data);
}
thread_sleep:
nxsig_usleep(CONFIG_SENSORS_BME680_POLL_INTERVAL);
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: bme680_register
*
* Description:
* Register the BME680 character device
* @devno - The user-specified device number, starting from 0
* @i2c - An instance of the I2C interface to use to communicate with
* BME680
*
* Return value:
* Zero (OK) on success; a negated errno value on failure
****************************************************************************/
int bme680_register(int devno, FAR struct i2c_master_s *i2c)
{
FAR struct sensor_lowerhalf_s *lower;
FAR struct bme680_dev_s *priv;
FAR char *argv[2];
char arg1[32];
int ret = OK;
int i;
DEBUGASSERT(i2c != NULL);
/* Initialize the BME680 device structure */
priv = (FAR struct bme680_dev_s *)kmm_zalloc(sizeof(struct bme680_dev_s));
if (priv == NULL)
{
snerr("ERROR: Failed to allocate instance (err = %d)\n", ret);
return -ENOMEM;
}
priv->i2c = i2c;
priv->enabled = false;
nxmutex_init(&priv->dev_lock);
nxsem_init(&priv->run, 0, 0);
/* Check Device ID */
ret = bme680_checkid(priv);
if (ret < 0)
{
snerr("ERROR: Wrong device ID!\n");
goto err_init;
}
/* Get Calibration Data */
ret = bme680_get_calib_data(priv);
if (ret < 0)
{
snerr("Failed to read calib data from bme680:%d\n", ret);
goto err_init;
}
#ifndef CONFIG_BME680_DISABLE_PRESS_MEAS
/* Register the barometer driver */
lower = &priv->dev.lower[BME680_PRESS_IDX];
lower->ops = &g_sensor_ops;
lower->type = SENSOR_TYPE_BAROMETER;
ret = sensor_register(lower, devno);
if (ret < 0)
{
snerr("ERROR: Failed to register barometer driver (err = %d)\n",
ret);
goto err_init;
}
#else
/* Register the temperature driver */
lower = &priv->dev.lower[BME680_TEMP_IDX];
lower->ops = &g_sensor_ops;
lower->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
ret = sensor_register(lower, devno);
if (ret < 0)
{
snerr("ERROR: Failed to register temperature driver (err = %d)\n",
ret);
goto err_init;
}
#endif
#ifndef CONFIG_BME680_DISABLE_HUM_MEAS
/* Register the humidity driver */
lower = &priv->dev.lower[BME680_HUM_IDX];
lower->ops = &g_sensor_ops;
lower->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
ret = sensor_register(lower, devno);
if (ret < 0)
{
snerr("ERROR: Failed to register humidity driver (err = %d)\n",
ret);
goto err_init;
}
#endif
#ifndef CONFIG_BME680_DISABLE_GAS_MEAS
/* Register the gas driver */
lower = &priv->dev.lower[BME680_GAS_IDX];
lower->ops = &g_sensor_ops;
lower->type = SENSOR_TYPE_GAS;
ret = sensor_register(lower, devno);
if (ret < 0)
{
snerr("ERROR: Failed to register gas driver (err = %d)\n",
ret);
goto err_init;
}
#endif
/* Create thread for polling sensor data */
snprintf(arg1, 16, "%p", priv);
argv[0] = arg1;
argv[1] = NULL;
ret = kthread_create("bme680_thread", SCHED_PRIORITY_DEFAULT,
CONFIG_SENSORS_BME680_THREAD_STACKSIZE,
bme680_thread, argv);
if (ret < 0)
{
snerr("ERROR: Failed to create poll thread (err = %d)\n", ret);
goto err_register;
}
sninfo("BME680 driver loaded successfully!\n");
return OK;
err_register:
for (i = 0; i < BME680_SENSORS_COUNT; i++)
{
sensor_unregister(&priv->dev.lower[i], devno);
}
err_init:
nxsem_destroy(&priv->run);
nxmutex_destroy(&priv->dev_lock);
kmm_free(priv);
return ret;
}
#endif /* CONFIG_I2C && CONFIG_SENSORS_BME680 */