AVRly - AVR Development Resources
ccs811.c File Reference

Driver for the CCS811 gas sensor. More...

#include <util/delay.h>
#include "ccs811.h"
#include "i2c.h"

Go to the source code of this file.

Macros

#define CCS811_ADDRESS_W   0xB4
 
#define CCS811_ADDRESS_R   0xB5
 
#define STATUS_REG   0x00
 
#define MEAS_MODE_REG   0x01
 
#define ALG_RESULT_DATA_REG   0x02
 
#define RAW_DATA_REG   0x03
 
#define ENV_DATA_REG   0x05
 
#define THRESHOLDS_REG   0x10
 
#define BASELINE_REG   0x11
 
#define HW_ID_REG   0x20
 
#define HW_VERSION_REG   0x21
 
#define FW_BOOT_VERSION_REG   0x23
 
#define FW_APP_VERSION_REG   0x24
 
#define INTERNAL_STATE_REG   0xA0
 
#define ERROR_ID_REG   0xE0
 
#define SW_RESET_REG   0xFF
 
#define ALG_RESULT_DATA_SIZE   8
 
#define ETVOC_SIZE   4
 
#define RAW_DATA_SIZE   2
 
#define ENV_DATA_SIZE   4
 
#define THRESHOLDS_SIZE   5
 
#define BASELINE_SIZE   2
 
#define FW_BOOT_VERSION_SIZE   2
 
#define FW_APP_VERSION_SIZE   2
 
#define SW_RESET_SIZE   4
 
#define APP_START   0xF4
 
#define GPIO_WAKE   0x5
 
#define HEATER_SUPPLY   5
 
#define HEATER_FAULT   4
 
#define MAX_RESISTANCE   3
 
#define MEASMODE_INVALID   2
 
#define READ_REG_INVALID   1
 
#define WRITE_REG_INVALID   0
 
#define DRIVE_MODE_BITS   4
 
#define INT_DATARDY_BIT   3
 
#define INT_THRESH_BIT   2
 
#define FW_MODE_BIT   7
 
#define APP_ERASE_BIT   6
 
#define APP_VERIFY_BIT   5
 
#define APP_VALID_BIT   4
 
#define DATA_READY_BIT   3
 
#define ERROR_BIT   0
 
#define BUS_SPEED_100KHZ   100000U
 
#define ATTEMPTS_MAX   10
 
#define CCS811_ID   0x81
 

Functions

uint8_t ccs811_read_byte (uint8_t reg)
 
void ccs811_burst_read (uint8_t reg, uint8_t length)
 
uint16_t ccs811_read_word (uint8_t reg)
 
void ccs811_write_byte (uint8_t reg, uint8_t byte)
 
uint8_t ccs811_get_status (void)
 
uint8_t init_ccs811 (ccs811_config_t *p_config)
 Initialisation routine (run once at startup). More...
 
uint16_t ccs811_get_eco2_level (void)
 Read eCO2 (equivalent carbon dioxide) level from sensor. More...
 
uint16_t ccs811_get_etvoc_level (void)
 Read eTVOC (equivalent total volatile organic compounds) level from sensor. More...
 
bool ccs811_data_ready_check (void)
 Read the status register and check if the data ready flag is set. More...
 
void ccs811_get_alg_result_data (void)
 Perform a read operation on all 8 bytes of ALG_RESULT_REGISTER. More...
 
void ccs811_update_env_data (uint8_t humidity, uint8_t temp)
 (Optional) Write environmental data from another sensor to the CCS811. More...
 
char * ccs811_error_to_string (void)
 For error handling/logging. More...
 

Detailed Description

Driver for the CCS811 gas sensor.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Author
Jason Duffy
Date
4th March 2022

This file provides the basic low-level functionality for the CCS81 gas sensor / air quality sensor. It was tested with the CJMCU-811 module which provides pin breakout to THT for breadboard prototyping, and some peripheral circuitry. The CCS811 eatures an on-board MCU to interface with, greatly reducing the load on the host MCU.

