1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
/*
* 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_defines.h"
#include "accelerometers_common.h"
#include <Si7210.h>
bool Si7210::detect() { return ACCEL_I2C_CLASS::wakePart(SI7210_ADDRESS); }
bool Si7210::init() {
// Turn on auto increment and sanity check ID
// Load OTP cal
uint8_t temp;
if (ACCEL_I2C_CLASS::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 ACCEL_I2C_CLASS::Mem_Write(SI7210_ADDRESS, reg, &temp, 1);
}
bool Si7210::read_reg(const uint8_t reg, uint8_t *val) { return ACCEL_I2C_CLASS::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;
ACCEL_I2C_CLASS::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;
}
|