Si7210 driver
Dependents: TBSense2_Sensor_Demo
Diff: Si7210.cpp
- Revision:
- 0:9bce98da584b
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