When the sensor is new, a burn-in period of 48hr is necessary for the resistive elements to level out and make readings more accurate. The CCS81 controls the burn-in period, allowing eCO2 and eTVOC readings to be used from first power-on after 60 minutes of operation in modes 1-3.

After early-life (Burn-In) use the conditioning period is the time required to achieve good sensor stability before measuring VOCs after a long idle period. After starting the application and calling init_ccs811(), run the sensor for 20 minutes before accurate readings are generated. The conditioning period must also be observed before writing to the BASELINE register.

This driver was written using the datasheet for the ams CCS81 gas sensor, which can be found at the link below.

See also
https://pdf1.alldatasheet.com/datasheet-pdf/view/1047395/AMSCO/CCS811.html

Definition in file ccs811.c.

Macro Definition Documentation

◆ CCS811_ADDRESS_W

#define CCS811_ADDRESS_W   0xB4

Definition at line 61 of file ccs811.c.

◆ CCS811_ADDRESS_R

#define CCS811_ADDRESS_R   0xB5

Definition at line 62 of file ccs811.c.

◆ STATUS_REG

#define STATUS_REG   0x00

Definition at line 65 of file ccs811.c.

◆ MEAS_MODE_REG

#define MEAS_MODE_REG   0x01

Definition at line 66 of file ccs811.c.

◆ ALG_RESULT_DATA_REG

#define ALG_RESULT_DATA_REG   0x02

Definition at line 67 of file ccs811.c.

◆ RAW_DATA_REG

#define RAW_DATA_REG   0x03

Definition at line 68 of file ccs811.c.

◆ ENV_DATA_REG

#define ENV_DATA_REG   0x05

Definition at line 69 of file ccs811.c.

◆ THRESHOLDS_REG

#define THRESHOLDS_REG   0x10

Definition at line 70 of file ccs811.c.

◆ BASELINE_REG

#define BASELINE_REG   0x11

Definition at line 71 of file ccs811.c.

◆ HW_ID_REG

#define HW_ID_REG   0x20

Definition at line 72 of file ccs811.c.

◆ HW_VERSION_REG

#define HW_VERSION_REG   0x21

Definition at line 73 of file ccs811.c.

◆ FW_BOOT_VERSION_REG

#define FW_BOOT_VERSION_REG   0x23

Definition at line 74 of file ccs811.c.

◆ FW_APP_VERSION_REG

#define FW_APP_VERSION_REG   0x24

Definition at line 75 of file ccs811.c.

◆ INTERNAL_STATE_REG

#define INTERNAL_STATE_REG   0xA0

Definition at line 76 of file ccs811.c.

◆ ERROR_ID_REG

#define ERROR_ID_REG   0xE0

Definition at line 77 of file ccs811.c.

◆ SW_RESET_REG

#define SW_RESET_REG   0xFF

Definition at line 78 of file ccs811.c.

◆ ALG_RESULT_DATA_SIZE

#define ALG_RESULT_DATA_SIZE   8

Definition at line 81 of file ccs811.c.

◆ ETVOC_SIZE

#define ETVOC_SIZE   4

Definition at line 82 of file ccs811.c.

◆ RAW_DATA_SIZE

#define RAW_DATA_SIZE   2

Definition at line 83 of file ccs811.c.

◆ ENV_DATA_SIZE

#define ENV_DATA_SIZE   4

Definition at line 84 of file ccs811.c.

◆ THRESHOLDS_SIZE

#define THRESHOLDS_SIZE   5

Definition at line 85 of file ccs811.c.

◆ BASELINE_SIZE

#define BASELINE_SIZE   2

Definition at line 86 of file ccs811.c.

◆ FW_BOOT_VERSION_SIZE

#define FW_BOOT_VERSION_SIZE   2

Definition at line 87 of file ccs811.c.

◆ FW_APP_VERSION_SIZE

