simple CCS811 driver

Dependencies:   AMS_ENS210_temp_humid_sensor

Dependents:   TBSense2_Sensor_Demo

Fork of AMS_CCS811_gas_sensor by Marcus Lee

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AMS_CCS811.h Source File

AMS_CCS811.h

00001 /**
00002 * @author Marcus Lee
00003 *
00004 * @section DESCRIPTION
00005 *    A library for the AMS CCS811 digital gas sensor.
00006 *
00007 */
00008 #ifndef AMS_CCS811_H
00009 #define AMS_CCS811_H
00010 
00011 #include "mbed.h"
00012 #include "AMS_ENS210.h"
00013 
00014 /* Library defaults */
00015 #define CONFIG_OP_MODE              TEN_SECOND              // Every 10 seconds
00016 #define CONFIG_INTR                 0                       // Interupt off
00017 #define CONFIG_ADDR_DIR             0                       // ADDR n_wake_pin pulled low
00018 #define CONFIG_ENS210_POLL          3000                    // ENS210 is polled every 3 seconds
00019 
00020 /* Library Constants */
00021 #define CCS811_SLAVE_ADDR_RAW_H     0x5B
00022 #define CCS811_SLAVE_ADDR_RAW_L     0x5A
00023 #define CCS811_SLAVE_ADDR_RAW       _slave_addr
00024 #define CCS811_SLAVE_ADDR           CCS811_SLAVE_ADDR_RAW << 1
00025 #define CCS811_SLAVE_ADDR_W         CCS811_SLAVE_ADDR
00026 #define CCS811_SLAVE_ADDR_R         CCS811_SLAVE_ADDR | 1
00027 
00028 #define MEAS_MODE                   0x01
00029 #define STATUS                      0x00
00030 
00031 #define ALG_RESULT_DATA             0x02
00032 #define RAW_DATA                    0x03
00033 #define ENV_DATA                    0x05
00034 #define ERROR_ID                    0xE0
00035 
00036 #define HW_ID                       0x20
00037 #define HW_VERSION                  0x21
00038 #define FW_BOOT_VERSION             0x23
00039 #define FW_APP_VERSION              0x24
00040 #define FW_ERASE                    0xF1
00041 #define FW_FLASH                    0xF2
00042 #define FW_VERIFY                   0xF3
00043 #define APP_START                   0xF4
00044 
00045 #define CCS811_T_AWAKE              55                      // us - time taken for sensor I2C to become active
00046 #define CCS811_T_DWAKE              25                      // us - time taken for sensor I2C to become inactive
00047 
00048 #define CCS811_MAX_HUMID            127.998046875           // maxmium value that can be represented in the register
00049 #define CCS811_MAX_TEMP             102.998046875           // maxmium value that can be represented in the register
00050 
00051 /* Error Codes */
00052 #define CCS811_NO_ERROR             "No Error";
00053 /* Sensor Errors */
00054 #define CCS811_ERR_NUM              8
00055 #define CCS811_WRITE_REG_INVALID    "The CCS811 received an I2C write request addressed to this station but with invalid register address ID"
00056 #define CCS811_READ_REG_INVALID     "The CCS811 received an I2C read request to a mailbox ID that is invalid"
00057 #define CCS811_MEASMODE_INVALID     "The CCS811 received an I2C request to write an unsupported mode to MEAS_MODE"
00058 #define CCS811_MAX_RESISTANCE       "The sensor resistance measurement has reached or exceeded the maximum range"
00059 #define CCS811_HEATER_FAULT         "The Heater current in the CCS811 is not in range"
00060 #define CCS811_HEATER_SUPPLY        "The Heater voltage is not being applied correctly"
00061 #define CCS811_RESERVED             "Reserved for Future Use"
00062 /* Library Errors */
00063 #define CCS811_LIB_ERR_NUM          9
00064 #define CCS811_LIB_N_WAKE_ID        0
00065 #define CCS811_LIB_N_WAKE           "nWAKE pin not set"
00066 #define CCS811_LIB_I2C_ID           1
00067 #define CCS811_LIB_I2C              "I2C interface is NULL"
00068 #define CCS811_LIB_SLAVE_W_ID       2
00069 #define CCS811_LIB_SLAVE_W          "Failed to write slave write address"
00070 #define CCS811_LIB_REG_ADDR_ID      3
00071 #define CCS811_LIB_REG_ADDR         "Failed to write register address"
00072 #define CCS811_LIB_I2CWRITE_ID      4
00073 #define CCS811_LIB_I2CWRITE         "Failed to write byte"
00074 #define CCS811_LIB_SLAVE_R_ID       5
00075 #define CCS811_LIB_SLAVE_R          "Failed to write slave read address"
00076 #define CCS811_LIB_INV_MODE_ID      6
00077 #define CCS811_LIB_INV_MODE         "Invalid operation mode"
00078 #define CCS811_LIB_ENS210_INIT_ID   7
00079 #define CCS811_LIB_ENS210_INIT      "Failed to create new AMS_ENS210 object"
00080 #define CCS811_LIB_ENS210_POLL_ID   7
00081 #define CCS811_LIB_ENS210_POLL      "AMS_ENS210 poll error"
00082 
00083 #define CCS811_TOTAL_ERR_NUM        CCS811_ERR_NUM+CCS811_LIB_ERR_NUM
00084 
00085 
00086 /** The AMS CCS811 class
00087  */
00088 class AMS_CCS811
00089 {
00090     public:
00091         /** Sensor operation modes.
00092          *
00093          */
00094         enum OP_MODES {
00095             IDLE,           /**< Measurements disabled */
00096             SECOND,         /**< Measurement every second */
00097             TEN_SECOND,     /**< Measurement every 10 seconds */
00098             SIXTY_SECOND,   /**< Measurement every 60 seconds */
00099             CONSTANT,       /**< Measurement every 250ms - Only raw data available */
00100             INVALID         /**< Invalid bit configuration/Error Occured */
00101         };
00102 
00103         /** Holds error information.
00104          *
00105          */
00106         struct ccs811_errors {
00107             int count;                          /**< Number of total errors */
00108             int codes[CCS811_TOTAL_ERR_NUM];    /**< Array of active error codes */
00109 
00110             ccs811_errors() : count(0) {}
00111         };
00112 
00113         /** Create an AMS_CCS811 instance
00114          *
00115          * @param i2c           The I2C interface to use for communication
00116          * @param n_wake_pin    Pin nWAKE is attached to
00117          */
00118         AMS_CCS811(I2C * i2c, PinName n_wake_pin);
00119 
00120         /** Create an AMS_CCS811 instance
00121          *
00122          * @param i2c           The I2C interface to use for communication
00123          * @param n_wake_pin    Pin nWAKE is attached to
00124          * @param ens210_i2c    The I2C interface for an attached AMS_ENS210
00125          */
00126         AMS_CCS811(I2C * i2c, PinName n_wake_pin, I2C * ens210_i2c);
00127 
00128         /** Destroy the AMS_CCS811 instance
00129          */
00130         ~AMS_CCS811();
00131 
00132         /** Initalise the sensor
00133          *
00134          * @return Intalisation success
00135          */
00136         bool init();
00137 
00138         /** Overwrite the sensor's firmware
00139          *
00140          * @return upload success
00141          */
00142         bool flash_firmware();
00143 
00144         /** Set the I2C interface
00145          *
00146          * @param i2c  The I2C interface to use for communication
00147          *
00148          */
00149         void i2c_interface(I2C * i2c);
00150 
00151         /** Set the ENS210 I2C interface
00152          *
00153          * @param i2c  The I2C interface for an attached AMS_ENS210
00154          *
00155          * @return Success
00156          */
00157         bool ens210_i2c_interface(I2C * i2c);
00158 
00159         /** Set whether the attached AMS_ENS210 is enabled.
00160          *  If an I2C interface is not set for the ENS210, calling this method will have no effect.
00161          *
00162          * @param enabled   True for enabled, false for disabled
00163          *
00164          * @return enabled  True for enabled, false for disabled
00165          */
00166         bool enable_ens210(bool enable);
00167 
00168         /** Get whether the attached AMS_ENS210 is enabled.
00169          *
00170          * @return enabled    True for enabled, false for disabled
00171          *
00172          */
00173         bool ens210_is_enabled();
00174 
00175         /** Set the AMS_ENS210 poll interval
00176          *
00177          * @param poll_ms  Poll interval in ms
00178          *
00179          */
00180         void ens210_poll_interval(int poll_ms);
00181 
00182         /** Get the AMS_ENS210 poll interval
00183          *
00184          * @return The poll interval in ms
00185          */
00186         int ens210_poll_interval();
00187 
00188         /** Get the current firmware mode
00189          *
00190          * @return 1 application mode, 0 for boot mode, -1 for error
00191          */
00192         int firmware_mode();
00193 
00194         /** Set the operation mode \n
00195          * Notes: \n 1.\ When a sensor operating mode is changed to a new mode with\n
00196          *          a lower sample rate (e.g.\ from SECOND to SIXTY_SECOND), it should be\n
00197          *          placed in IDLE for at least 10 minutes before enabling the new mode.\ \n
00198          *          When a sensor operating mode is changed to a new mode with a higher\n
00199          *          sample rate (e.g.\ from SIXTY_SECOND to SECOND), there is no requirement\n
00200          *          to wait before enabling the new mode.\ \n
00201          *  2.\ If this method fails, the state of the config register cannot be guaranteed.\ \n
00202          *  Check errors and ensure all config settings are as expected.
00203          *
00204          * @param mode  OP_MODES mode to set
00205          *
00206          * @return Write success
00207          */
00208         bool mode(OP_MODES mode);
00209 
00210         /** Get the current power mode
00211          *
00212          * @return The current OP_MODES mode
00213          */
00214         AMS_CCS811::OP_MODES mode();
00215 
00216         /** Set the ADDR mode \n
00217          *
00218          * @param high  True sets to high, false to low
00219          *
00220          * @return Write success
00221          */
00222         bool addr_mode(bool high);
00223 
00224         /** Get the the ADDR mode
00225          *
00226          * @return The current ADDR mode, true for high, false for low
00227          */
00228         bool addr_mode();
00229 
00230         /** Set the ADDR pin
00231          *
00232          * @param pin    Pin ADDR is attached to
00233          *
00234          * @return Write success
00235          */
00236         bool addr_pin(PinName pin);
00237 
00238         /** Get the the ADDR pin
00239          *
00240          * @return The addr pin
00241          */
00242         PinName addr_pin();
00243 
00244         /** Set the nWAKE pin
00245          *
00246          * @param pin    Pin nWAKE is attached to
00247          *
00248          * @return Write success
00249          */
00250         bool n_wake_pin(PinName pin);
00251 
00252         /** Get the the nWAKE pin
00253          *
00254          * @return The nWAKE pin
00255          */
00256         PinName n_wake_pin();
00257 
00258         /** Set the relative humidity (%) and temperature (C).\ \n
00259          *  Use when AMS ENS210 is not linked.\ \n
00260          *  Humidity values are clipped between 0 and CCS811_MAX_HUMID.\ \n
00261          *  Temperature values are clipped between -25 and CCS811_MAX_TEMP.
00262          *
00263          * @return Write success
00264          */
00265         bool env_data(float humid, float temp);
00266 
00267         /** Get the sensor collection state
00268          *  Use when interrupts are disabled.
00269          *
00270          * @return Current collection state, 1 for new data ready, 0 for data not ready and -1 for error
00271          */
00272         int has_new_data();
00273 
00274         /** Get the most recent CO2 measurement.\ \n
00275          *  Must call has_new_data() first when when interupts are disabled otherwise the same data will be returned
00276          *
00277          * @return Most recent eCO2 measurement in ppm
00278          */
00279         uint16_t co2_read();
00280 
00281         /** Get the most recent TVOC measurement.\ \n
00282          *  Must call has_new_data() first when when interupts are disabled otherwise the same data will be returned
00283          *
00284          * @return Most recent TVOC measurement in ppb
00285          */
00286         uint16_t tvoc_read();
00287 
00288         /** Get the most recent RAW data.\ \n
00289          *  Must call has_new_data() first when NOT in CONSTANT mode and interupts are disabled otherwise the same data will be returned.\ \n
00290          *  When in CONSTANT mode only this read method will return anything other than 0 or NULL.\ If 0 is returned, check for errors.
00291          *
00292          * @return Most recent RAW data
00293          */
00294         uint16_t raw_read();
00295 
00296         /** Get the most recent Tempurature(C) measurement from the ENS210 (if attached and enabled).\ \n
00297          *  Will be at most as old as the ENS210 poll time
00298          *
00299          * @return Most recent Tempurature(C) measurement from the ENS210
00300          */
00301         float temp_read();
00302 
00303         /** Get the most recent Relative Humidity(%) measurement from the ENS210 (if attached and enabled).\ \n
00304          *  Will be at most as old as the ENS210 poll time
00305          *
00306          * @return Most recent Relative Humidity(%) measurement from the ENS210
00307          */
00308         float humid_read();
00309 
00310         /** Get current error status
00311          *
00312          * @return True when error has occured, false when no error has occured
00313          */
00314         bool error_status();
00315 
00316         /** Get the latest errors.
00317          *
00318          * @return Latest errors.
00319          */
00320         ccs811_errors errors();
00321 
00322         /** Get the error string.
00323          *
00324          * @param err_code  Error code to be translated
00325          *
00326          * @return Error String.
00327          */
00328         const char * error_string(int err_code);
00329 
00330         /** Attach a function to be called when data is ready.
00331          *  Calling this method enables interupts
00332          *
00333          * @param func_ptr  A pointer to the function to be called
00334          * @param pin       Pin attached to nINT
00335          *
00336          * @return Attach success
00337          */
00338         bool attach(void (*func_ptr)(void), PinName pin) {
00339             _isr_data_fp.attach(func_ptr);
00340             interrupt_pin(pin);
00341             return enable_interupt(true);
00342         }
00343 
00344         /** Attach a member function to be called when data is ready.
00345          *  Calling this method enables interupts
00346          *
00347          * @param type_ptr  A pointer to the instance of the class
00348          * @param mem_ptr   A pointer to the member function
00349          * @param pin       Pin attached to nINT
00350          *
00351          * @return Attach success
00352          */
00353         template<typename T>
00354         bool attach(T *type_ptr, void (T::*mem_ptr)(void), PinName pin) {
00355             _isr_data_fp.attach(callback(type_ptr, mem_ptr));
00356             interrupt_pin(pin);
00357             return enable_interupt(true);
00358         }
00359 
00360         /** Set whether the data ready interupt is enabled.\ \n
00361          *  Note: If this method fails, the state of the config register cannot be guaranteed.\ \n
00362          *  Check errors and ensure all config settings are as expected.
00363          *
00364          * @param enabled    True for enabled, false for disabled
00365          *
00366          * @return Write success
00367          */
00368         bool enable_interupt(bool enable);
00369 
00370         /** Get whether the data ready interupt is enabled.
00371          *
00372          *
00373          * @return 1 for enabled, 0 for disabled, -1 for error
00374          */
00375         int interupt_enabled();
00376 
00377         /** Set the nINT pin
00378          *
00379          * @param pin    Pin nINT is attached to
00380          *
00381          * @return Write success
00382          */
00383         bool interrupt_pin(PinName pin);
00384 
00385         /** Get the the nINT pin
00386          *
00387          * @return The nINT pin
00388          */
00389         PinName interrupt_pin();
00390 
00391 
00392 
00393 
00394     private:
00395         I2C* _i2c;
00396 
00397         bool _addr_dir;
00398         int _slave_addr;
00399         void update_slave_addr();
00400 
00401         AMS_ENS210 *_ens210;
00402         bool _ens210_enabled;
00403         int _ens210_poll_split;
00404         void update_ens210_timer();
00405         Ticker _ens210_poll_t;
00406         void ens210_isr();
00407         float temp_reading;
00408         float humid_reading;
00409 
00410         float fractions[9];
00411         void _init_fractions();
00412         void float_to_short(float in, char * output);
00413 
00414         OP_MODES _mode;
00415 
00416         void set_defaults();
00417 
00418         bool _errors[CCS811_LIB_ERR_NUM];
00419         int _error_count;
00420         char _error_strings[CCS811_TOTAL_ERR_NUM][255];
00421         void _init_errors();
00422         void clear_errors();
00423         void new_error(int error_id);
00424 
00425         DigitalOut *_n_wake_out;
00426         DigitalOut *_addr_out;
00427 
00428         char _alg_result_data[8];
00429 
00430         FunctionPointer _isr_data_fp;
00431         bool _int_data_enabled;
00432         InterruptIn *_int_data;
00433         void _isr_data();
00434 
00435         bool write_config();
00436 
00437         struct read_byte_result {
00438             bool success;
00439             uint8_t byte;
00440             read_byte_result() : success(false), byte(0) {}
00441         };
00442         read_byte_result read_config();
00443         read_byte_result read_status();
00444 
00445         bool boot_app_start();
00446 
00447         int i2c_read(char reg_addr, char* output, int len);
00448         int i2c_write(char reg_addr, char* input, int len);
00449 
00450 };
00451 
00452 
00453 #endif /* AMS_CCS811_H */