samples: sensor: ccs811: update for new capabilities

Use nrf52_pca20020 and nrf51_ble400 to demonstrate the new functionality
of the CCS811 driver.

Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
Peter A. Bigot 2018-11-24 12:09:36 -06:00 committed by Maureen Helm
commit 45f9efe02f
5 changed files with 334 additions and 18 deletions

View file

@ -0,0 +1,52 @@
#
# Copyright (c) 2018 Peter Bigot Consulting, LLC
#
# SPDX-License-Identifier: Apache-2.0
#
mainmenu "CCS811 sample application"
choice
prompt "CCS811 Trigger On"
default APP_TRIGGER_ON_DATAREADY
depends on CCS811_TRIGGER
help
Select the type of trigger to use
config APP_TRIGGER_ON_DATAREADY
bool "Trigger on data ready"
config APP_TRIGGER_ON_THRESHOLD
bool "Trigger on eCO2 threshold crossing"
endchoice
config APP_CO2_MEDIUM_PPM
int "Threshold of eCO2 between low and medium"
default 1500
depends on APP_TRIGGER_ON_THRESHOLD
config APP_CO2_HIGH_PPM
int "Threshold of eCO2 between medium and high"
default 2500
depends on APP_TRIGGER_ON_THRESHOLD
config APP_MONITOR_BASELINE
bool "Display BASELINE register value for each sample"
default y
config APP_USE_ENVDATA
bool "Program CCS811 with fixed environmental parameters"
default n
config APP_ENV_TEMPERATURE
int "Environment temperature for CCS811, Cel"
default 25
depends on APP_USE_ENVDATA
config APP_ENV_HUMIDITY
int "Environment humidity for CCS811, %RH"
default 50
depends on APP_USE_ENVDATA
source "Kconfig.zephyr"

View file

@ -0,0 +1,87 @@
.. _ccs811:
CCS811 Indoor Air Quality Sensor
################################
Overview
********
The CCS811 digital gas sensor detects volatile organic compounds (VOCs)
for indoor air quality measurements. VOCs are often categorized as
pollutants and/or sensory irritants and can come from a variety of
sources such as construction materials (paint and carpet), machines
(copiers and processors), and even people (breathing and smoking). It
estimates carbon dioxide (CO2) levels where the main source of VOCs is
human presence.
Building and Running
********************
Building and Running on nrf52_pca20020
======================================
.. zephyr-app-commands::
:zephyr-app: samples/sensor/ccs811
:board: nrf52_pca20020
:goals: build flash
:compact:
Sample Output
=============
The sample output below is from a `Nordic Thingy:52
<https://www.nordicsemi.com/Software-and-tools/Prototyping-platforms/Nordic-Thingy-52>`_
(nrf52_pca20020) that includes this sensor (and others).
After a soft reset, there is a 5-second startup period
where readings are unstable, and then we can see steady
reported measurements of about 400 ppm eC02 and 0 ppb eTVOC.
.. code-block::console
*** Booting Zephyr OS build zephyr-v2.1.0-310-g32a3e9907bab ***
device is 0x20001088, name is CCS811
HW 12; FW Boot 1000 App 1100 ; mode 10
[0:00:00.046]: CCS811: 65021 ppm eCO2; 65021 ppb eTVOC
Voltage: 0.000000V; Current: 0.000000A
BASELINE fff4
Timed fetch got 0
[0:00:01.059]: CCS811: 65021 ppm eCO2; 65021 ppb eTVOC
Voltage: 0.000000V; Current: 0.000000A
BASELINE fff4
Timed fetch got 0
Timed fetch got stale data
Timed fetch got stale data
Timed fetch got stale data
[0:00:05.084]: CCS811: 400 ppm eCO2; 0 ppb eTVOC
Voltage: 0.677040V; Current: 0.000014A
BASELINE 8384
Timed fetch got 0
[0:00:06.096]: CCS811: 405 ppm eCO2; 0 ppb eTVOC
Voltage: 0.675428V; Current: 0.000014A
BASELINE 8384
Timed fetch got 0
[0:00:07.108]: CCS811: 400 ppm eCO2; 0 ppb eTVOC
Voltage: 0.677040V; Current: 0.000014A
BASELINE 8384
Timed fetch got 0
[0:00:08.121]: CCS811: 400 ppm eCO2; 0 ppb eTVOC
Voltage: 0.677040V; Current: 0.000014A
BASELINE 8384
Timed fetch got 0
[0:00:09.133]: CCS811: 400 ppm eCO2; 0 ppb eTVOC
Voltage: 0.677040V; Current: 0.000014A
BASELINE 8384
Timed fetch got 0
[0:00:10.145]: CCS811: 400 ppm eCO2; 0 ppb eTVOC
Voltage: 0.677040V; Current: 0.000014A
BASELINE 8384
Timed fetch got 0