#define FW_APP_VERSION_SIZE   2

Definition at line 88 of file ccs811.c.

◆ SW_RESET_SIZE

#define SW_RESET_SIZE   4

Definition at line 89 of file ccs811.c.

◆ APP_START

#define APP_START   0xF4

Definition at line 92 of file ccs811.c.

◆ GPIO_WAKE

#define GPIO_WAKE   0x5

Definition at line 93 of file ccs811.c.

◆ HEATER_SUPPLY

#define HEATER_SUPPLY   5

Definition at line 96 of file ccs811.c.

◆ HEATER_FAULT

#define HEATER_FAULT   4

Definition at line 97 of file ccs811.c.

◆ MAX_RESISTANCE

#define MAX_RESISTANCE   3

Definition at line 98 of file ccs811.c.

◆ MEASMODE_INVALID

#define MEASMODE_INVALID   2

Definition at line 99 of file ccs811.c.

◆ READ_REG_INVALID

#define READ_REG_INVALID   1

Definition at line 100 of file ccs811.c.

◆ WRITE_REG_INVALID

#define WRITE_REG_INVALID   0

Definition at line 101 of file ccs811.c.

◆ DRIVE_MODE_BITS

#define DRIVE_MODE_BITS   4

Definition at line 104 of file ccs811.c.

◆ INT_DATARDY_BIT

#define INT_DATARDY_BIT   3

Definition at line 105 of file ccs811.c.

◆ INT_THRESH_BIT

#define INT_THRESH_BIT   2

Definition at line 106 of file ccs811.c.

◆ FW_MODE_BIT

#define FW_MODE_BIT   7

Definition at line 109 of file ccs811.c.

◆ APP_ERASE_BIT

#define APP_ERASE_BIT   6

Definition at line 110 of file ccs811.c.

◆ APP_VERIFY_BIT

#define APP_VERIFY_BIT   5

Definition at line 111 of file ccs811.c.

◆ APP_VALID_BIT

#define APP_VALID_BIT   4

Definition at line 112 of file ccs811.c.

◆ DATA_READY_BIT

#define DATA_READY_BIT   3

Definition at line 113 of file ccs811.c.

◆ ERROR_BIT

#define ERROR_BIT   0

Definition at line 114 of file ccs811.c.

◆ BUS_SPEED_100KHZ

#define BUS_SPEED_100KHZ   100000U

Definition at line 116 of file ccs811.c.

◆ ATTEMPTS_MAX

#define ATTEMPTS_MAX   10

Definition at line 117 of file ccs811.c.

◆ CCS811_ID

#define CCS811_ID   0x81

Definition at line 118 of file ccs811.c.

Function Documentation

◆ ccs811_read_byte()

uint8_t ccs811_read_byte ( uint8_t  reg)

Definition at line 286 of file ccs811.c.

287{
288 uint8_t byte;
289
290 i2c_start();
291 i2c_send(CCS811_ADDRESS_W);
292 i2c_send(reg);
293 i2c_start();
294 i2c_send(CCS811_ADDRESS_R);
295 byte = i2c_read_no_ack();
296 i2c_stop();
297 return byte;
298}
uint8_t i2c_read_no_ack(void)
Read in from slave, sending NOACK when done (no TWEA).
Definition: atmega_i2c.c:115
void i2c_stop(void)
Sends a stop condition (sets TWSTO).
Definition: atmega_i2c.c:80
void i2c_send(uint8_t data)
Loads data, sends it out, waiting for completion.
Definition: atmega_i2c.c:90
void i2c_start(void)
Sends a start condition (sets TWSTA).
Definition: atmega_i2c.c:70

◆ ccs811_burst_read()

void ccs811_burst_read ( uint8_t  reg,
uint8_t  length 
)

Definition at line 300 of file ccs811.c.

