Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: si7210.h
- Revision:
- 1:8cb452601311
- Parent:
- 0:ee9d6b55bf85
--- a/si7210.h Tue Sep 12 17:17:09 2017 +0000 +++ b/si7210.h Thu Sep 14 00:07:17 2017 +0000 @@ -1,7 +1,88 @@ -#include "mbed.h" +/* 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 */ -#ifndef SI7210_H -#define SI7210_H +/** Support for Silicon Labs SI7210: Magnetic field and temperature sensor + * + * Example: + * @code + * + * #include "mbed.h" + * #include "SI7210.h" + * + * I2C i2c(I2C_SDA, I2C_SCL); + * SI7210<I2C> si7210(&i2c, SI7210_BASE_ADDR_7BIT); + * + * int main() { + * si7210_measurements_t data; + * bool ok; + * + * ok = si7210.enable() && + * si7210.read(&data) && + * si7210.disable(); + * + * if (ok) { + printf("Mag T: %f\r\n", data.mag_T); + printf("temp C/F: %f/%f\r\n", data.temp_C, data.temp_C * 9 / 5 + 32); + * } else { + * printf("si7210 error!\r\n"); + * } + * } + * @endcode + * @ingroup drivers + */ + +#pragma once + +#define ARAUTOINC__ARAUTOINC_MASK 0x01 +#define OTP_CTRL__OPT_BUSY_MASK 0x01 +#define OTP_CTRL__OPT_READ_EN_MASK 0x02 +#define POWER_CTRL__SLEEP_MASK 0x01 +#define POWER_CTRL__STOP_MASK 0x02 +#define POWER_CTRL__ONEBURST_MASK 0x04 +#define POWER_CTRL__USESTORE_MASK 0x08 +#define POWER_CTRL__MEAS_MASK 0x80 +#define DSPSIGSEL__MAG_VAL_SEL 0 +#define DSPSIGSEL__TEMP_VAL_SEL 1 + +/** I2C registers for Si72xx */ +#define SI72XX_OTP_TEMP_OFFSET 0x1D +#define SI72XX_OTP_TEMP_GAIN 0x1E +#define SI72XX_HREVID 0xC0 +#define SI72XX_DSPSIGM 0xC1 +#define SI72XX_DSPSIGL 0xC2 +#define SI72XX_DSPSIGSEL 0xC3 +#define SI72XX_POWER_CTRL 0xC4 +#define SI72XX_ARAUTOINC 0xC5 +#define SI72XX_CTRL1 0xC6 +#define SI72XX_CTRL2 0xC7 +#define SI72XX_SLTIME 0xC8 +#define SI72XX_CTRL3 0xC9 +#define SI72XX_A0 0xCA +#define SI72XX_A1 0xCB +#define SI72XX_A2 0xCC +#define SI72XX_CTRL4 0xCD +#define SI72XX_A3 0xCE +#define SI72XX_A4 0xCF +#define SI72XX_A5 0xD0 +#define SI72XX_OTP_ADDR 0xE1 +#define SI72XX_OTP_DATA 0xE2 +#define SI72XX_OTP_CTRL 0xE3 +#define SI72XX_TM_FG 0xE4 #define SI7210_BASE_ADDR_7BIT 0x30 @@ -10,6 +91,7 @@ float temp_C; } si7210_measurements_t; +template <class T> class SI7210 { public: /** @@ -17,10 +99,36 @@ * * @param i2c I2C class servicing the strip */ - SI7210(I2C * i2c, uint8_t addr_7bit) : _i2c(i2c) { + SI7210(T * i2c, uint8_t addr_7bit) : _i2c(i2c) { + _isTempOffsetAndGainValid = false; + _enabled = false; _addr_8bit = ((addr_7bit & 0x3) + SI7210_BASE_ADDR_7BIT) << 1; } - + + /** + * Activate the sensor (wake if sleeping). + * + * @returns true (success) or false (failure) + */ + bool enable(void) { + bool ok = _i2c_transfer(_addr_8bit, NULL, 0, 0); + if (ok) + _enabled = true; + return ok; + } + + /** + * Deactivate the sensor (puts it to sleep) + * + * @returns true (success) or false (failure) + */ + bool disable(void) { + bool ok = _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__SLEEP_MASK); + if (ok) + _enabled = ok; + return ok; + } + /** * Read temperature and humidity * @@ -29,10 +137,45 @@ * * @returns true (success) or false (failure) */ - bool read(si7210_measurements_t * data); + bool read(si7210_measurements_t * data) { + uint16_t magRaw; + uint16_t tempRaw; + + bool ok = _write_reg(SI72XX_ARAUTOINC, ARAUTOINC__ARAUTOINC_MASK) + && _write_reg(SI72XX_DSPSIGSEL, DSPSIGSEL__MAG_VAL_SEL) //capture mag field measurement + && _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__ONEBURST_MASK) + && _read_regs(SI72XX_DSPSIGM, 2, &magRaw) + && _write_reg(SI72XX_DSPSIGSEL, DSPSIGSEL__TEMP_VAL_SEL) //capture temp measurement + && _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__ONEBURST_MASK) + && _read_regs(SI72XX_DSPSIGM, 2, &tempRaw); + + if (ok && !_isTempOffsetAndGainValid) { + char otpTempOffset; + char otpTempGain; + + ok = _read_otp(SI72XX_OTP_TEMP_OFFSET, &otpTempOffset) + && _read_otp(SI72XX_OTP_TEMP_GAIN, &otpTempGain); + if (ok) { + _tempOffset = (float)otpTempOffset / 16; + _tempGain = 1 + (float)otpTempGain / 2048; + _isTempOffsetAndGainValid = true; + } + } + + if (ok) { + magRaw = ((magRaw >> 8) & 0xff) + ((magRaw & 0xff) << 8); + tempRaw = ((tempRaw >> 8) & 0xff) + ((tempRaw & 0xff) << 8); + ok = (magRaw & 0x8000) && (tempRaw & 0x8000); + data->mag_T = (float)(magRaw - 0xC000) * 0.00125F; + data->temp_C = (float)((tempRaw & ~0x8000) >> 3); + 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; + } + + return ok; + } protected: - + /** * I2C read/write helper function * @@ -43,15 +186,71 @@ * * @returns true (success) or false (failure) */ - bool _i2c_transfer(int address, void * buff, size_t writeSize, size_t readSize); + 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; + } + + /** + * Write to an I2C register + * + * @param reg sensor register to write + * @param val value to write + * + * @returns true (success) or false (failure) + */ + bool _write_reg(char reg, char val) { + char out[2] = {reg, val}; + return 0 == _i2c->write(_addr_8bit, out, 2); + } + /** - * - bool _validate(void) + * Read multiple sensor registers + * + * @param start_reg first sensor register to be read + * @param count number of registers to be read + * @param buff pointer to buffer where to store the register values + * + * @returns true (success) or false (failure) */ + bool _read_regs(char start_reg, char count, void * buff) { + bool ok; + ok = (0 == _i2c->write(_addr_8bit, &start_reg, 1, true)) + && (0 == _i2c->read(_addr_8bit, (char *)buff, count)); + return ok; + } + /** + * Read sensor OTP + * + * @param otpAddr OTP address to be read + * @param *data where to store the OTP data + * + * @returns true (success) or false (failure) + */ + bool _read_otp(uint8_t otpAddr, void *data) { + uint8_t optCtrl; + + bool ok = _read_regs(SI72XX_OTP_CTRL, 1, &optCtrl) + && !(optCtrl & OTP_CTRL__OPT_BUSY_MASK) + && _write_reg(SI72XX_OTP_ADDR, otpAddr) + && _write_reg(SI72XX_OTP_CTRL, OTP_CTRL__OPT_READ_EN_MASK) + && _read_regs(SI72XX_OTP_DATA, 1, data); + + return ok; + } + + bool _isTempOffsetAndGainValid; + float _tempOffset; + float _tempGain; + bool _enabled; int _addr_8bit; - I2C *_i2c; + T *_i2c; }; -#endif //SI7210_H