Skyward boardcore
Loading...
Searching...
No Matches
BMP280I2C.cpp
Go to the documentation of this file.
1/* Copyright (c) 2021 Skyward Experimental Rocketry
2 * Author: Alberto Nidasio
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 "BMP280I2C.h"
24
26#include <math.h>
27
28using namespace std;
29
30namespace Boardcore
31{
32
33const BMP280I2C::BMP280Config BMP280I2C::BMP280_DEFAULT_CONFIG = {
34 0, 0, SLEEP_MODE, SKIPPED, SKIPPED, 0, FILTER_OFF, STB_TIME_0_5};
35
36const BMP280I2C::BMP280Config BMP280I2C::BMP280_CONFIG_ALL_ENABLED = {
37 0,
38 0,
39 NORMAL_MODE,
40 OVERSAMPLING_16,
41 OVERSAMPLING_2,
42 0,
43 FILTER_COEFF_16,
44 STB_TIME_0_5};
45
46const BMP280I2C::BMP280Config BMP280I2C::BMP280_CONFIG_TEMP_SINGLE = {
47 0, 0, FORCED_MODE, SKIPPED, OVERSAMPLING_1, 0, FILTER_OFF, STB_TIME_0_5};
48
49BMP280I2C::BMP280I2C(I2C& bus, BMP280Config config) : bus(bus), config(config)
50{
51}
52
54{
55 if (!checkWhoAmI())
56 {
57 LOG_ERR(logger, "Invalid WHO AM I");
58
60 return false;
61 }
62
63 if (!reset())
64 return false;
65 miosix::Thread::sleep(3);
66
67 loadCompensationParameters();
68
69 // Read once the temperature to compute fineTemperature
70 setConfiguration(BMP280_CONFIG_TEMP_SINGLE);
71 miosix::Thread::sleep(
74
75 // Set the target configuration
76 setConfiguration();
77
78 BMP280Config readBackConfig = readConfiguration();
79
80 // Check if the configuration on the device matches ours
81 if (config.bytes.ctrlPressureAndTemperature !=
82 readBackConfig.bytes.ctrlPressureAndTemperature ||
83 config.bytes.config != readBackConfig.bytes.config)
84 {
85 LOG_ERR(logger, "Device configuration incorrect, setup failed");
86
88 return false;
89 }
90
91 return true;
92}
93
95{
96 config.bits.mode = mode;
97
98 setConfiguration();
99}
100
102{
103 config.bits.oversamplingPressure = oversampling;
104
105 setConfiguration();
106}
107
109{
110 config.bits.oversamplingTemperature = oversampling;
111
112 setConfiguration();
113}
114
116{
117 config.bits.filter = filterCoeff;
118
119 setConfiguration();
120}
121
123{
124 config.bits.standbyTime = standbyTime;
125
126 setConfiguration();
127}
128
130{
131 uint8_t buffer[3];
132 if (bus.readFromRegister(slaveConfig, REG_PRESS_MSB, buffer, 3))
133 {
134 int32_t adc_P = ((uint32_t)buffer[0]) << 12;
135 adc_P |= ((uint32_t)buffer[1]) << 4;
136 adc_P |= (buffer[2] >> 4) & 0x0F;
137
138 PressureData data;
140 data.pressure = compensatePressure(adc_P);
141 data.pressure /= 256; // Convert to Pa
142
143 return data;
144 }
145 else
146 {
148 return lastSample;
149 }
150}
151
153{
154 uint8_t buffer[3];
155 if (bus.readFromRegister(slaveConfig, REG_TEMP_MSB, buffer, 3))
156 {
157 int32_t adcTemperature = ((uint32_t)buffer[0]) << 12;
158 adcTemperature |= ((uint32_t)buffer[1]) << 4;
159 adcTemperature |= (buffer[2] >> 4) & 0x0F;
160
161 fineTemperature = computeFineTemperature(adcTemperature);
162
163 TemperatureData data;
165 data.temperature = compensateTemperature(fineTemperature);
166 data.temperature /= 100; // Convert to to DegC
167
168 return data;
169 }
170 else
171 {
173 return lastSample;
174 }
175}
176
178{
179 // TODO: This formula is not present in the BMP280's datasheet, it should
180 // be checked
181 return ceil(1.25 + (2.3 * config.bits.oversamplingTemperature) +
182 (2.3 * config.bits.oversamplingPressure + 0.575));
183}
184
186{
187 return calculateMaxMeasurementTime(config);
188}
189
190bool BMP280I2C::selfTest() { return checkWhoAmI(); }
191
193{
194 // TODO: implement selective read!
195
196 uint8_t buffer[6];
197 if (bus.readFromRegister(slaveConfig, REG_PRESS_MSB, buffer, 6))
198 {
199 BMP280Data data;
200
201 int32_t adcTemperature = ((uint32_t)buffer[3]) << 12;
202 adcTemperature |= ((uint32_t)buffer[4]) << 4;
203 adcTemperature |= (buffer[5] >> 4) & 0x0F;
204
205 int32_t adc_P = ((uint32_t)buffer[0]) << 12;
206 adc_P |= ((uint32_t)buffer[1]) << 4;
207 adc_P |= (buffer[2] >> 4) & 0x0F;
208
209 // Compensate temperature
210 fineTemperature = computeFineTemperature(adcTemperature);
212 data.temperature = compensateTemperature(fineTemperature);
213 data.temperature /= 100; // Convert to to DegC
214
215 // Compensate pressure
217 data.pressure = compensatePressure(adc_P);
218 data.pressure /= 256; // Convert to Pa
219
220 return data;
221 }
222 else
223 {
225 return lastSample;
226 }
227}
228
229bool BMP280I2C::reset()
230{
231 if (!bus.writeRegister(slaveConfig, REG_RESET, 0xB6))
232 {
234 return false;
235 }
236
237 return true;
238}
239
240bool BMP280I2C::checkWhoAmI()
241{
242 uint8_t whoAmIValue;
243
244 if (bus.readRegister(slaveConfig, REG_ID, whoAmIValue))
245 {
246 return whoAmIValue == REG_ID_VAL;
247 }
248 else
249 {
251 return false;
252 }
253}
254
255void BMP280I2C::setConfiguration() { setConfiguration(config); }
256
257void BMP280I2C::setConfiguration(BMP280Config config)
258{
259 if (!bus.writeRegister(slaveConfig, REG_CONFIG, config.bytes.config))
260 {
261 LOG_ERR(logger, "Error while writing to register REG_CONFIG");
262 return;
263 }
264
265 if (!bus.writeRegister(slaveConfig, REG_CTRL_MEAS,
266 config.bytes.ctrlPressureAndTemperature))
267 {
268 LOG_ERR(logger, "Error while writing to register REG_CTRL_MEAS");
269 return;
270 }
271}
272
273BMP280I2C::BMP280Config BMP280I2C::readConfiguration()
274{
275 BMP280Config tmp;
276
277 if (bus.readFromRegister(slaveConfig, REG_STATUS, (uint8_t*)&tmp, 3))
278 {
279 return tmp;
280 }
281 else
282 {
285 }
286}
287
288void BMP280I2C::loadCompensationParameters()
289{
290 // Read first batch of compensation parameters
291 if (!bus.readFromRegister(slaveConfig, REG_CALIB_0, (uint8_t*)&compParams,
292 25))
293 {
295 return;
296 }
297}
298
299int32_t BMP280I2C::computeFineTemperature(int32_t adcTemperature)
300{
301 int32_t var1, var2;
302 var1 = ((((adcTemperature >> 3) - ((int32_t)compParams.bits.dig_T1 << 1))) *
303 ((int32_t)compParams.bits.dig_T2)) >>
304 11;
305 var2 = (((((adcTemperature >> 4) - ((int32_t)compParams.bits.dig_T1)) *
306 ((adcTemperature >> 4) - ((int32_t)compParams.bits.dig_T1))) >>
307 12) *
308 ((int32_t)compParams.bits.dig_T3)) >>
309 14;
310 return var1 + var2;
311}
312
313int32_t BMP280I2C::compensateTemperature(int32_t fineTemperature)
314{
315 return (fineTemperature * 5 + 128) >> 8;
316}
317
318uint32_t BMP280I2C::compensatePressure(int32_t adc_P)
319{
320 int64_t var1, var2, p;
321 var1 = ((int64_t)fineTemperature) - 128000;
322 var2 = var1 * var1 * (int64_t)compParams.bits.dig_P6;
323 var2 = var2 + ((var1 * (int64_t)compParams.bits.dig_P5) << 17);
324 var2 = var2 + (((int64_t)compParams.bits.dig_P4) << 35);
325 var1 = ((var1 * var1 * (int64_t)compParams.bits.dig_P3) >> 8) +
326 ((var1 * ((int64_t)compParams.bits.dig_P2) << 12));
327 var1 =
328 ((((int64_t)1) << 47) + var1) * ((int64_t)compParams.bits.dig_P1) >> 33;
329 if (var1 == 0)
330 return 0; // avoid exception caused by division by zero
331 p = 1048576 - adc_P;
332 p = (((p << 31) - var2) * 3125) / var1;
333 var1 = (((int64_t)compParams.bits.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
334 var2 = (((int64_t)compParams.bits.dig_P8) * p) >> 19;
335 p = ((p + var1 + var2) >> 8) + (((int64_t)compParams.bits.dig_P7) << 4);
336 return (uint32_t)p;
337}
338
339} // namespace Boardcore
#define LOG_ERR(logger,...)
SensorErrors lastError
Definition Sensor.h:54
void setSensorMode(Mode mode)
Sets the sensor mode.
Definition BMP280I2C.cpp:94
bool init() override
Initialize the device with the specified configuration.
Definition BMP280I2C.cpp:53
BMP280I2C(I2C &bus, BMP280Config config=BMP280_CONFIG_ALL_ENABLED)
Definition BMP280I2C.cpp:49
void setTemperatureOversampling(Oversampling oversampling)
Sets the oversampling for temperature readings, use SKIPPED to disable temperature sampling.
void setPressureOversampling(Oversampling oversampling)
Sets the oversampling for pressure readings, use SKIPPED to disable pressure sampling.
PressureData readPressure()
Reads only the pressure, does not set the configuration.
BMP280Data sampleImpl() override
Read a data sample from the sensor. In case of errors, the method should return the last available co...
static const BMP280Config BMP280_CONFIG_TEMP_SINGLE
Definition BMP280I2C.h:147
void setStandbyTime(StandbyTime standbyTime)
Sets the standby time between readings in normal mode.
bool selfTest() override
Reads the WHO AM I register.
TemperatureData readTemperature()
Reads only the temperature, does not set the configuration.
static constexpr uint8_t REG_ID_VAL
Who am I value.
Definition BMP280I2C.h:138
static const BMP280Config BMP280_DEFAULT_CONFIG
Datasheet values for indoor navigation.
Definition BMP280I2C.h:141
unsigned int getMaxMeasurementTime()
static unsigned int calculateMaxMeasurementTime(BMP280Config config)
Maximum measurement time formula from datasheet page 51.
static const BMP280Config BMP280_CONFIG_ALL_ENABLED
Temperature enabled in forced mode.
Definition BMP280I2C.h:144
void setFilterCoeff(FilterCoeff filterCoeff)
Sets the coefficient for the IIR filter (applied to temperature and pressure)
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 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
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
Definition WIZ5500.h:318
struct Boardcore::BMP280I2C::BMP280Config::@5 bytes