[4.4.2] Remove 15 m/s limit on estimated vario (#12788)
[betaflight.git] / src / main / drivers / barometer / barometer_bmp085.c
blob24c1fcc85b588026aa2c19986fda0085d50cd3bb
1 /*
2 * This file is part of Cleanflight and Betaflight.
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/>.
21 #include <stdbool.h>
22 #include <stdint.h>
24 #include "platform.h"
26 #include "build/build_config.h"
28 #include "barometer.h"
30 #include "drivers/bus.h"
31 #include "drivers/bus_i2c.h"
32 #include "drivers/bus_i2c_busdev.h"
33 #include "drivers/exti.h"
34 #include "drivers/io.h"
35 #include "drivers/nvic.h"
36 #include "drivers/time.h"
38 #include "barometer_bmp085.h"
40 #ifdef USE_BARO
42 static bool isConversionComplete = false;
43 static bool isEOCConnected = false;
44 #define BMP085_DATA_TEMP_SIZE 2
45 #define BMP085_DATA_PRES_SIZE 3
46 #define BMP085_DATA_FRAME_SIZE 3
47 static uint8_t sensor_data[BMP085_DATA_FRAME_SIZE];
49 static IO_t eocIO;
50 static extiCallbackRec_t exti;
52 static void bmp085ExtiHandler(extiCallbackRec_t* cb)
54 UNUSED(cb);
55 isConversionComplete = true;
58 typedef struct {
59 int16_t ac1;
60 int16_t ac2;
61 int16_t ac3;
62 uint16_t ac4;
63 uint16_t ac5;
64 uint16_t ac6;
65 int16_t b1;
66 int16_t b2;
67 int16_t mb;
68 int16_t mc;
69 int16_t md;
70 } bmp085_smd500_calibration_param_t;
72 typedef struct {
73 bmp085_smd500_calibration_param_t cal_param;
74 uint8_t mode;
75 uint8_t chip_id, ml_version, al_version;
76 uint8_t dev_addr;
77 int32_t param_b5;
78 int16_t oversampling_setting;
79 } bmp085_t;
81 #define BMP085_I2C_ADDR 0x77
82 #define BMP085_CHIP_ID 0x55
83 #define BOSCH_PRESSURE_BMP085 85
84 #define BMP085_CHIP_ID_REG 0xD0
85 #define BMP085_VERSION_REG 0xD1
86 #define E_SENSOR_NOT_DETECTED (char) 0
87 #define BMP085_PROM_START__ADDR 0xaa
88 #define BMP085_PROM_DATA__LEN 22
89 #define BMP085_T_MEASURE 0x2E // temperature measurement
90 #define BMP085_P_MEASURE 0x34 // pressure measurement
91 #define BMP085_CTRL_MEAS_REG 0xF4
92 #define BMP085_ADC_OUT_MSB_REG 0xF6
93 #define BMP085_ADC_OUT_LSB_REG 0xF7
94 #define BMP085_CHIP_ID__POS 0
95 #define BMP085_CHIP_ID__MSK 0xFF
96 #define BMP085_CHIP_ID__LEN 8
97 #define BMP085_CHIP_ID__REG BMP085_CHIP_ID_REG
99 #define BMP085_ML_VERSION__POS 0
100 #define BMP085_ML_VERSION__LEN 4
101 #define BMP085_ML_VERSION__MSK 0x0F
102 #define BMP085_ML_VERSION__REG BMP085_VERSION_REG
104 #define BMP085_AL_VERSION__POS 4
105 #define BMP085_AL_VERSION__LEN 4
106 #define BMP085_AL_VERSION__MSK 0xF0
107 #define BMP085_AL_VERSION__REG BMP085_VERSION_REG
109 #define BMP085_GET_BITSLICE(regvar, bitname) (regvar & bitname##__MSK) >> bitname##__POS
110 #define BMP085_SET_BITSLICE(regvar, bitname, val) (regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK)
112 #define SMD500_PARAM_MG 3038 //calibration parameter
113 #define SMD500_PARAM_MH -7357 //calibration parameter
114 #define SMD500_PARAM_MI 3791 //calibration parameter
116 STATIC_UNIT_TESTED bmp085_t bmp085;
118 #define UT_DELAY 6000 // 1.5ms margin according to the spec (4.5ms T conversion time)
119 #define UP_DELAY 27000 // 6000+21000=27000 1.5ms margin according to the spec (25.5ms P conversion time with OSS=3)
121 static bool bmp085InitDone = false;
122 STATIC_UNIT_TESTED uint16_t bmp085_ut; // static result of temperature measurement
123 STATIC_UNIT_TESTED uint32_t bmp085_up; // static result of pressure measurement
125 static void bmp085ReadCalibrarionParameters(const extDevice_t *dev);
126 static void bmp085StartUT(baroDev_t *baro);
127 static bool bmp085ReadUT(baroDev_t *baro);
128 static bool bmp085GetUT(baroDev_t *baro);
129 static void bmp085StartUP(baroDev_t *baro);
130 static bool bmp085ReadUP(baroDev_t *baro);
131 static bool bmp085GetUP(baroDev_t *baro);
132 static int32_t bmp085GetTemperature(uint32_t ut);
133 static int32_t bmp085GetPressure(uint32_t up);
134 STATIC_UNIT_TESTED void bmp085Calculate(int32_t *pressure, int32_t *temperature);
136 static bool bmp085TestEOCConnected(baroDev_t *baro, const bmp085Config_t *config);
138 static IO_t xclrIO = IO_NONE;
139 #define BMP085_OFF IOLo(xclrIO);
140 #define BMP085_ON IOHi(xclrIO);
142 static void bmp085InitXclrIO(const bmp085Config_t *config)
144 xclrIO = IOGetByTag(config->xclrTag);
145 IOInit(xclrIO, OWNER_BARO_XCLR, 0);
146 IOConfigGPIO(xclrIO, IOCFG_OUT_PP);
149 bool bmp085Detect(const bmp085Config_t *config, baroDev_t *baro)
151 uint8_t data;
152 bool ack;
153 bool defaultAddressApplied = false;
155 if (bmp085InitDone) {
156 return true;
159 bmp085InitXclrIO(config);
160 BMP085_ON; // enable baro
162 // EXTI interrupt for barometer EOC
164 eocIO = IOGetByTag(config->eocTag);
165 IOInit(eocIO, OWNER_BARO_EOC, 0);
166 EXTIHandlerInit(&exti, bmp085ExtiHandler);
167 EXTIConfig(eocIO, &exti, NVIC_PRIO_BARO_EXTI, IOCFG_IN_FLOATING, BETAFLIGHT_EXTI_TRIGGER_RISING);
168 EXTIEnable(eocIO);
170 delay(20); // datasheet says 10ms, we'll be careful and do 20.
172 extDevice_t *dev = &baro->dev;
174 if ((dev->bus->busType == BUS_TYPE_I2C) && (dev->busType_u.i2c.address == 0)) {
175 // Default address for BMP085
176 dev->busType_u.i2c.address = BMP085_I2C_ADDR;
177 defaultAddressApplied = true;
180 ack = busReadRegisterBuffer(dev, BMP085_CHIP_ID__REG, &data, 1); /* read Chip Id */
181 if (ack) {
182 bmp085.chip_id = BMP085_GET_BITSLICE(data, BMP085_CHIP_ID);
183 bmp085.oversampling_setting = 3;
185 if (bmp085.chip_id == BMP085_CHIP_ID) { /* get bitslice */
186 busDeviceRegister(dev);
188 busReadRegisterBuffer(dev, BMP085_VERSION_REG, &data, 1); /* read Version reg */
189 bmp085.ml_version = BMP085_GET_BITSLICE(data, BMP085_ML_VERSION); /* get ML Version */
190 bmp085.al_version = BMP085_GET_BITSLICE(data, BMP085_AL_VERSION); /* get AL Version */
191 bmp085ReadCalibrarionParameters(dev); /* readout bmp085 calibparam structure */
192 baro->ut_delay = UT_DELAY;
193 baro->up_delay = UP_DELAY;
194 baro->start_ut = bmp085StartUT;
195 baro->read_ut = bmp085ReadUT;
196 baro->get_ut = bmp085GetUT;
197 baro->start_up = bmp085StartUP;
198 baro->read_up = bmp085ReadUP;
199 baro->get_up = bmp085GetUP;
200 baro->calculate = bmp085Calculate;
202 isEOCConnected = bmp085TestEOCConnected(baro, config);
204 bmp085InitDone = true;
205 return true;
209 if (eocIO) {
210 IORelease(eocIO);
211 EXTIRelease(eocIO);
214 BMP085_OFF;
216 if (defaultAddressApplied) {
217 dev->busType_u.i2c.address = 0;
220 return false;
223 static int32_t bmp085GetTemperature(uint32_t ut)
225 int32_t temperature;
226 int32_t x1, x2;
228 x1 = (((int32_t) ut - (int32_t) bmp085.cal_param.ac6) * (int32_t) bmp085.cal_param.ac5) >> 15;
229 x2 = ((int32_t) bmp085.cal_param.mc << 11) / (x1 + bmp085.cal_param.md);
230 bmp085.param_b5 = x1 + x2;
231 temperature = ((bmp085.param_b5 * 10 + 8) >> 4); // temperature in 0.01 C (make same as MS5611)
233 return temperature;
236 static int32_t bmp085GetPressure(uint32_t up)
238 int32_t pressure, x1, x2, x3, b3, b6;
239 uint32_t b4, b7;
241 b6 = bmp085.param_b5 - 4000;
242 // *****calculate B3************
243 x1 = (b6 * b6) >> 12;
244 x1 *= bmp085.cal_param.b2;
245 x1 >>= 11;
247 x2 = (bmp085.cal_param.ac2 * b6);
248 x2 >>= 11;
250 x3 = x1 + x2;
252 b3 = (((((int32_t) bmp085.cal_param.ac1) * 4 + x3) << bmp085.oversampling_setting) + 2) >> 2;
254 // *****calculate B4************
255 x1 = (bmp085.cal_param.ac3 * b6) >> 13;
256 x2 = (bmp085.cal_param.b1 * ((b6 * b6) >> 12)) >> 16;
257 x3 = ((x1 + x2) + 2) >> 2;
258 b4 = (bmp085.cal_param.ac4 * (uint32_t)(x3 + 32768)) >> 15;
260 b7 = ((uint32_t)(up - b3) * (50000 >> bmp085.oversampling_setting));
261 if (b7 < 0x80000000) {
262 pressure = (b7 << 1) / b4;
263 } else {
264 pressure = (b7 / b4) << 1;
267 x1 = pressure >> 8;
268 x1 *= x1;
269 x1 = (x1 * SMD500_PARAM_MG) >> 16;
270 x2 = (pressure * SMD500_PARAM_MH) >> 16;
271 pressure += (x1 + x2 + SMD500_PARAM_MI) >> 4; // pressure in Pa
273 return pressure;
276 static void bmp085StartUT(baroDev_t *baro)
278 isConversionComplete = false;
280 busWriteRegisterStart(&baro->dev, BMP085_CTRL_MEAS_REG, BMP085_T_MEASURE);
283 static bool bmp085ReadUT(baroDev_t *baro)
285 if (busBusy(&baro->dev, NULL)) {
286 return false;
289 // return old baro value if conversion time exceeds datasheet max when EOC is connected
290 if (isEOCConnected && !isConversionComplete) {
291 return false;
294 busReadRegisterBufferStart(&baro->dev, BMP085_ADC_OUT_MSB_REG, sensor_data, BMP085_DATA_TEMP_SIZE);
296 return true;
299 static bool bmp085GetUT(baroDev_t *baro)
301 if (busBusy(&baro->dev, NULL)) {
302 return false;
305 bmp085_ut = sensor_data[0] << 8 | sensor_data[1];
307 return true;
310 static void bmp085StartUP(baroDev_t *baro)
312 uint8_t ctrl_reg_data;
314 ctrl_reg_data = BMP085_P_MEASURE + (bmp085.oversampling_setting << 6);
316 isConversionComplete = false;
318 busWriteRegisterStart(&baro->dev, BMP085_CTRL_MEAS_REG, ctrl_reg_data);
321 static bool bmp085ReadUP(baroDev_t *baro)
323 if (busBusy(&baro->dev, NULL)) {
324 return false;
327 // return old baro value if conversion time exceeds datasheet max when EOC is connected
328 if (isEOCConnected && !isConversionComplete) {
329 return false;
332 busReadRegisterBufferStart(&baro->dev, BMP085_ADC_OUT_MSB_REG, sensor_data, BMP085_DATA_PRES_SIZE);
334 return true;
337 /** read out up for pressure conversion
338 depending on the oversampling ratio setting up can be 16 to 19 bit
339 \return up parameter that represents the uncompensated pressure value
341 static bool bmp085GetUP(baroDev_t *baro)
343 if (busBusy(&baro->dev, NULL)) {
344 return false;
347 bmp085_up = (uint32_t)(sensor_data[0] << 16 | sensor_data[1] << 8 | sensor_data[2])
348 >> (8 - bmp085.oversampling_setting);
350 return true;
353 STATIC_UNIT_TESTED void bmp085Calculate(int32_t *pressure, int32_t *temperature)
355 int32_t temp, press;
357 temp = bmp085GetTemperature(bmp085_ut);
358 press = bmp085GetPressure(bmp085_up);
359 if (pressure)
360 *pressure = press;
361 if (temperature)
362 *temperature = temp;
365 static void bmp085ReadCalibrarionParameters(const extDevice_t *dev)
367 uint8_t data[22];
368 busReadRegisterBuffer(dev, BMP085_PROM_START__ADDR, data, BMP085_PROM_DATA__LEN);
370 /*parameters AC1-AC6*/
371 bmp085.cal_param.ac1 = data[0] << 8 | data[1];
372 bmp085.cal_param.ac2 = data[2] << 8 | data[3];
373 bmp085.cal_param.ac3 = data[4] << 8 | data[5];
374 bmp085.cal_param.ac4 = data[6] << 8 | data[7];
375 bmp085.cal_param.ac5 = data[8] << 8 | data[9];
376 bmp085.cal_param.ac6 = data[10] << 8 | data[11];
378 /*parameters B1,B2*/
379 bmp085.cal_param.b1 = data[12] << 8 | data[13];
380 bmp085.cal_param.b2 = data[14] << 8 | data[15];
382 /*parameters MB,MC,MD*/
383 bmp085.cal_param.mb = data[16] << 8 | data[17];
384 bmp085.cal_param.mc = data[18] << 8 | data[19];
385 bmp085.cal_param.md = data[20] << 8 | data[21];
388 static bool bmp085TestEOCConnected(baroDev_t *baro, const bmp085Config_t *config)
390 UNUSED(config);
392 if (!bmp085InitDone && eocIO) {
393 // EOC should be low at this point. If not, assume EOC is not working
394 if (IORead(eocIO)) {
395 return false;
398 bmp085StartUT(baro);
399 delayMicroseconds(UT_DELAY * 2); // wait twice as long as normal, just to be sure
401 // conversion should have finished now so check if EOC is high
402 uint8_t status = IORead(eocIO);
403 if (status) {
404 return true;
408 return false; // assume EOC is not connected
411 #endif /* BARO */