Set blackbox file handler to NULL after closing file
[inav.git] / src / main / drivers / barometer / barometer_bmp388.c
blob0abdc6ab7b567e5f47bb1ac5c8e472b8ef062df4
1 /*
2 * This file is part of INAV.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
20 * BMP388 Driver author: Dominic Clifton
21 * INAV port: Michel Pastor
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <string.h>
28 #include <platform.h>
29 #include "build/build_config.h"
30 #include "build/debug.h"
31 #include "common/utils.h"
32 #include "common/log.h" // XXX
34 #include "drivers/time.h"
35 #include "drivers/io.h"
36 #include "drivers/bus.h"
37 #include "drivers/barometer/barometer.h"
38 #include "drivers/barometer/barometer_bmp388.h"
40 #if defined(USE_BARO) && (defined(USE_BARO_BMP388) || defined(USE_BARO_SPI_BMP388))
42 #define BMP388_I2C_ADDR (0x76) // same as BMP280/BMP180
43 #define BMP388_DEFAULT_CHIP_ID (0x50) // from https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/bmp3_defs.h#L130
45 #define BMP388_CMD_REG (0x7E)
46 #define BMP388_RESERVED_UPPER_REG (0x7D)
47 // everything between BMP388_RESERVED_UPPER_REG and BMP388_RESERVED_LOWER_REG is reserved.
48 #define BMP388_RESERVED_LOWER_REG (0x20)
49 #define BMP388_CONFIG_REG (0x1F)
50 #define BMP388_RESERVED_0x1E_REG (0x1E)
51 #define BMP388_ODR_REG (0x1D)
52 #define BMP388_OSR_REG (0x1C)
53 #define BMP388_PWR_CTRL_REG (0x1B)
54 #define BMP388_IF_CONFIG_REG (0x1A)
55 #define BMP388_INT_CTRL_REG (0x19)
56 #define BMP388_FIFO_CONFIG_2_REG (0x18)
57 #define BMP388_FIFO_CONFIG_1_REG (0x17)
58 #define BMP388_FIFO_WTM_1_REG (0x16)
59 #define BMP388_FIFO_WTM_0_REG (0x15)
60 #define BMP388_FIFO_DATA_REG (0x14)
61 #define BMP388_FIFO_LENGTH_1_REG (0x13)
62 #define BMP388_FIFO_LENGTH_0_REG (0x12)
63 #define BMP388_INT_STATUS_REG (0x11)
64 #define BMP388_EVENT_REG (0x10)
65 #define BMP388_SENSORTIME_3_REG (0x0F) // BME780 only
66 #define BMP388_SENSORTIME_2_REG (0x0E)
67 #define BMP388_SENSORTIME_1_REG (0x0D)
68 #define BMP388_SENSORTIME_0_REG (0x0C)
69 #define BMP388_RESERVED_0x0B_REG (0x0B)
70 #define BMP388_RESERVED_0x0A_REG (0x0A)
72 // see friendly register names below
73 #define BMP388_DATA_5_REG (0x09)
74 #define BMP388_DATA_4_REG (0x08)
75 #define BMP388_DATA_3_REG (0x07)
76 #define BMP388_DATA_2_REG (0x06)
77 #define BMP388_DATA_1_REG (0x05)
78 #define BMP388_DATA_0_REG (0x04)
80 #define BMP388_STATUS_REG (0x03)
81 #define BMP388_ERR_REG (0x02)
82 #define BMP388_RESERVED_0x01_REG (0x01)
83 #define BMP388_CHIP_ID_REG (0x00)
85 // friendly register names, from datasheet 4.3.4
86 #define BMP388_PRESS_MSB_23_16_REG BMP388_DATA_2_REG
87 #define BMP388_PRESS_LSB_15_8_REG BMP388_DATA_1_REG
88 #define BMP388_PRESS_XLSB_7_0_REG BMP388_DATA_0_REG
90 // friendly register names, from datasheet 4.3.5
91 #define BMP388_TEMP_MSB_23_16_REG BMP388_DATA_5_REG
92 #define BMP388_TEMP_LSB_15_8_REG BMP388_DATA_4_REG
93 #define BMP388_TEMP_XLSB_7_0_REG BMP388_DATA_3_REG
95 #define BMP388_DATA_FRAME_SIZE ((BMP388_DATA_5_REG - BMP388_DATA_0_REG) + 1) // +1 for inclusive
97 // from Datasheet 3.3
98 #define BMP388_MODE_SLEEP (0x00)
99 #define BMP388_MODE_FORCED (0x01)
100 #define BMP388_MODE_NORMAL (0x02)
102 #define BMP388_CALIRATION_LOWER_REG (0x30) // See datasheet 4.3.19, "calibration data"
103 #define BMP388_TRIMMING_NVM_PAR_T1_LSB_REG (0x31) // See datasheet 3.11.1 "Memory map trimming coefficients"
104 #define BMP388_TRIMMING_NVM_PAR_P11_REG (0x45) // See datasheet 3.11.1 "Memory map trimming coefficients"
105 #define BMP388_CALIRATION_UPPER_REG (0x57)
107 #define BMP388_TRIMMING_DATA_LENGTH ((BMP388_TRIMMING_NVM_PAR_P11_REG - BMP388_TRIMMING_NVM_PAR_T1_LSB_REG) + 1) // +1 for inclusive
109 #define BMP388_OVERSAMP_1X (0x00)
110 #define BMP388_OVERSAMP_2X (0x01)
111 #define BMP388_OVERSAMP_4X (0x02)
112 #define BMP388_OVERSAMP_8X (0x03)
113 #define BMP388_OVERSAMP_16X (0x04)
114 #define BMP388_OVERSAMP_32X (0x05)
116 // INT_CTRL register
117 #define BMP388_INT_OD_BIT 0
118 #define BMP388_INT_LEVEL_BIT 1
119 #define BMP388_INT_LATCH_BIT 2
120 #define BMP388_INT_FWTM_EN_BIT 3
121 #define BMP388_INT_FFULL_EN_BIT 4
122 #define BMP388_INT_RESERVED_5_BIT 5
123 #define BMP388_INT_DRDY_EN_BIT 6
124 #define BMP388_INT_RESERVED_7_BIT 7
126 // OSR register
127 #define BMP388_OSR_P_BIT 0 // to 2
128 #define BMP388_OSR4_T_BIT 3 // to 5
129 #define BMP388_OSR_P_MASK (0x03) // -----111
130 #define BMP388_OSR4_T_MASK (0x38) // --111---
132 // configure pressure and temperature oversampling, forced sampling mode
133 #define BMP388_PRESSURE_OSR (BMP388_OVERSAMP_8X)
134 #define BMP388_TEMPERATURE_OSR (BMP388_OVERSAMP_1X)
136 // see Datasheet 3.11.1 Memory Map Trimming Coefficients
137 typedef struct bmp388_calib_param_s {
138 uint16_t T1;
139 uint16_t T2;
140 int8_t T3;
141 int16_t P1;
142 int16_t P2;
143 int8_t P3;
144 int8_t P4;
145 uint16_t P5;
146 uint16_t P6;
147 int8_t P7;
148 int8_t P8;
149 int16_t P9;
150 int8_t P10;
151 int8_t P11;
152 } __attribute__((packed)) bmp388_calib_param_t;
154 STATIC_ASSERT(sizeof(bmp388_calib_param_t) == BMP388_TRIMMING_DATA_LENGTH, bmp388_calibration_structure_incorrectly_packed);
156 static bmp388_calib_param_t bmp388_cal;
157 // uncompensated pressure and temperature
158 static uint32_t bmp388_up = 0;
159 static uint32_t bmp388_ut = 0;
160 static uint8_t sensor_data[BMP388_DATA_FRAME_SIZE+1];
162 static int64_t t_lin = 0;
164 static bool bmp388StartUT(baroDev_t *baro);
165 static bool bmp388GetUT(baroDev_t *baro);
166 static bool bmp388StartUP(baroDev_t *baro);
167 static bool bmp388GetUP(baroDev_t *baro);
169 static bool bmp388Calculate(baroDev_t *baro, int32_t *pressure, int32_t *temperature);
171 static bool bmp388BeginForcedMeasurement(busDevice_t *busdev)
173 // enable pressure measurement, temperature measurement, set power mode and start sampling
174 uint8_t mode = BMP388_MODE_FORCED << 4 | 1 << 1 | 1 << 0;
175 return busWrite(busdev, BMP388_PWR_CTRL_REG, mode);
178 static bool bmp388StartUT(baroDev_t *baro)
180 UNUSED(baro);
181 // dummy
182 return true;
185 static bool bmp388GetUT(baroDev_t *baro)
187 UNUSED(baro);
188 // dummy
189 return true;
192 static bool bmp388StartUP(baroDev_t *baro)
194 // start measurement
195 return bmp388BeginForcedMeasurement(baro->busDev);
198 static bool bmp388GetUP(baroDev_t *baro)
200 if (baro->busDev->busType == BUSTYPE_SPI) {
201 // In SPI mode, first byte read is a dummy byte
202 busReadBuf(baro->busDev, BMP388_DATA_0_REG, &sensor_data[0], BMP388_DATA_FRAME_SIZE + 1);
203 } else {
204 // In I2C mode, no dummy byte is read
205 busReadBuf(baro->busDev, BMP388_DATA_0_REG, &sensor_data[1], BMP388_DATA_FRAME_SIZE);
208 bmp388_up = sensor_data[1] << 0 | sensor_data[2] << 8 | sensor_data[3] << 16;
209 bmp388_ut = sensor_data[4] << 0 | sensor_data[5] << 8 | sensor_data[6] << 16;
210 return true;
213 // Returns temperature in DegC, resolution is 0.01 DegC. Output value of "5123" equals 51.23 DegC
214 static int64_t bmp388CompensateTemperature(uint32_t uncomp_temperature)
216 uint64_t partial_data1;
217 uint64_t partial_data2;
218 uint64_t partial_data3;
219 int64_t partial_data4;
220 int64_t partial_data5;
221 int64_t partial_data6;
222 int64_t comp_temp;
224 partial_data1 = uncomp_temperature - (256 * bmp388_cal.T1);
225 partial_data2 = bmp388_cal.T2 * partial_data1;
226 partial_data3 = partial_data1 * partial_data1;
227 partial_data4 = (int64_t)partial_data3 * bmp388_cal.T3;
228 partial_data5 = ((int64_t)(partial_data2 * 262144) + partial_data4);
229 partial_data6 = partial_data5 / 4294967296;
230 /* Update t_lin, needed for pressure calculation */
231 t_lin = partial_data6;
232 comp_temp = (int64_t)((partial_data6 * 25) / 16384);
234 return comp_temp;
237 static uint64_t bmp388CompensatePressure(uint32_t uncomp_pressure)
239 int64_t partial_data1;
240 int64_t partial_data2;
241 int64_t partial_data3;
242 int64_t partial_data4;
243 int64_t partial_data5;
244 int64_t partial_data6;
245 int64_t offset;
246 int64_t sensitivity;
247 uint64_t comp_press;
249 partial_data1 = t_lin * t_lin;
250 partial_data2 = partial_data1 / 64;
251 partial_data3 = (partial_data2 * t_lin) / 256;
252 partial_data4 = (bmp388_cal.P8 * partial_data3) / 32;
253 partial_data5 = (bmp388_cal.P7 * partial_data1) * 16;
254 partial_data6 = (bmp388_cal.P6 * t_lin) * 4194304;
255 offset = (bmp388_cal.P5 * 140737488355328) + partial_data4 + partial_data5 + partial_data6;
257 partial_data2 = (bmp388_cal.P4 * partial_data3) / 32;
258 partial_data4 = (bmp388_cal.P3 * partial_data1) * 4;
259 partial_data5 = (bmp388_cal.P2 - 16384) * t_lin * 2097152;
260 sensitivity = ((bmp388_cal.P1 - 16384) * 70368744177664) + partial_data2 + partial_data4 + partial_data5;
262 partial_data1 = (sensitivity / 16777216) * uncomp_pressure;
263 partial_data2 = bmp388_cal.P10 * t_lin;
264 partial_data3 = partial_data2 + (65536 * bmp388_cal.P9);
265 partial_data4 = (partial_data3 * uncomp_pressure) / 8192;
266 partial_data5 = (partial_data4 * uncomp_pressure) / 512;
267 partial_data6 = (int64_t)((uint64_t)uncomp_pressure * (uint64_t)uncomp_pressure);
268 partial_data2 = (bmp388_cal.P11 * partial_data6) / 65536;
269 partial_data3 = (partial_data2 * uncomp_pressure) / 128;
270 partial_data4 = (offset / 4) + partial_data1 + partial_data5 + partial_data3;
271 comp_press = (((uint64_t)partial_data4 * 25) / (uint64_t)1099511627776);
273 return comp_press;
276 STATIC_UNIT_TESTED bool bmp388Calculate(baroDev_t *baro, int32_t *pressure, int32_t *temperature)
278 UNUSED(baro);
280 // calculate
281 int64_t t;
282 int64_t p;
284 t = bmp388CompensateTemperature(bmp388_ut);
285 p = bmp388CompensatePressure(bmp388_up);
287 if (pressure)
288 *pressure = (int32_t)(p / 256);
289 if (temperature)
290 *temperature = t;
292 return true;
295 #define DETECTION_MAX_RETRY_COUNT 5
296 static bool deviceDetect(busDevice_t * busDev)
298 uint8_t chipId[2];
299 uint8_t nRead;
300 uint8_t * pId;
302 if (busDev->busType == BUSTYPE_SPI) {
303 // In SPI mode, first byte read is a dummy byte
304 nRead = 2;
305 pId = &chipId[1];
306 } else {
307 // In I2C mode, no dummy byte is read
308 nRead = 1;
309 pId = &chipId[0];
312 for (int retry = 0; retry < DETECTION_MAX_RETRY_COUNT; retry++) {
313 delay(100);
315 bool ack = busReadBuf(busDev, BMP388_CHIP_ID_REG, chipId, nRead);
317 if (ack && *pId == BMP388_DEFAULT_CHIP_ID) {
318 return true;
322 return false;
325 bool bmp388Detect(baroDev_t *baro)
327 baro->busDev = busDeviceInit(BUSTYPE_ANY, DEVHW_BMP388, 0, OWNER_BARO);
328 if (baro->busDev == NULL) {
329 return false;
332 busSetSpeed(baro->busDev, BUS_SPEED_STANDARD);
334 if (!deviceDetect(baro->busDev)) {
335 busDeviceDeInit(baro->busDev);
336 return false;
339 // read calibration
340 if (baro->busDev->busType == BUSTYPE_SPI) {
341 // In SPI mode, first byte read is a dummy byte
342 uint8_t calibration_buf[sizeof(bmp388_calib_param_t) + 1];
343 busReadBuf(baro->busDev, BMP388_TRIMMING_NVM_PAR_T1_LSB_REG, calibration_buf, sizeof(bmp388_calib_param_t) + 1);
344 memcpy(&bmp388_cal, calibration_buf + 1, sizeof(bmp388_calib_param_t));
345 } else {
346 // In I2C mode, no dummy byte is read
347 busReadBuf(baro->busDev, BMP388_TRIMMING_NVM_PAR_T1_LSB_REG, (uint8_t*)&bmp388_cal, sizeof(bmp388_calib_param_t));
350 // set oversampling + power mode (forced), and start sampling
351 busWrite(baro->busDev, BMP388_OSR_REG,
352 ((BMP388_PRESSURE_OSR << BMP388_OSR_P_BIT) & BMP388_OSR_P_MASK) |
353 ((BMP388_TEMPERATURE_OSR << BMP388_OSR4_T_BIT) & BMP388_OSR4_T_MASK)
356 bmp388BeginForcedMeasurement(baro->busDev);
358 baro->ut_delay = 0;
359 baro->get_ut = bmp388GetUT;
360 baro->start_ut = bmp388StartUT;
362 baro->up_delay = 234 + (392 + ((1 << (BMP388_PRESSURE_OSR + 1)) * 2000)) + (313 + ((1 << (BMP388_TEMPERATURE_OSR + 1)) * 2000));
363 baro->start_up = bmp388StartUP;
364 baro->get_up = bmp388GetUP;
366 baro->calculate = bmp388Calculate;
368 return true;
371 #endif