Silicon Labs Si7210 device driver: I2C Hall Effect Magnetic Position and Temperature Sensor
SI7210.h@3:beca2e65b1b0, 2017-10-14 (annotated)
- Committer:
- sm168j
- Date:
- Sat Oct 14 20:10:05 2017 -0500
- Revision:
- 3:beca2e65b1b0
- Parent:
- 2:d85076c18c80
Corrected temperature reading calculation
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ninensei | 1:8cb452601311 | 1 | /* mbed Microcontroller Library |
ninensei | 1:8cb452601311 | 2 | * Copyright (c) 2017 AT&T, IIoT Foundry, Plano, TX, USA |
ninensei | 1:8cb452601311 | 3 | * |
ninensei | 1:8cb452601311 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
ninensei | 1:8cb452601311 | 5 | * you may not use this file except in compliance with the License. |
ninensei | 1:8cb452601311 | 6 | * You may obtain a copy of the License at |
ninensei | 1:8cb452601311 | 7 | * |
ninensei | 1:8cb452601311 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
ninensei | 1:8cb452601311 | 9 | * |
ninensei | 1:8cb452601311 | 10 | * Unless required by applicable law or agreed to in writing, software |
ninensei | 1:8cb452601311 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
ninensei | 1:8cb452601311 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
ninensei | 1:8cb452601311 | 13 | * See the License for the specific language governing permissions and |
ninensei | 1:8cb452601311 | 14 | * limitations under the License. |
ninensei | 1:8cb452601311 | 15 | */ |
ninensei | 1:8cb452601311 | 16 | |
ninensei | 1:8cb452601311 | 17 | /** \addtogroup drivers */ |
ninensei | 0:ee9d6b55bf85 | 18 | |
ninensei | 1:8cb452601311 | 19 | /** Support for Silicon Labs SI7210: Magnetic field and temperature sensor |
ninensei | 1:8cb452601311 | 20 | * |
ninensei | 1:8cb452601311 | 21 | * Example: |
ninensei | 1:8cb452601311 | 22 | * @code |
ninensei | 1:8cb452601311 | 23 | * |
ninensei | 1:8cb452601311 | 24 | * #include "mbed.h" |
ninensei | 1:8cb452601311 | 25 | * #include "SI7210.h" |
ninensei | 1:8cb452601311 | 26 | * |
ninensei | 1:8cb452601311 | 27 | * I2C i2c(I2C_SDA, I2C_SCL); |
ninensei | 1:8cb452601311 | 28 | * SI7210<I2C> si7210(&i2c, SI7210_BASE_ADDR_7BIT); |
ninensei | 1:8cb452601311 | 29 | * |
ninensei | 1:8cb452601311 | 30 | * int main() { |
ninensei | 1:8cb452601311 | 31 | * si7210_measurements_t data; |
ninensei | 1:8cb452601311 | 32 | * bool ok; |
ninensei | 1:8cb452601311 | 33 | * |
ninensei | 1:8cb452601311 | 34 | * ok = si7210.enable() && |
ninensei | 1:8cb452601311 | 35 | * si7210.read(&data) && |
ninensei | 1:8cb452601311 | 36 | * si7210.disable(); |
sm168j | 3:beca2e65b1b0 | 37 | * |
ninensei | 1:8cb452601311 | 38 | * if (ok) { |
ninensei | 1:8cb452601311 | 39 | printf("Mag T: %f\r\n", data.mag_T); |
ninensei | 1:8cb452601311 | 40 | printf("temp C/F: %f/%f\r\n", data.temp_C, data.temp_C * 9 / 5 + 32); |
ninensei | 1:8cb452601311 | 41 | * } else { |
ninensei | 1:8cb452601311 | 42 | * printf("si7210 error!\r\n"); |
ninensei | 1:8cb452601311 | 43 | * } |
ninensei | 1:8cb452601311 | 44 | * } |
ninensei | 1:8cb452601311 | 45 | * @endcode |
ninensei | 1:8cb452601311 | 46 | * @ingroup drivers |
ninensei | 1:8cb452601311 | 47 | */ |
ninensei | 1:8cb452601311 | 48 | |
ninensei | 1:8cb452601311 | 49 | #pragma once |
ninensei | 1:8cb452601311 | 50 | |
ninensei | 1:8cb452601311 | 51 | #define ARAUTOINC__ARAUTOINC_MASK 0x01 |
ninensei | 1:8cb452601311 | 52 | #define OTP_CTRL__OPT_BUSY_MASK 0x01 |
ninensei | 1:8cb452601311 | 53 | #define OTP_CTRL__OPT_READ_EN_MASK 0x02 |
ninensei | 1:8cb452601311 | 54 | #define POWER_CTRL__SLEEP_MASK 0x01 |
ninensei | 1:8cb452601311 | 55 | #define POWER_CTRL__STOP_MASK 0x02 |
ninensei | 1:8cb452601311 | 56 | #define POWER_CTRL__ONEBURST_MASK 0x04 |
ninensei | 1:8cb452601311 | 57 | #define POWER_CTRL__USESTORE_MASK 0x08 |
ninensei | 1:8cb452601311 | 58 | #define POWER_CTRL__MEAS_MASK 0x80 |
ninensei | 1:8cb452601311 | 59 | #define DSPSIGSEL__MAG_VAL_SEL 0 |
ninensei | 1:8cb452601311 | 60 | #define DSPSIGSEL__TEMP_VAL_SEL 1 |
ninensei | 1:8cb452601311 | 61 | |
ninensei | 1:8cb452601311 | 62 | /** I2C registers for Si72xx */ |
ninensei | 1:8cb452601311 | 63 | #define SI72XX_OTP_TEMP_OFFSET 0x1D |
ninensei | 1:8cb452601311 | 64 | #define SI72XX_OTP_TEMP_GAIN 0x1E |
ninensei | 1:8cb452601311 | 65 | #define SI72XX_HREVID 0xC0 |
ninensei | 1:8cb452601311 | 66 | #define SI72XX_DSPSIGM 0xC1 |
ninensei | 1:8cb452601311 | 67 | #define SI72XX_DSPSIGL 0xC2 |
ninensei | 1:8cb452601311 | 68 | #define SI72XX_DSPSIGSEL 0xC3 |
ninensei | 1:8cb452601311 | 69 | #define SI72XX_POWER_CTRL 0xC4 |
ninensei | 1:8cb452601311 | 70 | #define SI72XX_ARAUTOINC 0xC5 |
ninensei | 1:8cb452601311 | 71 | #define SI72XX_CTRL1 0xC6 |
ninensei | 1:8cb452601311 | 72 | #define SI72XX_CTRL2 0xC7 |
ninensei | 1:8cb452601311 | 73 | #define SI72XX_SLTIME 0xC8 |
ninensei | 1:8cb452601311 | 74 | #define SI72XX_CTRL3 0xC9 |
ninensei | 1:8cb452601311 | 75 | #define SI72XX_A0 0xCA |
ninensei | 1:8cb452601311 | 76 | #define SI72XX_A1 0xCB |
ninensei | 1:8cb452601311 | 77 | #define SI72XX_A2 0xCC |
ninensei | 1:8cb452601311 | 78 | #define SI72XX_CTRL4 0xCD |
ninensei | 1:8cb452601311 | 79 | #define SI72XX_A3 0xCE |
ninensei | 1:8cb452601311 | 80 | #define SI72XX_A4 0xCF |
ninensei | 1:8cb452601311 | 81 | #define SI72XX_A5 0xD0 |
ninensei | 1:8cb452601311 | 82 | #define SI72XX_OTP_ADDR 0xE1 |
ninensei | 1:8cb452601311 | 83 | #define SI72XX_OTP_DATA 0xE2 |
ninensei | 1:8cb452601311 | 84 | #define SI72XX_OTP_CTRL 0xE3 |
ninensei | 1:8cb452601311 | 85 | #define SI72XX_TM_FG 0xE4 |
ninensei | 0:ee9d6b55bf85 | 86 | |
ninensei | 0:ee9d6b55bf85 | 87 | #define SI7210_BASE_ADDR_7BIT 0x30 |
ninensei | 0:ee9d6b55bf85 | 88 | |
ninensei | 0:ee9d6b55bf85 | 89 | typedef struct { |
ninensei | 0:ee9d6b55bf85 | 90 | float mag_T; |
ninensei | 0:ee9d6b55bf85 | 91 | float temp_C; |
ninensei | 0:ee9d6b55bf85 | 92 | } si7210_measurements_t; |
ninensei | 0:ee9d6b55bf85 | 93 | |
ninensei | 1:8cb452601311 | 94 | template <class T> |
ninensei | 0:ee9d6b55bf85 | 95 | class SI7210 { |
ninensei | 0:ee9d6b55bf85 | 96 | public: |
ninensei | 0:ee9d6b55bf85 | 97 | /** |
ninensei | 0:ee9d6b55bf85 | 98 | * Constructor |
ninensei | 0:ee9d6b55bf85 | 99 | * |
ninensei | 0:ee9d6b55bf85 | 100 | * @param i2c I2C class servicing the strip |
ninensei | 0:ee9d6b55bf85 | 101 | */ |
ninensei | 1:8cb452601311 | 102 | SI7210(T * i2c, uint8_t addr_7bit) : _i2c(i2c) { |
ninensei | 1:8cb452601311 | 103 | _isTempOffsetAndGainValid = false; |
ninensei | 1:8cb452601311 | 104 | _enabled = false; |
ninensei | 0:ee9d6b55bf85 | 105 | _addr_8bit = ((addr_7bit & 0x3) + SI7210_BASE_ADDR_7BIT) << 1; |
ninensei | 0:ee9d6b55bf85 | 106 | } |
ninensei | 1:8cb452601311 | 107 | |
ninensei | 1:8cb452601311 | 108 | /** |
ninensei | 1:8cb452601311 | 109 | * Activate the sensor (wake if sleeping). |
ninensei | 1:8cb452601311 | 110 | * |
ninensei | 1:8cb452601311 | 111 | * @returns true (success) or false (failure) |
ninensei | 1:8cb452601311 | 112 | */ |
ninensei | 1:8cb452601311 | 113 | bool enable(void) { |
ninensei | 1:8cb452601311 | 114 | bool ok = _i2c_transfer(_addr_8bit, NULL, 0, 0); |
ninensei | 1:8cb452601311 | 115 | if (ok) |
ninensei | 1:8cb452601311 | 116 | _enabled = true; |
ninensei | 1:8cb452601311 | 117 | return ok; |
ninensei | 1:8cb452601311 | 118 | } |
ninensei | 1:8cb452601311 | 119 | |
ninensei | 1:8cb452601311 | 120 | /** |
ninensei | 1:8cb452601311 | 121 | * Deactivate the sensor (puts it to sleep) |
ninensei | 1:8cb452601311 | 122 | * |
ninensei | 1:8cb452601311 | 123 | * @returns true (success) or false (failure) |
ninensei | 1:8cb452601311 | 124 | */ |
ninensei | 1:8cb452601311 | 125 | bool disable(void) { |
ninensei | 1:8cb452601311 | 126 | bool ok = _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__SLEEP_MASK); |
ninensei | 1:8cb452601311 | 127 | if (ok) |
ninensei | 1:8cb452601311 | 128 | _enabled = ok; |
ninensei | 1:8cb452601311 | 129 | return ok; |
ninensei | 1:8cb452601311 | 130 | } |
ninensei | 1:8cb452601311 | 131 | |
ninensei | 0:ee9d6b55bf85 | 132 | /** |
ninensei | 0:ee9d6b55bf85 | 133 | * Read temperature and humidity |
ninensei | 0:ee9d6b55bf85 | 134 | * |
ninensei | 0:ee9d6b55bf85 | 135 | * @param data points to struct to store measurements in. Stucture is |
ninensei | 0:ee9d6b55bf85 | 136 | * valid only when function returns success indication. |
ninensei | 0:ee9d6b55bf85 | 137 | * |
ninensei | 0:ee9d6b55bf85 | 138 | * @returns true (success) or false (failure) |
ninensei | 0:ee9d6b55bf85 | 139 | */ |
ninensei | 1:8cb452601311 | 140 | bool read(si7210_measurements_t * data) { |
ninensei | 1:8cb452601311 | 141 | uint16_t magRaw; |
ninensei | 1:8cb452601311 | 142 | uint16_t tempRaw; |
sm168j | 3:beca2e65b1b0 | 143 | |
ninensei | 1:8cb452601311 | 144 | bool ok = _write_reg(SI72XX_ARAUTOINC, ARAUTOINC__ARAUTOINC_MASK) |
ninensei | 1:8cb452601311 | 145 | && _write_reg(SI72XX_DSPSIGSEL, DSPSIGSEL__MAG_VAL_SEL) //capture mag field measurement |
ninensei | 1:8cb452601311 | 146 | && _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__ONEBURST_MASK) |
ninensei | 1:8cb452601311 | 147 | && _read_regs(SI72XX_DSPSIGM, 2, &magRaw) |
ninensei | 1:8cb452601311 | 148 | && _write_reg(SI72XX_DSPSIGSEL, DSPSIGSEL__TEMP_VAL_SEL) //capture temp measurement |
ninensei | 1:8cb452601311 | 149 | && _write_reg(SI72XX_POWER_CTRL, POWER_CTRL__ONEBURST_MASK) |
ninensei | 1:8cb452601311 | 150 | && _read_regs(SI72XX_DSPSIGM, 2, &tempRaw); |
ninensei | 1:8cb452601311 | 151 | |
ninensei | 1:8cb452601311 | 152 | if (ok && !_isTempOffsetAndGainValid) { |
sm168j | 3:beca2e65b1b0 | 153 | signed char otpTempOffset; |
sm168j | 3:beca2e65b1b0 | 154 | signed char otpTempGain; |
sm168j | 3:beca2e65b1b0 | 155 | |
ninensei | 1:8cb452601311 | 156 | ok = _read_otp(SI72XX_OTP_TEMP_OFFSET, &otpTempOffset) |
ninensei | 1:8cb452601311 | 157 | && _read_otp(SI72XX_OTP_TEMP_GAIN, &otpTempGain); |
ninensei | 1:8cb452601311 | 158 | if (ok) { |
ninensei | 1:8cb452601311 | 159 | _tempOffset = (float)otpTempOffset / 16; |
ninensei | 1:8cb452601311 | 160 | _tempGain = 1 + (float)otpTempGain / 2048; |
ninensei | 1:8cb452601311 | 161 | _isTempOffsetAndGainValid = true; |
ninensei | 1:8cb452601311 | 162 | } |
ninensei | 1:8cb452601311 | 163 | } |
sm168j | 3:beca2e65b1b0 | 164 | |
ninensei | 1:8cb452601311 | 165 | if (ok) { |
ninensei | 1:8cb452601311 | 166 | magRaw = ((magRaw >> 8) & 0xff) + ((magRaw & 0xff) << 8); |
ninensei | 1:8cb452601311 | 167 | tempRaw = ((tempRaw >> 8) & 0xff) + ((tempRaw & 0xff) << 8); |
ninensei | 1:8cb452601311 | 168 | ok = (magRaw & 0x8000) && (tempRaw & 0x8000); |
ninensei | 1:8cb452601311 | 169 | data->mag_T = (float)(magRaw - 0xC000) * 0.00125F; |
ninensei | 1:8cb452601311 | 170 | data->temp_C = (float)((tempRaw & ~0x8000) >> 3); |
ninensei | 1:8cb452601311 | 171 | 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; |
ninensei | 1:8cb452601311 | 172 | } |
sm168j | 3:beca2e65b1b0 | 173 | |
ninensei | 1:8cb452601311 | 174 | return ok; |
ninensei | 1:8cb452601311 | 175 | } |
ninensei | 0:ee9d6b55bf85 | 176 | |
ninensei | 0:ee9d6b55bf85 | 177 | protected: |
ninensei | 1:8cb452601311 | 178 | |
ninensei | 0:ee9d6b55bf85 | 179 | /** |
ninensei | 0:ee9d6b55bf85 | 180 | * I2C read/write helper function |
ninensei | 0:ee9d6b55bf85 | 181 | * |
ninensei | 0:ee9d6b55bf85 | 182 | * @param address is the register to read/write |
ninensei | 0:ee9d6b55bf85 | 183 | * @param buff holds the data to write and recieves the data to read |
ninensei | 0:ee9d6b55bf85 | 184 | * @param writeSize is the number of bytes to write to register |
ninensei | 0:ee9d6b55bf85 | 185 | * @param readSize is the number of bytes to retrieve from device |
ninensei | 0:ee9d6b55bf85 | 186 | * |
ninensei | 0:ee9d6b55bf85 | 187 | * @returns true (success) or false (failure) |
ninensei | 0:ee9d6b55bf85 | 188 | */ |
ninensei | 1:8cb452601311 | 189 | bool _i2c_transfer(int address, void * buff, size_t writeSize, size_t readSize) { |
ninensei | 1:8cb452601311 | 190 | bool ok; |
ninensei | 1:8cb452601311 | 191 | bool expect_response = (readSize != 0); |
sm168j | 3:beca2e65b1b0 | 192 | |
ninensei | 1:8cb452601311 | 193 | ok = !_i2c->write(address, (char*)buff, writeSize, expect_response); |
ninensei | 1:8cb452601311 | 194 | if (ok && expect_response) |
ninensei | 1:8cb452601311 | 195 | ok = !_i2c->read(address, (char*)buff, readSize); |
sm168j | 3:beca2e65b1b0 | 196 | |
ninensei | 1:8cb452601311 | 197 | return ok; |
ninensei | 1:8cb452601311 | 198 | } |
ninensei | 1:8cb452601311 | 199 | |
ninensei | 1:8cb452601311 | 200 | /** |
ninensei | 1:8cb452601311 | 201 | * Write to an I2C register |
ninensei | 1:8cb452601311 | 202 | * |
ninensei | 1:8cb452601311 | 203 | * @param reg sensor register to write |
ninensei | 1:8cb452601311 | 204 | * @param val value to write |
ninensei | 1:8cb452601311 | 205 | * |
ninensei | 1:8cb452601311 | 206 | * @returns true (success) or false (failure) |
ninensei | 1:8cb452601311 | 207 | */ |
ninensei | 1:8cb452601311 | 208 | bool _write_reg(char reg, char val) { |
ninensei | 1:8cb452601311 | 209 | char out[2] = {reg, val}; |
ninensei | 1:8cb452601311 | 210 | return 0 == _i2c->write(_addr_8bit, out, 2); |
ninensei | 1:8cb452601311 | 211 | } |
ninensei | 1:8cb452601311 | 212 | |
ninensei | 0:ee9d6b55bf85 | 213 | /** |
ninensei | 1:8cb452601311 | 214 | * Read multiple sensor registers |
ninensei | 1:8cb452601311 | 215 | * |
ninensei | 1:8cb452601311 | 216 | * @param start_reg first sensor register to be read |
ninensei | 1:8cb452601311 | 217 | * @param count number of registers to be read |
ninensei | 1:8cb452601311 | 218 | * @param buff pointer to buffer where to store the register values |
ninensei | 1:8cb452601311 | 219 | * |
ninensei | 1:8cb452601311 | 220 | * @returns true (success) or false (failure) |
ninensei | 0:ee9d6b55bf85 | 221 | */ |
ninensei | 1:8cb452601311 | 222 | bool _read_regs(char start_reg, char count, void * buff) { |
ninensei | 1:8cb452601311 | 223 | bool ok; |
ninensei | 1:8cb452601311 | 224 | ok = (0 == _i2c->write(_addr_8bit, &start_reg, 1, true)) |
ninensei | 1:8cb452601311 | 225 | && (0 == _i2c->read(_addr_8bit, (char *)buff, count)); |
ninensei | 1:8cb452601311 | 226 | return ok; |
ninensei | 1:8cb452601311 | 227 | } |
ninensei | 0:ee9d6b55bf85 | 228 | |
ninensei | 1:8cb452601311 | 229 | /** |
ninensei | 1:8cb452601311 | 230 | * Read sensor OTP |
ninensei | 1:8cb452601311 | 231 | * |
ninensei | 1:8cb452601311 | 232 | * @param otpAddr OTP address to be read |
ninensei | 1:8cb452601311 | 233 | * @param *data where to store the OTP data |
ninensei | 1:8cb452601311 | 234 | * |
ninensei | 1:8cb452601311 | 235 | * @returns true (success) or false (failure) |
ninensei | 1:8cb452601311 | 236 | */ |
ninensei | 1:8cb452601311 | 237 | bool _read_otp(uint8_t otpAddr, void *data) { |
ninensei | 1:8cb452601311 | 238 | uint8_t optCtrl; |
sm168j | 3:beca2e65b1b0 | 239 | |
ninensei | 1:8cb452601311 | 240 | bool ok = _read_regs(SI72XX_OTP_CTRL, 1, &optCtrl) |
ninensei | 1:8cb452601311 | 241 | && !(optCtrl & OTP_CTRL__OPT_BUSY_MASK) |
ninensei | 1:8cb452601311 | 242 | && _write_reg(SI72XX_OTP_ADDR, otpAddr) |
ninensei | 1:8cb452601311 | 243 | && _write_reg(SI72XX_OTP_CTRL, OTP_CTRL__OPT_READ_EN_MASK) |
ninensei | 1:8cb452601311 | 244 | && _read_regs(SI72XX_OTP_DATA, 1, data); |
sm168j | 3:beca2e65b1b0 | 245 | |
ninensei | 1:8cb452601311 | 246 | return ok; |
ninensei | 1:8cb452601311 | 247 | } |
ninensei | 1:8cb452601311 | 248 | |
ninensei | 1:8cb452601311 | 249 | bool _isTempOffsetAndGainValid; |
ninensei | 1:8cb452601311 | 250 | float _tempOffset; |
ninensei | 1:8cb452601311 | 251 | float _tempGain; |
ninensei | 1:8cb452601311 | 252 | bool _enabled; |
ninensei | 0:ee9d6b55bf85 | 253 | int _addr_8bit; |
ninensei | 1:8cb452601311 | 254 | T *_i2c; |
ninensei | 0:ee9d6b55bf85 | 255 | }; |
ninensei | 0:ee9d6b55bf85 | 256 |