View file

@ -0,0 +1,12 @@
#
# Copyright (c) 2018 Peter Bigot Consulting, LLC
#
# SPDX-License-Identifier: Apache-2.0
#
CONFIG_STDOUT_CONSOLE=y
CONFIG_SENSOR=y
CONFIG_CCS811=y
#CONFIG_CCS811_DRIVE_MODE_2=y
#CONFIG_CCS811_TRIGGER_GLOBAL_THREAD=y
#CONFIG_CCS811_TRIGGER_OWN_THREAD=y

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2018 Peter Bigot Consulting, LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
&i2c0 {
status = "okay";
sda-pin = <0>;
scl-pin = <1>;
/* Sparkfun Environment Combo uses second I2C address */
ccs811: ccs811@5b {
compatible = "ams,ccs811";
reg = <0x5b>;
label = "CCS811";
irq-gpios = <&gpio0 2 GPIO_INT_ACTIVE_LOW>;
wake-gpios = <&gpio0 5 GPIO_INT_ACTIVE_LOW>;
reset-gpios = <&gpio0 6 GPIO_INT_ACTIVE_LOW>;
};
};

View file

@ -1,4 +1,5 @@
/* /*
* Copyright (c) 2018 Peter Bigot Consulting, LLC
* Copyright (c) 2018 Linaro Ltd. * Copyright (c) 2018 Linaro Ltd.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
@ -8,33 +9,113 @@
#include <device.h> #include <device.h>
#include <drivers/sensor.h> #include <drivers/sensor.h>
#include <sys/printk.h> #include <sys/printk.h>
#include <drivers/sensor/ccs811.h>
#include <stdio.h>
static bool app_fw_2;
static const char *now_str(void)
{
static char buf[16]; /* ...HH:MM:SS.MMM */
u32_t now = k_uptime_get_32();
unsigned int ms = now % MSEC_PER_SEC;
unsigned int s;
unsigned int min;
unsigned int h;
now /= MSEC_PER_SEC;
s = now % 60U;
now /= 60U;
min = now % 60U;
now /= 60U;
h = now;
snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u",
h, min, s, ms);
return buf;
}
static int do_fetch(struct device *dev)
{
struct sensor_value co2, tvoc, voltage, current;
int rc = 0;
int baseline = -1;
#ifdef CONFIG_APP_MONITOR_BASELINE
rc = ccs811_baseline_fetch(dev);
if (rc >= 0) {
baseline = rc;
rc = 0;
}
#endif
if (rc == 0) {
rc = sensor_sample_fetch(dev);
}
if (rc == 0) {
const struct ccs811_result_type *rp = ccs811_result(dev);
sensor_channel_get(dev, SENSOR_CHAN_CO2, &co2);
sensor_channel_get(dev, SENSOR_CHAN_VOC, &tvoc);
sensor_channel_get(dev, SENSOR_CHAN_VOLTAGE, &voltage);
sensor_channel_get(dev, SENSOR_CHAN_CURRENT, &current);
printk("\n[%s]: CCS811: %u ppm eCO2; %u ppb eTVOC\n",
now_str(), co2.val1, tvoc.val1);
printk("Voltage: %d.%06dV; Current: %d.%06dA\n", voltage.val1,
voltage.val2, current.val1, current.val2);
#ifdef CONFIG_APP_MONITOR_BASELINE
printk("BASELINE %04x\n", baseline);
#endif
if (app_fw_2 && !(rp->status & CCS811_STATUS_DATA_READY)) {
printk("STALE DATA\n");
}
if (rp->status & CCS811_STATUS_ERROR) {
printk("ERROR: %02x\n", rp->error);
}
}
return rc;
}
#ifndef CONFIG_CCS811_TRIGGER_NONE
static void trigger_handler(struct device *dev, struct sensor_trigger *trig)
{
int rc = do_fetch(dev);
if (rc == 0) {
printk("Triggered fetch got %d\n", rc);
} else if (-EAGAIN == rc) {
printk("Triggered fetch got stale data\n");
} else {
printk("Triggered fetch failed: %d\n", rc);
}
}
#endif /* !CONFIG_CCS811_TRIGGER_NONE */
static void do_main(struct device *dev) static void do_main(struct device *dev)
{ {
struct sensor_value co2, voc, voltage, current; while (true) {
int rc = do_fetch(dev);
while (1) { if (rc == 0) {
sensor_sample_fetch(dev); printk("Timed fetch got %d\n", rc);
sensor_channel_get(dev, SENSOR_CHAN_CO2, &co2); } else if (-EAGAIN == rc) {
sensor_channel_get(dev, SENSOR_CHAN_VOC, &voc); printk("Timed fetch got stale data\n");
sensor_channel_get(dev, SENSOR_CHAN_VOLTAGE, &voltage); } else {
sensor_channel_get(dev, SENSOR_CHAN_CURRENT, &current); printk("Timed fetch failed: %d\n", rc);
break;
printk("Co2: %d.%06dppm; VOC: %d.%06dppb\n", co2.val1, co2.val2, }
voc.val1, voc.val2); k_sleep(1000);
printk("Voltage: %d.%06dV; Current: %d.%06dA\n\n", voltage.val1,
voltage.val2, current.val1, current.val2);
k_sleep(K_MSEC(1000));
} }
} }
void main(void) void main(void)
{ {
struct device *dev; struct device *dev = device_get_binding(DT_INST_0_AMS_CCS811_LABEL);
struct ccs811_configver_type cfgver;
int rc;
dev = device_get_binding(DT_INST_0_AMS_CCS811_LABEL);
if (!dev) { if (!dev) {
printk("Failed to get device binding"); printk("Failed to get device binding");
return; return;
@ -42,5 +123,68 @@ void main(void)
printk("device is %p, name is %s\n", dev, dev->config->name); printk("device is %p, name is %s\n", dev, dev->config->name);
do_main(dev); rc = ccs811_configver_fetch(dev, &cfgver);
if (rc == 0) {
printk("HW %02x; FW Boot %04x App %04x ; mode %02x\n",
cfgver.hw_version, cfgver.fw_boot_version,
cfgver.fw_app_version, cfgver.mode);
app_fw_2 = (cfgver.fw_app_version >> 8) > 0x11;
}
#ifdef CONFIG_APP_USE_ENVDATA
struct sensor_value temp = { CONFIG_APP_ENV_TEMPERATURE };
struct sensor_value humidity = { CONFIG_APP_ENV_HUMIDITY };
rc = ccs811_envdata_update(dev, &temp, &humidity);
printk("ENV_DATA set for %d Cel, %d %%RH got %d\n",
temp.val1, humidity.val1, rc);
#endif
#ifdef CONFIG_CCS811_TRIGGER
struct sensor_trigger trig = { 0 };
#ifdef CONFIG_APP_TRIGGER_ON_THRESHOLD
printk("Triggering on threshold:\n");
if (rc == 0) {
struct sensor_value thr = {
.val1 = CONFIG_APP_CO2_MEDIUM_PPM,
};
rc = sensor_attr_set(dev, SENSOR_CHAN_CO2,
SENSOR_ATTR_LOWER_THRESH,
&thr);
printk("L/M threshold to %d got %d\n", thr.val1, rc);
}
if (rc == 0) {
struct sensor_value thr = {
.val1 = CONFIG_APP_CO2_HIGH_PPM,
};
rc = sensor_attr_set(dev, SENSOR_CHAN_CO2,
SENSOR_ATTR_UPPER_THRESH,
&thr);
printk("M/H threshold to %d got %d\n", thr.val1, rc);
}
trig.type = SENSOR_TRIG_THRESHOLD;
trig.chan = SENSOR_CHAN_CO2;
#elif defined(CONFIG_APP_TRIGGER_ON_DATAREADY)
printk("Triggering on data ready\n");
trig.type = SENSOR_TRIG_DATA_READY;
trig.chan = SENSOR_CHAN_ALL;
#else
#error Unhandled trigger on
#endif
if (rc == 0) {
rc = sensor_trigger_set(dev, &trig, trigger_handler);
}
if (rc == 0) {
#ifdef CONFIG_APP_TRIGGER_ON_DATAREADY
while (true) {
k_sleep(K_FOREVER);
}
#endif
}
printk("Trigger installation got: %d\n", rc);
#endif /* CONFIG_CCS811_TRIGGER */
if (rc == 0) {
do_main(dev);
}
} }