drivers: sensor: ccs811: rework data fetch to prepare for non-polled use

The original implementation relied on the DATA_READY bit of the STATUS
register to indicate when a reading was available.  This bit remains
clear for the first several readings produced by the CCS811.

When INT_DATARDY is set in MEAS_MODE the nINT signal will remain
asserted until ALG_RESULT_DATA is read.  If this is treated as a LEVEL
signal, which is the common case in Zephyr, gating the read of
ALG_RESULT_DATA on DATA_READY means the signal will never be cleared,
and the interrupt callback will be repeated immediately.

Since the STATUS register value is part of the ALG_RESULT_DATA block
just read the whole thing, and provide its content to the user only if
the DATA_READY bit is set.

Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
Peter A. Bigot 2018-11-21 13:16:13 -06:00 committed by Maureen Helm
commit 29c5f30ed2

View file

@ -73,11 +73,10 @@ static inline u8_t error_from_status(int status)
static int ccs811_sample_fetch(struct device *dev, enum sensor_channel chan)
{
struct ccs811_data *drv_data = dev->driver_data;
int rc;
int tries;
u16_t buf[4];
u8_t cmd;
int status;
int rv = -EIO;
/* Check data ready flag for the measurement interval */
#ifdef CONFIG_CCS811_DRIVE_MODE_1
@ -88,50 +87,41 @@ static int ccs811_sample_fetch(struct device *dev, enum sensor_channel chan)
tries = 601;
#endif
while (tries-- > 0) {
do {
const u8_t cmd = CCS811_REG_ALG_RESULT_DATA;
set_wake(drv_data, true);
status = fetch_status(drv_data->i2c);
if (status < 0) {
goto out;
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));
goto out;
return -EIO;
}
if ((status & CCS811_STATUS_DATA_READY) || tries == 0) {
if (status & CCS811_STATUS_DATA_READY) {
break;
}
set_wake(drv_data, false);
k_sleep(K_MSEC(100));
}
} while (--tries > 0);
if (!(status & CCS811_STATUS_DATA_READY)) {
LOG_ERR("Sensor data not available");
goto out;
return -EIO;
}
cmd = CCS811_REG_ALG_RESULT_DATA;
if (i2c_write_read(drv_data->i2c, DT_INST_0_AMS_CCS811_BASE_ADDRESS,
&cmd, sizeof(cmd),
(u8_t *)buf, 8) < 0) {
LOG_ERR("Failed to read conversion data.");
goto out;
}
drv_data->co2 = sys_be16_to_cpu(buf[0]);
drv_data->voc = sys_be16_to_cpu(buf[1]);
drv_data->status = buf[2] & 0xff;
drv_data->error = buf[2] >> 8;
drv_data->status = status;
drv_data->error = error_from_status(status);
drv_data->resistance = sys_be16_to_cpu(buf[3]);
rv = 0;
out:
set_wake(drv_data, false);
return rv;
return 0;
}
static int ccs811_channel_get(struct device *dev,