Device driver for Si7020 Digital humidity and temperature sensor.

Dependents:   Si7020_example MAXWSNENV_sensors MAXWSNENV_sensors Hello-Uzuki-sensor-shield ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Si7020.cpp Source File

Si7020.cpp

00001 /*******************************************************************************
00002  * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a
00005  * copy of this software and associated documentation files (the "Software"),
00006  * to deal in the Software without restriction, including without limitation
00007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008  * and/or sell copies of the Software, and to permit persons to whom the
00009  * Software is furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included
00012  * in all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017  * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020  * OTHER DEALINGS IN THE SOFTWARE.
00021  *
00022  * Except as contained in this notice, the name of Maxim Integrated
00023  * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024  * Products, Inc. Branding Policy.
00025  *
00026  * The mere transfer of this software does not imply any licenses
00027  * of trade secrets, proprietary technology, copyrights, patents,
00028  * trademarks, maskwork rights, or any other form of intellectual
00029  * property whatsoever. Maxim Integrated Products, Inc. retains all
00030  * ownership rights.
00031  *******************************************************************************
00032  */
00033 
00034 #include "Si7020.h"
00035 
00036 /***** Definitions *****/
00037 #define I2C_ADDR    (0x80)  // 1000000x
00038 #define POLYVAL     (0x131)
00039 
00040 /***** File Scope Data *****/
00041 static const char cmd_meas_humid[] = { 0xE5 };
00042 static const char cmd_meas_humid_no_hold[] = { 0xF5 };
00043 static const char cmd_meas_temp[] = { 0xE3 };
00044 static const char cmd_meas_temp_no_hold[] = { 0xF3 };
00045 static const char cmd_meas_prev_temp[] = { 0xE0 };
00046 static const char cmd_rst[] = { 0xFE };
00047 static const char cmd_write_user1[] = { 0xE6 };
00048 static const char cmd_read_user1[] = { 0xE7 };
00049 static const char cmd_id_1[] = { 0xFA, 0x0F };
00050 static const char cmd_id_2[] = { 0xFC, 0xC9 };
00051 static const char cmd_fw_ver[] = { 0x84, 0xB8 };
00052 
00053 //******************************************************************************
00054 Si7020::Si7020(PinName sda, PinName scl)
00055 {
00056     i2c_ = new I2C(sda, scl);
00057     i2c_owner = true;
00058 
00059     // 400KHz, as specified by the datasheet.
00060     i2c_->frequency(400000);
00061 }
00062 
00063 //******************************************************************************
00064 Si7020::Si7020(I2C *i2c) :
00065     i2c_(i2c)
00066 {
00067     i2c_owner = false;
00068 }
00069 
00070 //******************************************************************************
00071 Si7020::~Si7020()
00072 {
00073     if(i2c_owner) {
00074         delete i2c_;
00075     }
00076 }
00077 
00078 //******************************************************************************
00079 int Si7020::reset(void)
00080 {
00081     if (i2c_->write(I2C_ADDR, cmd_rst, sizeof(cmd_rst)) != 0) {
00082         return -1;
00083     }
00084 
00085     return 0;
00086 }
00087 
00088 //******************************************************************************
00089 int Si7020::getElectronicId(char* id)
00090 {
00091     // Send cmd with repeated start
00092     if (i2c_->write(I2C_ADDR, cmd_id_1, sizeof(cmd_id_1), true) != 0) {
00093         return -1;
00094     }
00095 
00096     // Read first portion of ID
00097     char temp[8];
00098     if (i2c_->read(I2C_ADDR, temp, 8, false) != 0) {
00099         return -1;
00100     }
00101 
00102     // Check the CRC
00103     char crc = 0;
00104     int i;
00105     for(i = 0; i < 4; i++) {
00106         crc = crc8(temp[2*i], crc);
00107         if(crc != temp[2*i +1]) {
00108             return -1;
00109         }
00110     }
00111 
00112     // Save top portion of ID
00113     id[7] = temp [0];
00114     id[6] = temp [2];
00115     id[5] = temp [4];
00116     id[4] = temp [6];
00117 
00118     // Send cmd with repeated start
00119     if (i2c_->write(I2C_ADDR, cmd_id_2, sizeof(cmd_id_2), true) != 0) {
00120         return -1;
00121     }
00122 
00123     // Read rest of ID
00124     if (i2c_->read(I2C_ADDR, temp, 6, false) != 0) {
00125         return -1;
00126     }
00127 
00128     // Check the CRC
00129     crc = 0;
00130     for(i = 0; i < 2; i++) {
00131         crc = crc8(temp[3*i], crc);
00132         crc = crc8(temp[3*i + 1], crc);
00133         if(crc != temp[3*i + 2]) {
00134             return -1;
00135         }
00136     }
00137 
00138     // Save bottom portion of ID
00139     id[3] = temp [0];
00140     id[2] = temp [1];
00141     id[1] = temp [3];
00142     id[0] = temp [4];
00143 
00144     return 0;
00145 }
00146 
00147 //******************************************************************************
00148 int Si7020::configResolution(Si7020::resolution_t resolution)
00149 {
00150     char data[2];
00151 
00152     if (i2c_->write(I2C_ADDR, cmd_read_user1, sizeof(cmd_read_user1)) != 0) {
00153         return -1;
00154     }
00155 
00156     if (i2c_->read(I2C_ADDR, &data[1], 1) != 0) {
00157         return -1;
00158     }
00159 
00160     switch (resolution) {
00161         case RH_12b_TEMP_14b:
00162             data[1] &= ~0x81;
00163             break;
00164         case RH_8b_TEMP_12b:
00165             data[1] = (data[1] & ~0x80) | 0x01;
00166             break;
00167         case RH_10b_TEMP_13b:
00168             data[1] = (data[1] & ~0x01) | 0x80;
00169             break;
00170         case RH_11b_TEMP_11b:
00171             data[1] |= 0x81;
00172             break;
00173         default:
00174             return -1;
00175     }
00176 
00177     data[0] = cmd_write_user1[0];
00178 
00179     if (i2c_->write(I2C_ADDR, data, 2) != 0) {
00180         return -1;
00181     }
00182 
00183     return 0;
00184 }
00185 
00186 //******************************************************************************
00187 int Si7020::getTemperature(int16_t *tempCx10)
00188 {
00189     if (i2c_->write(I2C_ADDR, cmd_meas_temp, sizeof(cmd_meas_temp)) != 0) {
00190         return -1;
00191     }
00192 
00193     return checkTemperature(tempCx10);
00194 }
00195 
00196 //******************************************************************************
00197 int Si7020::getTemperature(float *tempC)
00198 {
00199     if (i2c_->write(I2C_ADDR, cmd_meas_temp, sizeof(cmd_meas_temp)) != 0) {
00200         return -1;
00201     }
00202 
00203     return checkTemperature(tempC);
00204 }
00205 
00206 //******************************************************************************
00207 int Si7020::startTemperature(void)
00208 {
00209     if (i2c_->write(I2C_ADDR, cmd_meas_temp_no_hold, sizeof(cmd_meas_temp_no_hold)) != 0) {
00210         return -1;
00211     }
00212 
00213     return 0;
00214 }
00215 
00216 //******************************************************************************
00217 int Si7020::checkTemperature(int16_t *tempCx10)
00218 {
00219     char data[3];
00220     uint16_t code;
00221     int temp;
00222 
00223     if (i2c_->read(I2C_ADDR, data, 3) != 0) {
00224         return -1;
00225     }
00226 
00227     // Get 16-bit value from bytes read
00228     code = ((uint16_t)data[0] << 8) + data[1];
00229 
00230     // Calculate the temperature using the formula from the datasheet
00231     // Scaled by 100
00232     temp = ((((int)17572 * code) + 0x8000) >> 16) - 4685;
00233 
00234     // Return value is to be scaled by 10
00235     *tempCx10 = (temp + 5) / 10;
00236     
00237     return 0;
00238 }
00239 
00240 //******************************************************************************
00241 int Si7020::checkTemperature(float *tempC)
00242 {
00243     char data[3];
00244     uint16_t code;
00245 
00246     if (i2c_->read(I2C_ADDR, data, 3) != 0) {
00247         return -1;
00248     }
00249 
00250     // Get 16-bit value from bytes read
00251     code = ((uint16_t)data[0] << 8) + data[1];
00252 
00253     // Calculate the temperature using the formula from the datasheet
00254     // Scaled by 100
00255     *tempC = ((175.72f * (float)code) / 65536.0f) - 46.85f;
00256 
00257     return 0;
00258 }
00259 
00260 //******************************************************************************
00261 int Si7020::getHumidity(int16_t *humidx10)
00262 {
00263     if (i2c_->write(I2C_ADDR, cmd_meas_humid, sizeof(cmd_meas_humid), true) != 0) {
00264         return -1;
00265     }
00266 
00267     return checkHumidity(humidx10);
00268 }
00269 
00270 //******************************************************************************
00271 int Si7020::getHumidity(float *humid)
00272 {
00273     if (i2c_->write(I2C_ADDR, cmd_meas_humid, sizeof(cmd_meas_humid)) != 0) {
00274         return -1;
00275     }
00276 
00277     return checkHumidity(humid);
00278 }
00279 
00280 //******************************************************************************
00281 int Si7020::startHumidity(void)
00282 {
00283     if (i2c_->write(I2C_ADDR, cmd_meas_humid_no_hold, sizeof(cmd_meas_humid_no_hold)) != 0) {
00284         return -1;
00285     }
00286 
00287     return 0;
00288 }
00289 
00290 //******************************************************************************
00291 int Si7020::checkHumidity(int16_t *humidx10)
00292 {
00293     char data[3];
00294     uint16_t code;
00295 
00296     if (i2c_->read(I2C_ADDR, data, 3) != 0) {
00297         return -1;
00298     }
00299 
00300     // Get 16-bit value from bytes read
00301     code = ((uint16_t)data[0] << 8) + data[1];
00302 
00303     // Calculate the humidity using the formula from the datasheet
00304     // Scaled by 10
00305     *humidx10 = ((((int)1250 * code) + 0x8000) >> 16) - 60;
00306 
00307     // Check the crc
00308     char crc = crc8(data[0], 0x00);
00309     crc = crc8(data[1], crc);
00310     if(crc != data[2]) {
00311         return -1;
00312     }
00313 
00314     return 0;
00315 }
00316 
00317 //******************************************************************************
00318 int Si7020::checkHumidity(float *humid)
00319 {
00320     char data[3];
00321     uint16_t code;
00322 
00323     if (i2c_->read(I2C_ADDR, data, 3) != 0) {
00324         return -1;
00325     }
00326 
00327     // Get 16-bit value from bytes read
00328     code = ((uint16_t)data[0] << 8) + data[1];
00329 
00330     // Calculate the humidity using the formula from the datasheet
00331     *humid = ((125.0f * (float)code) / 65536.0f) - 6.0f;
00332 
00333     return 0;
00334 }
00335 
00336 //******************************************************************************
00337 int Si7020::getPrevTemperature(float *tempC) {
00338 
00339     if (i2c_->write(I2C_ADDR, cmd_meas_prev_temp, sizeof(cmd_meas_prev_temp)) != 0) {
00340         return -1;
00341     }
00342 
00343     if(checkTemperature(tempC) != 0) {
00344         return -1;
00345     }
00346 
00347     return 0;
00348 }
00349 
00350 //******************************************************************************
00351 int Si7020::getPrevTemperature(int16_t *tempCx10) {
00352 
00353     if (i2c_->write(I2C_ADDR, cmd_meas_prev_temp, sizeof(cmd_meas_prev_temp)) != 0) {
00354         return -1;
00355     }
00356 
00357     if(checkTemperature(tempCx10) != 0) {
00358         return -1;
00359     }
00360 
00361     return 0;
00362 }
00363 
00364 //******************************************************************************
00365 int Si7020::getRev(char *rev)
00366 {
00367     if (i2c_->write(I2C_ADDR, cmd_fw_ver, sizeof(cmd_fw_ver)) != 0) {
00368         return -1;
00369     }
00370 
00371     if (i2c_->read(I2C_ADDR, rev, 1) != 0) {
00372         return -1;
00373     }
00374     
00375     return 0;
00376 }
00377 
00378 //******************************************************************************
00379 int Si7020::heater(bool enable)
00380 {
00381     char data[2];
00382 
00383     if (i2c_->write(I2C_ADDR, cmd_read_user1, sizeof(cmd_read_user1)) != 0) {
00384         return -1;
00385     }
00386 
00387     if (i2c_->read(I2C_ADDR, &data[1], 1) != 0) {
00388         return -1;
00389     }
00390 
00391     if (enable) {
00392         data[1] |= 0x04;
00393     } else {
00394         data[1] &= ~0x04;
00395     }
00396 
00397     data[0] = cmd_write_user1[0];
00398 
00399     if (i2c_->write(I2C_ADDR, data, 2) != 0) {
00400         return -1;
00401     }
00402 
00403     return 0;
00404 }
00405 
00406 //******************************************************************************
00407 char Si7020::crc8(char value, char seed)
00408 {
00409     int i;
00410 
00411     for (i = 0; i < 8; i++) {
00412 
00413         if ((value ^ seed) & 0x80) {
00414             seed <<= 1;
00415             seed ^= POLYVAL;
00416         } else {
00417             seed <<= 1;
00418         }
00419 
00420         value <<= 1;
00421     }
00422 
00423     return seed;
00424 }