301{
302 i2c_start();
303 i2c_send(CCS811_ADDRESS_W);
304 i2c_send(reg);
305 i2c_start();
306 i2c_send(CCS811_ADDRESS_R);
307
308 for (uint8_t i = 0; i < length; ++i)
309 {
310 read_buffer[i] = i2c_read_ack();
311 }
312 i2c_stop();
313}
uint8_t i2c_read_ack(void)
Read in from slave, sending ACK when done (sets TWEA).
Definition: atmega_i2c.c:102

◆ ccs811_read_word()

uint16_t ccs811_read_word ( uint8_t  reg)

Definition at line 315 of file ccs811.c.

316{
317 uint16_t msb;
318 uint16_t byte;
319
320 i2c_start();
321 i2c_send(CCS811_ADDRESS_W);
322 i2c_send(reg);
323 i2c_start();
324 i2c_send(CCS811_ADDRESS_R);
325
326 msb = i2c_read_ack();
327 byte = i2c_read_no_ack();
328 byte |= (msb << 8);
329
330 return byte;
331}

◆ ccs811_write_byte()

void ccs811_write_byte ( uint8_t  reg,
uint8_t  byte 
)

Definition at line 277 of file ccs811.c.

278{
279 i2c_start();
280 i2c_send(CCS811_ADDRESS_W);
281 i2c_send(reg);
282 i2c_send(byte);
283 i2c_stop();
284}

◆ ccs811_get_status()

uint8_t ccs811_get_status ( void  )

Definition at line 271 of file ccs811.c.

272{
273 uint8_t status = ccs811_read_byte(STATUS_REG);
274 return status;
275}

◆ init_ccs811()

uint8_t init_ccs811 ( ccs811_config_t p_config)

Initialisation routine (run once at startup).

This function is to be called before any other functions in this file can be called. Instantiate the ccs811_config_t object first, then pass it's address into init_ccs811() to make config data available at file scope.

Parameters
p_configis a pointer to the ccs811_config_t object.
Returns
An error code is returned as an unsigned 8 bit integer.

Definition at line 133 of file ccs811.c.

134{
135 p_config_global = p_config; // Make a copy of pointer with file scope.
136 uint8_t ret = 0; // For return value
137 init_i2c(BUS_SPEED_100KHZ);
138 if (ccs811_read_byte(HW_ID_REG) == CCS811_ID)
139 {
140 uint8_t status = ccs811_get_status();
141 if (bit_is_set(status, APP_VALID_BIT))
142 {
143 i2c_start();
144 i2c_send(CCS811_ADDRESS_W);
145 i2c_send(APP_START);
146 i2c_stop();
147 _delay_ms(100);
148
149 uint8_t byte = 0;
150 byte |= (p_config_global->drive_mode << DRIVE_MODE_BITS);
151 byte |= (p_config_global->interrupt_dataready << INT_DATARDY_BIT);
152 byte |= (p_config_global->interrupt_threshold <<INT_THRESH_BIT);
153
154 for (uint8_t count = 0; count < ATTEMPTS_MAX; ++count)
155 {
156 ccs811_write_byte(MEAS_MODE_REG, byte);
157 _delay_ms(500);
158 uint8_t mode = ccs811_read_byte(MEAS_MODE_REG);
159 if (mode == byte)
160 {
161 break; // Success
162 }
163 if (count == (ATTEMPTS_MAX - 1))
164 {
165 ret = 3; // Max attempts reached
166 }
167 }
168 }
169 else
170 {
171 ret = 2; // Error - app invalid
172 }
173 }
174 else
175 {
176 ret = 1; // ccs81 ID failed
177 }
178 return ret;
179}
void init_i2c(uint32_t bus_speed)
Sets pullups and initializes i2c clock to desired bus speed.
Definition: atmega_i2c.c:49

◆ ccs811_get_eco2_level()

uint16_t ccs811_get_eco2_level ( void  )

Read eCO2 (equivalent carbon dioxide) level from sensor.

Once the data_ready flag is set, this function can be called.

Returns
eCO2 level in ppm is returned, ranging from (400 - 32768ppm).

