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