Silicon Labs Si7210 device driver: I2C Hall Effect Magnetic Position and Temperature Sensor
SI7210.h
- Committer:
- ninensei
- Date:
- 2017-09-14
- Revision:
- 2:d85076c18c80
- Parent:
- si7210.h@ 1:8cb452601311
- Child:
- 3:beca2e65b1b0
File content as of revision 2:d85076c18c80:
/* 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 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 typedef struct { float mag_T; float temp_C; } si7210_measurements_t; template <class T> class SI7210 { public: /** * Constructor * * @param i2c I2C class servicing the strip */ 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 * * @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(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 * * @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; } /** * 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); } /** * 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; T *_i2c; };