aboutsummaryrefslogtreecommitdiffhomepage
path: root/source/Core/Drivers/Si7210.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core/Drivers/Si7210.cpp')
-rw-r--r--source/Core/Drivers/Si7210.cpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/source/Core/Drivers/Si7210.cpp b/source/Core/Drivers/Si7210.cpp
new file mode 100644
index 00000000..b3eae4ae
--- /dev/null
+++ b/source/Core/Drivers/Si7210.cpp
@@ -0,0 +1,184 @@
+/*
+ * Si7210.cpp
+ *
+ * Created on: 5 Oct. 2020
+ * Author: Ralim
+ *
+ * This is based on the very nice sample code by Sean Farrelly (@FARLY7)
+ * Over here : https://github.com/FARLY7/si7210-driver
+ *
+ * This class is licensed as MIT to match this code base
+ */
+
+#include <Si7210.h>
+#include "Si7210_defines.h"
+#include "I2C_Wrapper.hpp"
+bool Si7210::detect() {
+ return FRToSI2C::wakePart(SI7210_ADDRESS);
+
+}
+
+bool Si7210::init() {
+ //Turn on auto increment and sanity check ID
+ //Load OTP cal
+
+ uint8_t temp;
+ if (FRToSI2C::Mem_Read(SI7210_ADDRESS, SI7210_REG_ID, &temp, 1)) {
+ // We don't really care what model it is etc, just probing to check its probably this iC
+ if (temp != 0x00 && temp != 0xFF) {
+ temp = 0x00;
+
+ /* Set device and internal driver settings */
+ if (!write_reg( SI7210_CTRL1, (uint8_t) ~SW_LOW4FIELD_MASK, 0)) {
+ return false;
+ }
+
+ /* Disable periodic auto-wakeup by device, and tamper detect. */
+ if ((!write_reg(SI7210_CTRL3, (uint8_t) ~SL_TIMEENA_MASK, 0)))
+ return false;
+
+ /* Disable tamper detection by setting sw_tamper to 63 */
+ if (!write_reg(SI7210_CTRL3, SL_FAST_MASK | SL_TIMEENA_MASK, 63 << 2))
+ return false;
+
+ if (!set_high_range())
+ return false;
+
+ /* Stop the control loop by setting stop bit */
+ if (!write_reg( SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, STOP_MASK)) /* WARNING: Removed USE_STORE MASK */
+ return false;
+
+ /* Use a burst size of 128/4096 samples in FIR and IIR modes */
+ if (!write_reg(SI7210_CTRL4, 0, DF_BURSTSIZE_128 | DF_BW_4096))
+ return false;
+
+ /* Select field strength measurement */
+ if (!write_reg( SI7210_DSPSIGSEL, 0, DSP_SIGSEL_FIELD_MASK))
+ return false;
+
+ return true; //start_periodic_measurement();
+
+ }
+ }
+ return false;
+}
+
+int16_t Si7210::read() {
+ //Read the two regs
+ int16_t temp = 0;
+ if (!get_field_strength(&temp)) {
+ temp = 0;
+ }
+ return temp;
+}
+
+bool Si7210::write_reg(const uint8_t reg, const uint8_t mask, const uint8_t val) {
+ uint8_t temp = 0;
+ if (mask) {
+ if (!read_reg(reg, &temp)) {
+ return false;
+ }
+ temp &= mask;
+ }
+ temp |= val;
+ return FRToSI2C::Mem_Write(SI7210_ADDRESS, reg, &temp, 1);
+}
+
+bool Si7210::read_reg(const uint8_t reg, uint8_t* val) {
+ return FRToSI2C::Mem_Read(SI7210_ADDRESS, reg, val, 1);
+}
+
+bool Si7210::start_periodic_measurement() {
+ /* Enable periodic wakeup */
+ if (!write_reg(SI7210_CTRL3, (uint8_t) ~SL_TIMEENA_MASK, SL_TIMEENA_MASK))
+ return false;
+
+ /* Start measurement */
+ /* Change to ~STOP_MASK with STOP_MASK */
+ return write_reg( SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, 0);
+
+}
+
+bool Si7210::get_field_strength(int16_t* field) {
+ *field = 0;
+ uint8_t val = 0;
+ FRToSI2C::wakePart(SI7210_ADDRESS);
+
+ if (!write_reg( SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, STOP_MASK))
+ return false;
+
+ /* Read most-significant byte */
+ if (!read_reg( SI7210_DSPSIGM, &val))
+ return false;
+ *field = (val & DSP_SIGM_DATA_MASK) << 8;
+
+ /* Read least-significant byte of data */
+ if (!read_reg( SI7210_DSPSIGL, &val))
+ return false;
+
+ *field += val;
+ *field -= 16384U;
+ //field is now a +- measurement
+ //In units of 0.0125 mT
+ // Aka 12.5uT
+ //Clear flags
+ read_reg( SI7210_CTRL1, &val);
+ read_reg( SI7210_CTRL2, &val);
+//Start next one
+
+ /* Use a burst size of 128/4096 samples in FIR and IIR modes */
+ write_reg( SI7210_CTRL4, 0, DF_BURSTSIZE_128 | DF_BW_4096);
+
+ /* Selet field strength measurement */
+ write_reg( SI7210_DSPSIGSEL, 0, DSP_SIGSEL_FIELD_MASK);
+
+ /* Start measurement */
+ write_reg( SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, ONEBURST_MASK);
+
+ return true;
+}
+
+bool Si7210::set_high_range() {
+ //To set the unit into 200mT range, no magnet temperature calibration
+ // We want to copy OTP 0x27->0x2C into a0->a5
+ uint8_t base_addr = 0x27; // You can change this to pick the temp calibration
+ bool worked = true;
+ uint8_t val = 0;
+
+ /* Load A0 register */
+ worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr);
+ worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
+ worked &= read_reg( SI7210_OTP_DATA, &val);
+ worked &= write_reg( SI7210_A0, 0, val);
+
+ /* Load A1 register */
+ worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 1);
+ worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
+ worked &= read_reg( SI7210_OTP_DATA, &val);
+ worked &= write_reg( SI7210_A1, 0, val);
+
+ /* Load A2 register */
+ worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 2);
+ worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
+ worked &= read_reg( SI7210_OTP_DATA, &val);
+ worked &= write_reg( SI7210_A2, 0, val);
+
+ /* Load A3 register */
+ worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 3);
+ worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
+ worked &= read_reg( SI7210_OTP_DATA, &val);
+ worked &= write_reg( SI7210_A3, 0, val);
+
+ /* Load A4 register */
+ worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 4);
+ worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
+ worked &= read_reg( SI7210_OTP_DATA, &val);
+ worked &= write_reg( SI7210_A4, 0, val);
+
+ /* Load A5 register */
+ worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 5);
+ worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
+ worked &= read_reg( SI7210_OTP_DATA, &val);
+ worked &= write_reg( SI7210_A5, 0, val);
+ return worked;
+}