Definition at line 182 of file ccs811.c.

183{
184 uint16_t data = ccs811_read_word(ALG_RESULT_DATA_REG);
185 return data;
186}

◆ ccs811_get_etvoc_level()

uint16_t ccs811_get_etvoc_level ( void  )

Read eTVOC (equivalent total volatile organic compounds) level from sensor.

Once the data_ready flag is set, this function can be called.

Returns
eTVOC level in ppb is returned, ranging from (0 - 32768ppb).

Definition at line 189 of file ccs811.c.

190{
191 uint8_t data = 0;
192 ccs811_burst_read(ALG_RESULT_DATA_REG, ETVOC_SIZE);
193 uint8_t msb = read_buffer[ETVOC_SIZE - 2];
194 data = read_buffer[ETVOC_SIZE - 1];
195 data |= (msb << 8);
196 return data;
197}

◆ ccs811_data_ready_check()

bool ccs811_data_ready_check ( void  )

Read the status register and check if the data ready flag is set.

Use this function to poll the data ready flag and call the getter functions above only when a new value is ready.

Returns
A boolean value of true is returned if flag is set, otherwise false is returned.

Definition at line 200 of file ccs811.c.

201{
202 bool ret = false;
203 uint8_t status = ccs811_get_status();
204 if (bit_is_set(status, DATA_READY_BIT))
205 {
206 ret = true;
207 }
208 return ret;
209}

◆ ccs811_get_alg_result_data()

void ccs811_get_alg_result_data ( void  )

Perform a read operation on all 8 bytes of ALG_RESULT_REGISTER.

The data is stored in the read_buffer[] array, and can be extracted using the register size definitions in the source file.

Definition at line 211 of file ccs811.c.

212{
213 ccs811_burst_read(ALG_RESULT_DATA_REG, ALG_RESULT_DATA_SIZE);
214}

◆ ccs811_update_env_data()

void ccs811_update_env_data ( uint8_t  humidity,
uint8_t  temp 
)

(Optional) Write environmental data from another sensor to the CCS811.

The sensor has the capability to use humidity and temperature data in a compensation formula to imporve the accuracy of it's readings.

Parameters
uint8_thumidity is the Relative Humidity % passed in as an integer.
uint8_ttemp is the temperature in degrees Celcius.

Definition at line 216 of file ccs811.c.

217{
218 uint8_t lsb = 0;
219
220 i2c_start();
221 i2c_send(CCS811_ADDRESS_W);
222 i2c_send(ENV_DATA_REG);
223 i2c_send(humidity << 1);
224 i2c_send(lsb);
225 i2c_send(((temp + 25) << 1));
226 i2c_send(lsb);
227 i2c_stop();
228}

◆ ccs811_error_to_string()

char * ccs811_error_to_string ( void  )

For error handling/logging.

If the error flag is set on the status register, call this function to turn the error code into a string message.

Parameters
char*pointer to the first element of the string is returned.

Definition at line 231 of file ccs811.c.

232{
233 char *msg;
234 uint8_t error = ccs811_read_byte(ERROR_ID_REG);
235 if (bit_is_set(error, HEATER_SUPPLY))
236 {
237 msg = "Heater Supply";
238 }
239 else if (bit_is_set(error, HEATER_FAULT))
240 {
241 msg = "Heater Fault";
242 }
243 else if (bit_is_set(error, MAX_RESISTANCE))
244 {
245 msg = "Max Resistance";
246 }
247 else if (bit_is_set(error, MEASMODE_INVALID))
248 {
249 msg = "Invalid Meas Mode";
250 }
251 else if (bit_is_set(error, READ_REG_INVALID))
252 {
253 msg = "Read Reg Invalid";
254 }
255 else if (bit_is_set(error, WRITE_REG_INVALID))
256 {
257 msg = "Write Reg Invalid";
258 }
259 else
260 {
261 msg = "Unknown Error";
262 }
263 return msg;
264}