drivers: sensor: ccs811: provide access to sensor results
Expose the entire content of the ALG_RESULT_DATA block to the application, primarily so the status and error flags can be seen. With those available the application has the ability to detect that a stale result has been provided so sensor_fetch_sample() can return -EAGAIN in this case instead of -EIO, and it doesn't need to block which is annoying. This should also make the sensor usable on older Nordic Thingy:52 devices with outdated CCS811 application firmware that doesn't properly implement the DATA_READY bit. Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
parent
c90a738d8c
commit
cb84836745
3 changed files with 92 additions and 63 deletions
|
@ -70,6 +70,13 @@ static inline u8_t error_from_status(int status)
|
|||
return status >> 8;
|
||||
}
|
||||
|
||||
const struct ccs811_result_type *ccs811_result(struct device *dev)
|
||||
{
|
||||
struct ccs811_data *drv_data = dev->driver_data;
|
||||
|
||||
return &drv_data->result;
|
||||
}
|
||||
|
||||
int ccs811_baseline_fetch(struct device *dev)
|
||||
{
|
||||
const u8_t cmd = CCS811_REG_BASELINE;
|
||||
|
@ -176,55 +183,30 @@ int ccs811_envdata_update(struct device *dev,
|
|||
static int ccs811_sample_fetch(struct device *dev, enum sensor_channel chan)
|
||||
{
|
||||
struct ccs811_data *drv_data = dev->driver_data;
|
||||
struct ccs811_result_type *rp = &drv_data->result;
|
||||
const u8_t cmd = CCS811_REG_ALG_RESULT_DATA;
|
||||
int rc;
|
||||
int tries;
|
||||
u16_t buf[4];
|
||||
int status;
|
||||
unsigned int status;
|
||||
|
||||
/* Check data ready flag for the measurement interval */
|
||||
#ifdef CONFIG_CCS811_DRIVE_MODE_1
|
||||
tries = 11;
|
||||
#elif defined(CONFIG_CCS811_DRIVE_MODE_2)
|
||||
tries = 101;
|
||||
#elif defined(CONFIG_CCS811_DRIVE_MODE_3)
|
||||
tries = 601;
|
||||
#endif
|
||||
|
||||
do {
|
||||
const u8_t cmd = CCS811_REG_ALG_RESULT_DATA;
|
||||
|
||||
set_wake(drv_data, true);
|
||||
rc = i2c_write_read(drv_data->i2c, DT_INST_0_AMS_CCS811_BASE_ADDRESS,
|
||||
&cmd, sizeof(cmd),
|
||||
(u8_t *)buf, sizeof(buf));
|
||||
|
||||
set_wake(drv_data, false);
|
||||
if (rc < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
status = buf[2];
|
||||
if (status & CCS811_STATUS_ERROR) {
|
||||
LOG_ERR("CCS811 ERROR ID %02x",
|
||||
error_from_status(status));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (status & CCS811_STATUS_DATA_READY) {
|
||||
break;
|
||||
}
|
||||
|
||||
k_sleep(K_MSEC(100));
|
||||
} while (--tries > 0);
|
||||
if (!(status & CCS811_STATUS_DATA_READY)) {
|
||||
set_wake(drv_data, true);
|
||||
rc = i2c_write_read(drv_data->i2c, DT_INST_0_AMS_CCS811_BASE_ADDRESS,
|
||||
&cmd, sizeof(cmd),
|
||||
(u8_t *)buf, sizeof(buf));
|
||||
set_wake(drv_data, false);
|
||||
if (rc < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
drv_data->co2 = sys_be16_to_cpu(buf[0]);
|
||||
drv_data->voc = sys_be16_to_cpu(buf[1]);
|
||||
drv_data->status = status;
|
||||
drv_data->error = error_from_status(status);
|
||||
drv_data->raw = sys_be16_to_cpu(buf[3]);
|
||||
return 0;
|
||||
|
||||
rp->co2 = sys_be16_to_cpu(buf[0]);
|
||||
rp->voc = sys_be16_to_cpu(buf[1]);
|
||||
status = sys_le16_to_cpu(buf[2]); /* sic */
|
||||
rp->status = status;
|
||||
rp->error = error_from_status(status);
|
||||
rp->raw = sys_be16_to_cpu(buf[3]);
|
||||
|
||||
/* @todo APP FW 1.1 may not set DATA_READY. */
|
||||
return (rp->status & CCS811_STATUS_DATA_READY) ? 0 : -EAGAIN;
|
||||
}
|
||||
|
||||
static int ccs811_channel_get(struct device *dev,
|
||||
|
@ -232,16 +214,17 @@ static int ccs811_channel_get(struct device *dev,
|
|||
struct sensor_value *val)
|
||||
{
|
||||
struct ccs811_data *drv_data = dev->driver_data;
|
||||
const struct ccs811_result_type *rp = &drv_data->result;
|
||||
u32_t uval;
|
||||
|
||||
switch (chan) {
|
||||
case SENSOR_CHAN_CO2:
|
||||
val->val1 = drv_data->co2;
|
||||
val->val1 = rp->co2;
|
||||
val->val2 = 0;
|
||||
|
||||
break;
|
||||
case SENSOR_CHAN_VOC:
|
||||
val->val1 = drv_data->voc;
|
||||
val->val1 = rp->voc;
|
||||
val->val2 = 0;
|
||||
|
||||
break;
|
||||
|
@ -249,7 +232,7 @@ static int ccs811_channel_get(struct device *dev,
|
|||
/*
|
||||
* Raw ADC readings are contained in least significant 10 bits
|
||||
*/
|
||||
uval = ((drv_data->raw & CCS811_RAW_VOLTAGE_MSK)
|
||||
uval = ((rp->raw & CCS811_RAW_VOLTAGE_MSK)
|
||||
>> CCS811_RAW_VOLTAGE_POS) * CCS811_RAW_VOLTAGE_SCALE;
|
||||
val->val1 = uval / 1000000U;
|
||||
val->val2 = uval % 1000000;
|
||||
|
@ -260,7 +243,7 @@ static int ccs811_channel_get(struct device *dev,
|
|||
* Current readings are contained in most
|
||||
* significant 6 bits in microAmps
|
||||
*/
|
||||
uval = ((drv_data->raw & CCS811_RAW_CURRENT_MSK)
|
||||
uval = ((rp->raw & CCS811_RAW_CURRENT_MSK)
|
||||
>> CCS811_RAW_CURRENT_POS) * CCS811_RAW_CURRENT_SCALE;
|
||||
val->val1 = uval / 1000000U;
|
||||
val->val2 = uval % 1000000;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <device.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <sys/util.h>
|
||||
#include <drivers/sensor/ccs811.h>
|
||||
|
||||
/* Registers */
|
||||
#define CCS811_REG_STATUS 0x00
|
||||
|
@ -29,17 +30,7 @@
|
|||
#define CCS881_HW_ID 0x81
|
||||
#define CCS811_HW_VERSION 0x10
|
||||
|
||||
/* Status register fields */
|
||||
#define CCS811_STATUS_ERROR BIT(0)
|
||||
#define CCS811_STATUS_DATA_READY BIT(3)
|
||||
#define CCS811_STATUS_APP_VALID BIT(4)
|
||||
#define CCS811_STATUS_FW_MODE BIT(7)
|
||||
|
||||
/* Measurement modes */
|
||||
#define CCS811_MODE_IDLE 0x00
|
||||
#define CCS811_MODE_IAQ_1SEC 0x10
|
||||
#define CCS811_MODE_IAQ_10SEC 0x20
|
||||
#define CCS811_MODE_IAQ_60SEC 0x30
|
||||
#define CCS811_MODE_RAW_DATA 0x40
|
||||
#define CCS811_MODE_DATARDY 0x08
|
||||
#define CCS811_MODE_THRESH 0x04
|
||||
|
@ -85,11 +76,7 @@ struct ccs811_data {
|
|||
#ifdef DT_INST_0_AMS_CCS811_WAKE_GPIOS_CONTROLLER
|
||||
struct device *wake_gpio;
|
||||
#endif
|
||||
u16_t co2;
|
||||
u16_t voc;
|
||||
u16_t raw;
|
||||
u8_t status;
|
||||
u8_t error;
|
||||
struct ccs811_result_type result;
|
||||
u8_t mode;
|
||||
};
|
||||
|
||||
|
|
|
@ -22,6 +22,65 @@ extern "C" {
|
|||
#include <device.h>
|
||||
#include <drivers/sensor.h>
|
||||
|
||||
/* Status register fields */
|
||||
#define CCS811_STATUS_ERROR BIT(0)
|
||||
#define CCS811_STATUS_DATA_READY BIT(3)
|
||||
#define CCS811_STATUS_APP_VALID BIT(4)
|
||||
#define CCS811_STATUS_FW_MODE BIT(7)
|
||||
|
||||
/* Error register fields */
|
||||
#define CCS811_ERROR_WRITE_REG_INVALID BIT(0)
|
||||
#define CCS811_ERROR_READ_REG_INVALID BIT(1)
|
||||
#define CCS811_ERROR_MEASMODE_INVALID BIT(2)
|
||||
#define CCS811_ERROR_MAX_RESISTANCE BIT(3)
|
||||
#define CCS811_ERROR_HEATER_FAULT BIT(4)
|
||||
#define CCS811_ERROR_HEATER_SUPPLY BIT(5)
|
||||
|
||||
/* Measurement mode constants */
|
||||
#define CCS811_MODE_IDLE 0x00
|
||||
#define CCS811_MODE_IAQ_1SEC 0x10
|
||||
#define CCS811_MODE_IAQ_10SEC 0x20
|
||||
#define CCS811_MODE_IAQ_60SEC 0x30
|
||||
#define CCS811_MODE_IAQ_RAW_250MSEC 0x40
|
||||
|
||||
/** @brief Information collected from the sensor on each fetch. */
|
||||
struct ccs811_result_type {
|
||||
/** Equivalent carbon dioxide in parts-per-million volume (ppmv). */
|
||||
u16_t co2;
|
||||
|
||||
/**
|
||||
* Equivalent total volatile organic compounts in
|
||||
* parts-per-billion volume.
|
||||
*/
|
||||
u16_t voc;
|
||||
|
||||
/** Raw voltage and current measured by sensor. */
|
||||
u16_t raw;
|
||||
|
||||
/** Sensor status at completion of most recent fetch. */
|
||||
u8_t status;
|
||||
|
||||
/**
|
||||
* Sensor error flags at completion of most recent fetch.
|
||||
*
|
||||
* Note that errors are cleared when read.
|
||||
*/
|
||||
u8_t error;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Access storage for the most recent data read from the sensor.
|
||||
*
|
||||
* This content of the object referenced is updated by
|
||||
* sensor_fetch_sample(), except for ccs811_result_type::mode which is
|
||||
* set on driver initialization.
|
||||
*
|
||||
* @param dev Pointer to the sensor device
|
||||
*
|
||||
* @return a pointer to the result information.
|
||||
*/
|
||||
const struct ccs811_result_type *ccs811_result(struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Fetch the current value of the BASELINE register.
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue