Skyward boardcore
Loading...
Searching...
No Matches
LPS28DFW.cpp
Go to the documentation of this file.
1/* Copyright (c) 2023 Skyward Experimental Rocketry
2 * Author: Emilio Corigliano
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include "LPS28DFW.h"
24
26
27#include "LPS28DFWDefs.h"
28
29using namespace Boardcore::LPS28DFWDefs;
30
31namespace Boardcore
32{
34 : i2cConfig{sensorConfig.sa0 ? lsp28dfwAddress1 : lsp28dfwAddress0,
35 I2CDriver::Addressing::BIT7, I2CDriver::Speed::MAX_SPEED},
36 i2c(i2c), sensorConfig(sensorConfig)
37{
38 pressureSensitivity = (sensorConfig.fsr == FullScaleRange::FS_1260
39 ? pressureSensitivity1260hPa
40 : pressureSensitivity4060hPa);
41}
42
44{
45 if (isInitialized)
46 {
47 LOG_ERR(logger, "Attempted to initialized sensor twice but failed");
49 return false;
50 }
51
52 // Setting the actual sensor configurations (Mode, ODR, AVG, FSR, DRDY)
53 if (!setConfig(sensorConfig))
54 {
55 LOG_ERR(logger, "Configuration not applied correctly");
57 return false;
58 }
59
61 isInitialized = true;
62 return true;
63}
64
66{
67 // Since the sensor doesn't provide any self-test feature we just try to
68 // probe the sensor and read his whoami register.
69 if (!isInitialized)
70 {
71 LOG_ERR(logger, "Invoked selfTest() but sensor was uninitialized");
73 return false;
74 }
75
76 // Trying to probe the sensor to check if it is connected
77 if (!i2c.probe(i2cConfig))
78 {
79 LOG_ERR(logger,
80 "Can't communicate with the sensor or sensor not attached");
82 return false;
83 }
84
85 // Reading the whoami value to assure communication
86 uint8_t whoamiValue{0};
87 if (!i2c.readRegister(i2cConfig, WHO_AM_I, whoamiValue))
88 {
89 LOG_ERR(logger, "Can't communicate with the sensor");
91 return false;
92 }
93
94 // Checking the whoami value to assure correct communication
95 if (whoamiValue != WHO_AM_I_VALUE)
96 {
97 LOG_ERR(logger,
98 "WHO_AM_I value differs from expectation: read 0x{02x} "
99 "but expected 0x{02x}",
100 whoamiValue, WHO_AM_I_VALUE);
102 return false;
103 }
104
105 return true;
106}
107
108bool LPS28DFW::setConfig(const SensorConfig& newSensorConfig)
109{
110 // Setting the FIFO_CTRL register to the correct mode (according to the
111 // ODR set: BYPASS for the one shot mode and CONTINUOUS for the
112 // continuous mode).
113 if (!i2c.writeRegister(
114 i2cConfig, FIFO_CTRL,
115 (newSensorConfig.odr == ODR::ONE_SHOT ? FIFO_CTRL::BYPASS
116 : FIFO_CTRL::CONTINUOUS)))
117 {
119 return false;
120 }
121
122 if (!(setFullScaleRange(sensorConfig.fsr) && setAverage(sensorConfig.avg) &&
123 setOutputDataRate(sensorConfig.odr) &&
124 setDRDYInterrupt(sensorConfig.drdy)))
125 {
126 LOG_ERR(logger, "Sensor not configured");
127 return false;
128 }
129
130 return true;
131}
132
134{
135 // Since the CTRL_REG1 contains only the AVG and ODR settings, we use the
136 // internal driver state to set the register with the wanted ODR and AVG
137 // without previously reading it. This allows to avoid a useless
138 // transaction.
139 if (!i2c.writeRegister(i2cConfig, CTRL_REG1, sensorConfig.odr | avg))
140 {
142 return false;
143 }
144
145 sensorConfig.avg = avg;
146 return true;
147}
148
150{
151 // Since the CTRL_REG1 contains only the AVG and ODR settings, we use the
152 // internal driver state to set the register with the wanted ODR and AVG
153 // without previously reading it. This allows to avoid a useless
154 // transaction.
155 if (!i2c.writeRegister(i2cConfig, CTRL_REG1, odr | sensorConfig.avg))
156 {
158 return false;
159 }
160
161 sensorConfig.odr = odr;
162 return true;
163}
164
166{
167 uint8_t ctrl_reg2;
168 if (!i2c.readRegister(i2cConfig, CTRL_REG2, ctrl_reg2))
169 {
171 return false;
172 }
173
174 if (fs == FullScaleRange::FS_1260)
175 {
176 pressureSensitivity = pressureSensitivity1260hPa;
177 ctrl_reg2 = (ctrl_reg2 & ~CTRL_REG2::FS_MODE);
178 }
179 else
180 {
181 pressureSensitivity = pressureSensitivity4060hPa;
182 ctrl_reg2 = (ctrl_reg2 | CTRL_REG2::FS_MODE);
183 }
184
185 if (!i2c.writeRegister(i2cConfig, CTRL_REG2, ctrl_reg2))
186 {
188 return false;
189 }
190
191 sensorConfig.fsr = fs;
192 return true;
193}
194
196{
197 if (!i2c.writeRegister(i2cConfig, CTRL_REG4, (drdy ? (INT_EN | DRDY) : 0)))
198 {
200 return false;
201 }
202
203 sensorConfig.drdy = drdy;
204 return true;
205}
206
207float LPS28DFW::convertPressure(uint8_t pressXL, uint8_t pressL, uint8_t pressH)
208{
209 // Pressure conversion
210 // sign extending the 27-bit value: shifting to the right a signed type
211 // extends its sign. So positioning the bytes shifted to the left of 8
212 // bits, casting the result in a signed int8_t and then shifting the
213 // result to the right of 8 bits will make the work.
214 int32_t press_temp =
215 ((int32_t)((pressH << 24) | (pressL << 16) | (pressXL << 8))) >> 8;
216 return ((float)press_temp / pressureSensitivity);
217}
218
219float LPS28DFW::convertTemperature(uint8_t tempL, uint8_t tempH)
220{
221 // Temperature conversion
222 int16_t temp_temp = (tempH << 8) | (tempL << 0);
223 return ((float)temp_temp) / temperatureSensitivity;
224}
225
227{
228 uint8_t statusValue{0};
229 uint8_t val[5] = {0};
230 LPS28DFWData data;
231
233
234 if (sensorConfig.odr == ODR::ONE_SHOT)
235 {
236 uint8_t ctrl_reg2_val{0};
237
238 // Triggering sampling
239 if (!(i2c.readRegister(i2cConfig, CTRL_REG2, ctrl_reg2_val) &&
240 i2c.writeRegister(i2cConfig, CTRL_REG2,
241 ctrl_reg2_val | CTRL_REG2::ONE_SHOT_START)))
242 {
244 return lastSample;
245 }
246
247 // Poll status register until the sample is ready
248 do
249 {
250 if (!i2c.readRegister(i2cConfig, STATUS, statusValue))
251 {
253 return lastSample;
254 }
255 } while ((statusValue & (STATUS::P_DA | STATUS::T_DA)) !=
256 (STATUS::P_DA | STATUS::T_DA));
257 }
258 else
259 {
260 // read status register value
261 if (!i2c.readRegister(i2cConfig, STATUS, statusValue))
262 {
264 return lastSample;
265 }
266 }
267
269
270 // reading 5 bytes if also Temperature new sample, otherwise only the 3
271 // pressure bytes
272 if (!i2c.readFromRegister(i2cConfig, PRESS_OUT_XL, val,
273 ((statusValue & STATUS::T_DA) ? 5 : 3)))
274 {
276 return lastSample;
277 }
278
279 // If pressure new data present
280 if (statusValue & STATUS::P_DA)
281 {
282 data.pressureTimestamp = ts;
283 data.pressure = convertPressure(val[0], val[1], val[2]);
284 }
285 else
286 {
290 }
291
292 // If temperature new data present
293 if (statusValue & STATUS::T_DA)
294 {
295 data.temperatureTimestamp = ts;
296 data.temperature = convertTemperature(val[3], val[4]);
297 }
298 else
299 {
302 }
303
304 return data;
305}
306
307} // namespace Boardcore
#define LOG_ERR(logger,...)
SensorErrors lastError
Definition Sensor.h:54
Low level driver for I2C peripherals.
Definition I2CDriver.h:57
High level driver for the I2C peripherals.
Definition I2C.h:40
bool readFromRegister(const I2CDriver::I2CSlaveConfig &slaveConfig, const uint8_t registerAddress, void *buffer, const size_t nBytes)
Non blocking operation to read n-bytes from register from a slave.
Definition I2C.cpp:189
bool probe(const I2CDriver::I2CSlaveConfig &slaveConfig)
Non blocking operation to check if a slave is available.
Definition I2C.cpp:198
bool writeRegister(const I2CDriver::I2CSlaveConfig &slaveConfig, const uint8_t registerAddress, const uint8_t registerContent)
Non blocking operation to write an 8-bit register from a slave.
Definition I2C.cpp:111
bool readRegister(const I2CDriver::I2CSlaveConfig &slaveConfig, const uint8_t registerAddress, uint8_t &registerContent)
Non blocking operation to read an 8-bit register from a slave.
Definition I2C.cpp:48
LPS28DFWData sampleImpl() override
Read a data sample from the sensor. In case of errors, the method should return the last available co...
Definition LPS28DFW.cpp:226
bool setOutputDataRate(ODR odr)
Sets and saves the output data rate.
Definition LPS28DFW.cpp:149
bool setAverage(AVG avg)
Sets and saves the oversampling on the sensor.
Definition LPS28DFW.cpp:133
ODR
Enumeration for Output Data Rate Configuration.
Definition LPS28DFW.h:58
FullScaleRange
Enumeration for the full scale range to set on the sensor. Available are 1260 hPa or 4060 hPa.
Definition LPS28DFW.h:45
AVG
Enumeration for the oversampling to set on the sensor.
Definition LPS28DFW.h:81
bool setConfig(const SensorConfig &config)
Sets and saves the configurations passed on the parameters.
Definition LPS28DFW.cpp:108
bool setDRDYInterrupt(bool drdy)
Sets and saves the full scale range.
Definition LPS28DFW.cpp:195
LPS28DFW(I2C &i2c, SensorConfig sensorConfig)
Constructor that stores the initial settings (without applying them to the sensor).
Definition LPS28DFW.cpp:33
bool selfTest() override
The self test method returns true if we read the right whoami value. We can't make a better self test...
Definition LPS28DFW.cpp:65
bool setFullScaleRange(FullScaleRange fs)
Sets and saves the full scale range.
Definition LPS28DFW.cpp:165
bool init() override
Initializes the sensor with the current settings.
Definition LPS28DFW.cpp:43
Various LPS28DFW register/enums definitions.
@ FS_MODE
Full-scale selection.
@ WHO_AM_I
Device Who am I register.
@ PRESS_OUT_XL
Pressure output value LSB data.
@ CTRL_REG1
Control Register 1 [ODR, AVG].
@ DRDY
Date-ready signal on INT_DRDY pin.
@ INT_EN
Interrupt signal on INT_DRDY pin.
uint64_t getTimestamp()
Returns the current timer value in microseconds.
This file includes all the types the logdecoder script will decode.
@ INVALID_WHOAMI
Definition SensorData.h:40
Struct that sums up all the settings of the sensor.
Definition LPS28DFW.h:95
AVG avg
Average avg samples.
Definition LPS28DFW.h:99
ODR odr
Output data rate.
Definition LPS28DFW.h:100
bool drdy
Enable Interrupt for Data Ready.
Definition LPS28DFW.h:101
FullScaleRange fsr
Full scale range.
Definition LPS28DFW.h:98
Struct for the LPS28DFW barometer data. Pressures stored in Pa and Temperature in °C.