Library for the AMS CC811 digitial gas sensor

Dependencies:   AMS_ENS210_temp_humid_sensor

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