Si7210 driver
Dependents: TBSense2_Sensor_Demo
Revision 0:9bce98da584b, committed 2017-05-04
- Comitter:
- stevew817
- Date:
- Thu May 04 12:15:44 2017 +0000
- Commit message:
- Initial WIP;
Changed in this revision
Si7210.cpp | Show annotated file Show diff for this revision Revisions of this file |
Si7210.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 9bce98da584b Si7210.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Si7210.cpp Thu May 04 12:15:44 2017 +0000 @@ -0,0 +1,234 @@ +#include "Si7210.h" + +#define OTP_BUSY_MASK 1 +#define OTP_READ_EN_MASK 2 +#define NUM_HALL_DEVICES 3 +#define STOP_MASK 2 +#define SLTIMEENA_MASK 1 +#define SW_TAMPER_MASK 0xFC +#define SL_FAST_MASK 2 +#define SLEEP_MASK 1 +#define ONEBURST_MASK 4 + +namespace silabs { +Si7210::Si7210(PinName sda, PinName scl, uint8_t address) +{ + _i2c = new I2C(sda, scl); + _i2c->frequency(400000); + _address = address; + _ownI2C = true; + + // Initialize members + _temperatureOffset = 0; + _temperatureGain = 0; + _rawTemperature = 0; + _rawField = 0; + _range = RANGE_20mT; +} + +Si7210::Si7210(I2C *i2c_bus, uint8_t address) +{ + _i2c = i2c_bus; + _address = address; + _ownI2C = false; + + // Initialize members + _temperatureOffset = 0; + _temperatureGain = 0; + _rawTemperature = 0; + _rawField = 0; + _range = RANGE_20mT; +} + +Si7210::~Si7210() +{ + if (_ownI2C) { + delete _i2c; + } +} + +int Si7210::getTemperature() +{ + // we operate on 11 fractional bits. + int offset; + int64_t temperature; + + if (_temperatureOffset == 0 && + _temperatureGain == 0) { + /* read out compensation values */ + writeRegister(SI72XX_OTP_ADDR, 0x1DU); + writeRegister(SI72XX_OTP_CTRL, OTP_READ_EN_MASK); + readRegister(SI72XX_OTP_DATA, (uint8_t*)&_temperatureOffset); + + writeRegister(SI72XX_OTP_ADDR, 0x1EU); + writeRegister(SI72XX_OTP_CTRL, OTP_READ_EN_MASK); + readRegister(SI72XX_OTP_DATA, (uint8_t*)&_temperatureGain); + } + + temperature = ((int64_t)_rawTemperature * (int64_t)_rawTemperature) * (-21) / 10000; + temperature += ((1522 * _rawTemperature) / 10); + temperature -= 273000; + + + // offset = val@0x1D / 16 = val@0x1D / 2048 * 128 + offset = (int32_t)_temperatureOffset * 1000 / 16; + // gain = 1 + val@0x1E + // temperature = raw * gain + offset + temperature = temperature + (temperature * _temperatureGain / 2048) + offset; + // return temperature + return temperature; +} + +/* + * Get last measured field strength + * return: int32_t = field strength in micro-Tesla. + */ +int Si7210::getFieldStrength() +{ + switch(_range) { + case RANGE_20mT: + return (_rawField / 4) + _rawField; // rawField * 1.25 + case RANGE_200mT: + return (_rawField * 12) + (_rawField / 2); //rawField * 12.5 + default: + return 0; + } +} + +/* + * Set measurement range. + * Return true if successful, false if device is not responding. + */ +bool Si7210::setFieldStrength(Si7210_range_t range) +{ + _range = range; +} + +/* + * Perform measurement of magnetic field. + * Return true if new data available + */ +bool Si7210::fetchFieldStrength() +{ + uint8_t temp = 0x04; + readRegister(SI72XX_DSPSIGM, &temp); + if(temp & 0x80) { + /* Fresh data available */ + _rawField = 0; + _rawField += (temp & 0x7FU) * 256; + readRegister(SI72XX_DSPSIGL, &temp); + _rawField += temp; + _rawField -= 16384U; + return true; + } + return false; +} + +bool Si7210::measureOnce() +{ + uint8_t temp; + wakeup(); + readRegister(SI72XX_POWER_CTRL, &temp); + temp = (temp & 0xF0) | 0xA; // Stop control loop + writeRegister(SI72XX_POWER_CTRL, temp); + + if (_range == RANGE_200mT) { + writeRegister(SI72XX_OTP_ADDR, 0x27U); + writeRegister(SI72XX_OTP_CTRL, OTP_READ_EN_MASK); + readRegister(SI72XX_OTP_DATA, &temp); + writeRegister(SI72XX_A0, temp); + writeRegister(SI72XX_OTP_ADDR, 0x28U); + writeRegister(SI72XX_OTP_CTRL, OTP_READ_EN_MASK); + readRegister(SI72XX_OTP_DATA, &temp); + writeRegister(SI72XX_A1, temp); + writeRegister(SI72XX_OTP_ADDR, 0x29U); + writeRegister(SI72XX_OTP_CTRL, OTP_READ_EN_MASK); + readRegister(SI72XX_OTP_DATA, &temp); + writeRegister(SI72XX_A2, temp); + writeRegister(SI72XX_OTP_ADDR, 0x2AU); + writeRegister(SI72XX_OTP_CTRL, OTP_READ_EN_MASK); + readRegister(SI72XX_OTP_DATA, &temp); + writeRegister(SI72XX_A3, temp); + writeRegister(SI72XX_OTP_ADDR, 0x2BU); + writeRegister(SI72XX_OTP_CTRL, OTP_READ_EN_MASK); + readRegister(SI72XX_OTP_DATA, &temp); + writeRegister(SI72XX_A4, temp); + writeRegister(SI72XX_OTP_ADDR, 0x2CU); + writeRegister(SI72XX_OTP_CTRL, OTP_READ_EN_MASK); + readRegister(SI72XX_OTP_DATA, &temp); + writeRegister(SI72XX_A5, temp); + } + + writeRegister(SI72XX_CTRL4, 0x44); // Use a burst of 4 samples + temp = 0x4; + writeRegister(SI72XX_DSPSIGSEL, temp); // Select field strength data + + readRegister(SI72XX_POWER_CTRL, &temp); + temp = (temp & 0xF0) | 0x0C; // Start measurement + writeRegister(SI72XX_POWER_CTRL, temp); + + do { + readRegister(SI72XX_POWER_CTRL, &temp); + } while ( (temp & 0x80) != 0 ); + + fetchFieldStrength(); + + writeRegister(SI72XX_CTRL4, 0x0); // Don't burst + temp = 0x1; + writeRegister(SI72XX_DSPSIGSEL, temp); // Select temperature data + + readRegister(SI72XX_POWER_CTRL, &temp); + temp = (temp & 0xF0) | 0x0C; // Start measurement + writeRegister(SI72XX_POWER_CTRL, temp); + + readRegister(SI72XX_DSPSIGM, &temp); + _rawTemperature = 0; + _rawTemperature += 32 * (temp & 0x7F); + readRegister(SI72XX_DSPSIGL, &temp); + _rawTemperature += (temp >> 3); + + sleep(); + return true; +} + +bool Si7210::check() +{ + uint8_t temp; + wakeup(); + readRegister(SI72XX_HREVID, &temp); + sleep(); + + return true; +} + +bool Si7210::wakeup() +{ + uint8_t temp; + if(_i2c->read(_address, (char*)&temp, 1) == 0) return true; + return false; +} + +bool Si7210::sleep() +{ + uint8_t temp; + readRegister(SI72XX_CTRL3, &temp); + temp &= 0xFEU; // Clear sltimena + writeRegister(SI72XX_CTRL3, temp); + readRegister(SI72XX_POWER_CTRL, &temp); + temp = (temp & 0xF8U) | 0x01; // clear STOP and set SLEEP + return writeRegister(SI72XX_POWER_CTRL, temp); +} + +bool Si7210::readRegister(uint8_t reg, uint8_t *result) +{ + _i2c->write(_address, (const char*)®, 1, true); + return _i2c->read(_address, (char*)result, 1) == 0; +} + +bool Si7210::writeRegister(uint8_t reg, uint8_t data) +{ + uint8_t buffer[2] = {reg, data}; + return _i2c->write(_address, (const char*)buffer, 2) == 0; +} + +} // namespace silabs \ No newline at end of file
diff -r 000000000000 -r 9bce98da584b Si7210.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Si7210.h Thu May 04 12:15:44 2017 +0000 @@ -0,0 +1,138 @@ +/***************************************************************************//** + * @file Si7210.h + * @brief Driver class for the Silicon Labs Si7210 I2C Hall-effect sensor + ******************************************************************************* + * @section License + * <b>(C) Copyright 2017 Silicon Labs, http://www.silabs.com</b> + ******************************************************************************* + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no + * obligation to support this Software. Silicon Labs is providing the + * Software "AS IS", with no express or implied warranties of any kind, + * including, but not limited to, any implied warranties of merchantability + * or fitness for any particular purpose or warranties against infringement + * of any proprietary rights of a third party. + * + * Silicon Labs will not be liable for any consequential, incidental, or + * special damages, or any other relief, or for any claim by any third party, + * arising from your use of this Software. + * + ******************************************************************************/ +#ifndef SI7210_H +#define SI7210_H + +#include "mbed.h" + +/* Possible I2C slave addresses */ +#define SI7210_ADDRESS_0 (0x30U << 1) +#define SI7210_ADDRESS_1 (0x31U << 1) +#define SI7210_ADDRESS_2 (0x32U << 1) +#define SI7210_ADDRESS_3 (0x33U << 1) + +/* Register addresses */ +#define SI72XX_HREVID 0xC0U +#define SI72XX_DSPSIGM 0xC1U +#define SI72XX_DSPSIGL 0xC2U +#define SI72XX_DSPSIGSEL 0xC3U +#define SI72XX_POWER_CTRL 0xC4U +#define SI72XX_ARAUTOINC 0xC5U +#define SI72XX_CTRL1 0xC6U +#define SI72XX_CTRL2 0xC7U +#define SI72XX_SLTIME 0xC8U +#define SI72XX_CTRL3 0xC9U +#define SI72XX_A0 0xCAU +#define SI72XX_A1 0xCBU +#define SI72XX_A2 0xCCU +#define SI72XX_CTRL4 0xCDU +#define SI72XX_A3 0xCEU +#define SI72XX_A4 0xCFU +#define SI72XX_A5 0xD0U +#define SI72XX_OTP_ADDR 0xE1U +#define SI72XX_OTP_DATA 0xE2U +#define SI72XX_OTP_CTRL 0xE3U +#define SI72XX_TM_FG 0xE4U + +#define SI72XX_ERROR_BUSY 0xFEU +#define SI72XX_ERROR_NODATA 0xFDU + +/* Possible (bipolar) measurement range settings */ +typedef enum { + RANGE_20mT, + RANGE_200mT +} Si7210_range_t; + +namespace silabs { +class Si7210 +{ +public: + Si7210(PinName sda, PinName scl, uint8_t address); + Si7210(I2C *i2c_bus, uint8_t address = SI7210_ADDRESS_0); + ~Si7210(); + + /* + * Get last measured temperature data + * return: int = temperature in 1/4th degrees centigrade + */ + int getTemperature(); + + /* + * Get last measured field strength + * return: int = field strength in micro-Tesla. + */ + int getFieldStrength(); + + /* + * Set measurement range. + * Return true if successful, false if device is not responding. + */ + bool setFieldStrength(Si7210_range_t range); + + /* + * Return true if successful, false if device is not responding. + */ + bool fetchFieldStrength(); + + bool measureOnce(); + + /* + * Check if the sensor is active and responding. + */ + bool check(); + + /* Read a register from Si7210 */ + bool readRegister(uint8_t reg, uint8_t *result); + bool writeRegister(uint8_t reg, uint8_t data); + + bool wakeup(); + bool sleep(); + +private: + + I2C *_i2c; + bool _ownI2C; + + uint8_t _address; + + int8_t _temperatureOffset; + int8_t _temperatureGain; + + int _rawTemperature; + int _rawField; + + Si7210_range_t _range; + +}; // class Si7210 + +} // namespace silabs + +#endif \ No newline at end of file