Steve Martin / libdev_si7210
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SI7210.h Source File

SI7210.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 AT&T, IIoT Foundry, Plano, TX, USA
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 /** \addtogroup drivers */
00018 
00019 /** Support for Silicon Labs SI7210: Magnetic field and temperature sensor
00020  *
00021  * Example:
00022  * @code
00023  *
00024  * #include "mbed.h"
00025  * #include "SI7210.h"
00026  *
00027  * I2C          i2c(I2C_SDA, I2C_SCL);
00028  * SI7210<I2C>  si7210(&i2c, SI7210_BASE_ADDR_7BIT);
00029  *
00030  * int main() {
00031  *     si7210_measurements_t  data;
00032  *     bool                   ok;
00033  *
00034  *     ok = si7210.enable() &&
00035  *          si7210.read(&data) &&
00036  *          si7210.disable();
00037  *
00038  *     if (ok) {
00039             printf("Mag T: %f\r\n", data.mag_T);
00040             printf("temp C/F: %f/%f\r\n", data.temp_C, data.temp_C * 9 / 5 + 32);
00041  *     } else {
00042  *         printf("si7210 error!\r\n");
00043  *     }
00044  * }
00045  * @endcode
00046  * @ingroup drivers
00047  */
00048 
00049 #pragma once
00050 
00051 #define ARAUTOINC__ARAUTOINC_MASK       0x01
00052 #define OTP_CTRL__OPT_BUSY_MASK         0x01
00053 #define OTP_CTRL__OPT_READ_EN_MASK      0x02
00054 #define POWER_CTRL__SLEEP_MASK          0x01
00055 #define POWER_CTRL__STOP_MASK           0x02
00056 #define POWER_CTRL__ONEBURST_MASK       0x04
00057 #define POWER_CTRL__USESTORE_MASK       0x08
00058 #define POWER_CTRL__MEAS_MASK           0x80
00059 #define DSPSIGSEL__MAG_VAL_SEL          0
00060 #define DSPSIGSEL__TEMP_VAL_SEL         1
00061 
00062 /** I2C registers for Si72xx */
00063 #define SI72XX_OTP_TEMP_OFFSET  0x1D
00064 #define SI72XX_OTP_TEMP_GAIN    0x1E
00065 #define SI72XX_HREVID           0xC0
00066 #define SI72XX_DSPSIGM          0xC1
00067 #define SI72XX_DSPSIGL          0xC2
00068 #define SI72XX_DSPSIGSEL        0xC3
00069 #define SI72XX_POWER_CTRL       0xC4
00070 #define SI72XX_ARAUTOINC        0xC5
00071 #define SI72XX_CTRL1            0xC6
00072 #define SI72XX_CTRL2            0xC7
00073 #define SI72XX_SLTIME           0xC8
00074 #define SI72XX_CTRL3            0xC9
00075 #define SI72XX_A0               0xCA
00076 #define SI72XX_A1               0xCB
00077 #define SI72XX_A2               0xCC
00078 #define SI72XX_CTRL4            0xCD
00079 #define SI72XX_A3               0xCE
00080 #define SI72XX_A4               0xCF
00081 #define SI72XX_A5               0xD0
00082 #define SI72XX_OTP_ADDR         0xE1
00083 #define SI72XX_OTP_DATA         0xE2
00084 #define SI72XX_OTP_CTRL         0xE3
00085 #define SI72XX_TM_FG            0xE4
00086 
00087 #define SI7210_BASE_ADDR_7BIT   0x30
00088 
00089 typedef struct {
00090     float       mag_T;
00091     float       temp_C;
00092 } si7210_measurements_t;
00093 
00094 template <class T>
00095 class SI7210 {
00096  public:
00097     /**
00098     * Constructor
00099     *
00100     * @param i2c I2C class servicing the strip
00101     */
00102     SI7210(T * i2c, uint8_t addr_7bit) : _i2c(i2c) {
00103         _isTempOffsetAndGainValid = false;
00104         _enabled = false;
00105         _addr_8bit = ((addr_7bit & 0x3) + SI7210_BASE_ADDR_7BIT) << 1;
00106     }
00107 
00108     /**
00109     * Activate the sensor (wake if sleeping).
00110     *
00111     * @returns true (success) or false (failure)
00112     */
00113     bool enable(void) {
00114         bool ok = _i2c_transfer(_addr_8bit, NULL, 0, 0);
00115         if (ok)
00116             _enabled = true;
00117         return ok;
00118     }
00119 
00120     /**
00121     * Deactivate the sensor (puts it to sleep)
00122     *
00123     * @returns true (success) or false (failure)
00124     */
00125     bool disable(void) {
00126         bool ok = _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__SLEEP_MASK);
00127         if (ok)
00128             _enabled = ok;
00129         return ok;
00130     }
00131 
00132     /**
00133     * Read temperature and humidity
00134     *
00135     * @param data points to struct to store measurements in.  Stucture is
00136     *      valid only when function returns success indication.
00137     *
00138     * @returns true (success) or false (failure)
00139     */
00140     bool read(si7210_measurements_t * data) {
00141         uint16_t    magRaw;
00142         uint16_t    tempRaw;
00143 
00144         bool ok = _write_reg(SI72XX_ARAUTOINC, ARAUTOINC__ARAUTOINC_MASK)
00145                && _write_reg(SI72XX_DSPSIGSEL, DSPSIGSEL__MAG_VAL_SEL)      //capture mag field measurement
00146                && _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__ONEBURST_MASK)
00147                && _read_regs(SI72XX_DSPSIGM, 2, &magRaw)
00148                && _write_reg(SI72XX_DSPSIGSEL, DSPSIGSEL__TEMP_VAL_SEL)     //capture temp measurement
00149                && _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__ONEBURST_MASK)
00150                && _read_regs(SI72XX_DSPSIGM, 2, &tempRaw);
00151 
00152         if (ok && !_isTempOffsetAndGainValid) {
00153             signed char otpTempOffset;
00154             signed char otpTempGain;
00155 
00156             ok = _read_otp(SI72XX_OTP_TEMP_OFFSET, &otpTempOffset)
00157               && _read_otp(SI72XX_OTP_TEMP_GAIN, &otpTempGain);
00158             if (ok) {
00159                 _tempOffset = (float)otpTempOffset / 16;
00160                 _tempGain = 1 + (float)otpTempGain / 2048;
00161                 _isTempOffsetAndGainValid = true;
00162             }
00163         }
00164 
00165         if (ok) {
00166             magRaw = ((magRaw >> 8) & 0xff) + ((magRaw & 0xff) << 8);
00167             tempRaw = ((tempRaw >> 8) & 0xff) + ((tempRaw & 0xff) << 8);
00168             ok = (magRaw & 0x8000) && (tempRaw & 0x8000);
00169             data->mag_T = (float)(magRaw - 0xC000) * 0.00125F;
00170             data->temp_C = (float)((tempRaw & ~0x8000) >> 3);
00171             data->temp_C = _tempGain * (-3.83e-6F * data->temp_C * data->temp_C + 0.16094F * data->temp_C - 279.80F - 0.222F * 3.0F) + _tempOffset;
00172         }
00173 
00174         return ok;
00175     }
00176 
00177  protected:
00178 
00179     /**
00180     * I2C read/write helper function
00181     *
00182     * @param address is the register to read/write
00183     * @param buff holds the data to write and recieves the data to read
00184     * @param writeSize is the number of bytes to write to register
00185     * @param readSize is the number of bytes to retrieve from device
00186     *
00187     * @returns true (success) or false (failure)
00188     */
00189     bool _i2c_transfer(int address, void * buff, size_t writeSize, size_t readSize) {
00190         bool ok;
00191         bool expect_response = (readSize != 0);
00192 
00193         ok = !_i2c->write(address, (char*)buff, writeSize, expect_response);
00194         if (ok && expect_response)
00195             ok = !_i2c->read(address, (char*)buff, readSize);
00196 
00197         return ok;
00198     }
00199 
00200     /**
00201     * Write to an I2C register
00202     *
00203     * @param reg sensor register to write
00204     * @param val value to write
00205     *
00206     * @returns true (success) or false (failure)
00207     */
00208     bool _write_reg(char reg, char val) {
00209         char out[2] = {reg, val};
00210         return 0 == _i2c->write(_addr_8bit, out, 2);
00211     }
00212 
00213     /**
00214     * Read multiple sensor registers
00215     *
00216     * @param start_reg first sensor register to be read
00217     * @param count number of registers to be read
00218     * @param buff pointer to buffer where to store the register values
00219     *
00220     * @returns true (success) or false (failure)
00221     */
00222     bool _read_regs(char start_reg, char count, void * buff) {
00223         bool ok;
00224         ok = (0 == _i2c->write(_addr_8bit, &start_reg, 1, true))
00225              && (0 == _i2c->read(_addr_8bit, (char *)buff, count));
00226         return ok;
00227     }
00228 
00229     /**
00230     * Read sensor OTP
00231     *
00232     * @param otpAddr OTP address to be read
00233     * @param *data where to store the OTP data
00234     *
00235     * @returns true (success) or false (failure)
00236     */
00237     bool _read_otp(uint8_t otpAddr, void *data) {
00238         uint8_t optCtrl;
00239 
00240         bool ok = _read_regs(SI72XX_OTP_CTRL, 1, &optCtrl)
00241                && !(optCtrl & OTP_CTRL__OPT_BUSY_MASK)
00242                && _write_reg(SI72XX_OTP_ADDR, otpAddr)
00243                && _write_reg(SI72XX_OTP_CTRL, OTP_CTRL__OPT_READ_EN_MASK)
00244                && _read_regs(SI72XX_OTP_DATA, 1, data);
00245 
00246         return ok;
00247     }
00248 
00249     bool    _isTempOffsetAndGainValid;
00250     float   _tempOffset;
00251     float   _tempGain;
00252     bool    _enabled;
00253     int     _addr_8bit;
00254     T      *_i2c;
00255 };
00256