Silicon Labs Si7021-A20 device driver: I2C Humidity and Temperature Sensor

SI7021.h

Committer:
ninensei
Date:
2017-09-14
Revision:
1:344923bddd4f

File content as of revision 1:344923bddd4f:

/* mbed Microcontroller Library
 * Copyright (c) 2017 AT&T, IIoT Foundry, Plano, TX, USA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** \addtogroup drivers */

/** Support for Silicon Labs SI7021 temperature and humidity sensor
 *
 * Example:
 * @code
 *
 * #include "mbed.h"
 * #include "SI7021.h"
 *
 * I2C          i2c(I2C_SDA, I2C_SCL);
 * SI7021<I2C>  si7021(&i2c);
 *
 * int main() {
 *     si7021_measurements_t  data;
 *     bool                   ok;
 *
 *     ok = si7021->read(&data);
 *           
 *     if (ok) {
 *         printf("%%RelHum: %f\r\n", data.humidity_PR);
 *         printf("temp C/F: %f/%f\r\n", data.temp_C, data.temp_C * 9 / 5 + 32);
 *     } else {
 *         printf("si7021 error!\r\n");
 *     }
 * }
 * @endcode
 * @ingroup drivers
 */

#pragma once

#define SI7021A20_I2C_ADDR              0x80

#define SI7021A20_CMD_MEAS_RH_HMM       0xE5
#define SI7021A20_CMD_MEAS_RH_NHMM      0xF5
#define SI7021A20_CMD_MEAS_TEMP_HMM     0xE3
#define SI7021A20_CMD_MEAS_TEMP_NHMM    0xF3
#define SI7021A20_CMD_READ_TEMP         0xE0
#define SI7021A20_CMD_RESET             0xFE
#define SI7021A20_CMD_WRITE_USER1       0xE6
#define SI7021A20_CMD_WRITE_USER2       0xE7
#define SI7021A20_CMD_WRITE_HEAT_CTRL   0x51
#define SI7021A20_CMD_READ_HEAT_CTRL    0x11
#define SI7021A20_CMD_READ_ID1          0xFA0F
#define SI7021A20_CMD_READ_ID2          0xFCC9
#define SI7021A20_REGF_ID2_DEV_ID               0x15
#define SI7021A20_CMD_READ_FW_REV       0x84B8

typedef struct {
    float       temp_C;
    float       humidity_PR;
} si7021_measurements_t;

template <class T>
class SI7021 {
 public:
    /**
    * Constructor
    *
    * @param i2c I2C class servicing the strip
    */
    SI7021(T * i2c) : _i2c(i2c) {}

    /**
    * Read temperature and humidity
    *
    * @param data points to struct to store measurements in.  Stucture is
    *      valid only when function returns success indication.
    *
    * @returns true (success) or false (failure)
    */
    bool read(si7021_measurements_t * data) {
        bool    ok;
        union {
            char    cmd;
            struct {
                uint8_t  meas_msb;
                uint8_t  meas_lsb;
            };
        } buff;
        
        buff.cmd = SI7021A20_CMD_MEAS_RH_HMM;
        ok = (_i2c_transfer(SI7021A20_I2C_ADDR, &buff, 1, 2));
        if (ok) {
            // Humidity% = measurement * 125/65536 - 6
            int meas_raw        = ((int)buff.meas_msb << 8) + buff.meas_lsb;
            data->humidity_PR   = (float)meas_raw * (125.0F/65536.0F) - 6.0F;
        
            buff.cmd = SI7021A20_CMD_READ_TEMP;
            ok = _i2c_transfer(SI7021A20_I2C_ADDR, &buff, 1, 2);
        }
        if (ok) {
            // TempC = measurement * 175.72/65536 - 46.85
            int meas_raw    = ((int)buff.meas_msb << 8) + buff.meas_lsb;
            data->temp_C    = meas_raw * (175.72/65536.0) - 46.85;
         }
        return ok;
    }    

 protected:

    /**
    * I2C read/write helper function
    *
    * @param address is the register to read/write
    * @param buff holds the data to write and recieves the data to read
    * @param writeSize is the number of bytes to write to register
    * @param readSize is the number of bytes to retrieve from device
    *
    * @returns true (success) or false (failure)
    */
    bool _i2c_transfer(int address, void * buff, size_t writeSize, size_t readSize) {
        bool ok;
        bool expect_response = (readSize != 0);
    
        ok = !_i2c->write(address, (char*)buff, writeSize, expect_response);
        if (ok && expect_response)
            ok = !_i2c->read(address, (char*)buff, readSize);
    
        return ok;
    }
    

    T  *_i2c;
};