Si7210 driver

Dependents:   TBSense2_Sensor_Demo

Files at this revision

API Documentation at this revision

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*)&reg, 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