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)
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/>.
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"
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
];
51 static extiCallbackRec_t exti
;
53 static void bmp085ExtiHandler(extiCallbackRec_t
* cb
)
56 isConversionComplete
= true;
72 } bmp085_smd500_calibration_param_t
;
75 bmp085_smd500_calibration_param_t cal_param
;
77 uint8_t chip_id
, ml_version
, al_version
;
80 int16_t oversampling_setting
;
83 #define BMP085_I2C_ADDR 0x77
84 #define BMP085_CHIP_ID 0x55
85 #define BOSCH_PRESSURE_BMP085 85
86 #define BMP085_CHIP_ID_REG 0xD0
87 #define BMP085_VERSION_REG 0xD1
88 #define E_SENSOR_NOT_DETECTED (char) 0
89 #define BMP085_PROM_START__ADDR 0xaa
90 #define BMP085_PROM_DATA__LEN 22
91 #define BMP085_T_MEASURE 0x2E // temperature measurent
92 #define BMP085_P_MEASURE 0x34 // pressure measurement
93 #define BMP085_CTRL_MEAS_REG 0xF4
94 #define BMP085_ADC_OUT_MSB_REG 0xF6
95 #define BMP085_ADC_OUT_LSB_REG 0xF7
96 #define BMP085_CHIP_ID__POS 0
97 #define BMP085_CHIP_ID__MSK 0xFF
98 #define BMP085_CHIP_ID__LEN 8
99 #define BMP085_CHIP_ID__REG BMP085_CHIP_ID_REG
101 #define BMP085_ML_VERSION__POS 0
102 #define BMP085_ML_VERSION__LEN 4
103 #define BMP085_ML_VERSION__MSK 0x0F
104 #define BMP085_ML_VERSION__REG BMP085_VERSION_REG
106 #define BMP085_AL_VERSION__POS 4
107 #define BMP085_AL_VERSION__LEN 4
108 #define BMP085_AL_VERSION__MSK 0xF0
109 #define BMP085_AL_VERSION__REG BMP085_VERSION_REG
111 #define BMP085_GET_BITSLICE(regvar, bitname) (regvar & bitname##__MSK) >> bitname##__POS
112 #define BMP085_SET_BITSLICE(regvar, bitname, val) (regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK)
114 #define SMD500_PARAM_MG 3038 //calibration parameter
115 #define SMD500_PARAM_MH -7357 //calibration parameter
116 #define SMD500_PARAM_MI 3791 //calibration parameter
118 STATIC_UNIT_TESTED bmp085_t bmp085
;
120 #define UT_DELAY 6000 // 1.5ms margin according to the spec (4.5ms T conversion time)
121 #define UP_DELAY 27000 // 6000+21000=27000 1.5ms margin according to the spec (25.5ms P conversion time with OSS=3)
123 static bool bmp085InitDone
= false;
124 STATIC_UNIT_TESTED
uint16_t bmp085_ut
; // static result of temperature measurement
125 STATIC_UNIT_TESTED
uint32_t bmp085_up
; // static result of pressure measurement
127 static void bmp085ReadCalibrarionParameters(const extDevice_t
*dev
);
128 static void bmp085StartUT(baroDev_t
*baro
);
129 static bool bmp085ReadUT(baroDev_t
*baro
);
130 static bool bmp085GetUT(baroDev_t
*baro
);
131 static void bmp085StartUP(baroDev_t
*baro
);
132 static bool bmp085ReadUP(baroDev_t
*baro
);
133 static bool bmp085GetUP(baroDev_t
*baro
);
134 static int32_t bmp085GetTemperature(uint32_t ut
);
135 static int32_t bmp085GetPressure(uint32_t up
);
136 STATIC_UNIT_TESTED
void bmp085Calculate(int32_t *pressure
, int32_t *temperature
);
138 static bool bmp085TestEOCConnected(baroDev_t
*baro
, const bmp085Config_t
*config
);
140 static IO_t xclrIO
= IO_NONE
;
141 #define BMP085_OFF IOLo(xclrIO);
142 #define BMP085_ON IOHi(xclrIO);
144 static void bmp085InitXclrIO(const bmp085Config_t
*config
)
146 xclrIO
= IOGetByTag(config
->xclrTag
);
147 IOInit(xclrIO
, OWNER_BARO_XCLR
, 0);
148 IOConfigGPIO(xclrIO
, IOCFG_OUT_PP
);
151 bool bmp085Detect(const bmp085Config_t
*config
, baroDev_t
*baro
)
155 bool defaultAddressApplied
= false;
157 if (bmp085InitDone
) {
161 bmp085InitXclrIO(config
);
162 BMP085_ON
; // enable baro
165 // EXTI interrupt for barometer EOC
167 eocIO
= IOGetByTag(config
->eocTag
);
168 IOInit(eocIO
, OWNER_BARO_EOC
, 0);
169 EXTIHandlerInit(&exti
, bmp085ExtiHandler
);
170 EXTIConfig(eocIO
, &exti
, NVIC_PRIO_BARO_EXTI
, IOCFG_IN_FLOATING
, BETAFLIGHT_EXTI_TRIGGER_RISING
);
171 EXTIEnable(eocIO
, true);
176 delay(20); // datasheet says 10ms, we'll be careful and do 20.
178 extDevice_t
*dev
= &baro
->dev
;
180 if ((dev
->bus
->busType
== BUS_TYPE_I2C
) && (dev
->busType_u
.i2c
.address
== 0)) {
181 // Default address for BMP085
182 dev
->busType_u
.i2c
.address
= BMP085_I2C_ADDR
;
183 defaultAddressApplied
= true;
186 ack
= busReadRegisterBuffer(dev
, BMP085_CHIP_ID__REG
, &data
, 1); /* read Chip Id */
188 bmp085
.chip_id
= BMP085_GET_BITSLICE(data
, BMP085_CHIP_ID
);
189 bmp085
.oversampling_setting
= 3;
191 if (bmp085
.chip_id
== BMP085_CHIP_ID
) { /* get bitslice */
192 busDeviceRegister(dev
);
194 busReadRegisterBuffer(dev
, BMP085_VERSION_REG
, &data
, 1); /* read Version reg */
195 bmp085
.ml_version
= BMP085_GET_BITSLICE(data
, BMP085_ML_VERSION
); /* get ML Version */
196 bmp085
.al_version
= BMP085_GET_BITSLICE(data
, BMP085_AL_VERSION
); /* get AL Version */
197 bmp085ReadCalibrarionParameters(dev
); /* readout bmp085 calibparam structure */
198 baro
->ut_delay
= UT_DELAY
;
199 baro
->up_delay
= UP_DELAY
;
200 baro
->start_ut
= bmp085StartUT
;
201 baro
->read_ut
= bmp085ReadUT
;
202 baro
->get_ut
= bmp085GetUT
;
203 baro
->start_up
= bmp085StartUP
;
204 baro
->read_up
= bmp085ReadUP
;
205 baro
->get_up
= bmp085GetUP
;
206 baro
->calculate
= bmp085Calculate
;
208 isEOCConnected
= bmp085TestEOCConnected(baro
, config
);
210 bmp085InitDone
= true;
224 if (defaultAddressApplied
) {
225 dev
->busType_u
.i2c
.address
= 0;
231 static int32_t bmp085GetTemperature(uint32_t ut
)
236 x1
= (((int32_t) ut
- (int32_t) bmp085
.cal_param
.ac6
) * (int32_t) bmp085
.cal_param
.ac5
) >> 15;
237 x2
= ((int32_t) bmp085
.cal_param
.mc
<< 11) / (x1
+ bmp085
.cal_param
.md
);
238 bmp085
.param_b5
= x1
+ x2
;
239 temperature
= ((bmp085
.param_b5
* 10 + 8) >> 4); // temperature in 0.01 C (make same as MS5611)
244 static int32_t bmp085GetPressure(uint32_t up
)
246 int32_t pressure
, x1
, x2
, x3
, b3
, b6
;
249 b6
= bmp085
.param_b5
- 4000;
250 // *****calculate B3************
251 x1
= (b6
* b6
) >> 12;
252 x1
*= bmp085
.cal_param
.b2
;
255 x2
= (bmp085
.cal_param
.ac2
* b6
);
260 b3
= (((((int32_t) bmp085
.cal_param
.ac1
) * 4 + x3
) << bmp085
.oversampling_setting
) + 2) >> 2;
262 // *****calculate B4************
263 x1
= (bmp085
.cal_param
.ac3
* b6
) >> 13;
264 x2
= (bmp085
.cal_param
.b1
* ((b6
* b6
) >> 12)) >> 16;
265 x3
= ((x1
+ x2
) + 2) >> 2;
266 b4
= (bmp085
.cal_param
.ac4
* (uint32_t)(x3
+ 32768)) >> 15;
268 b7
= ((uint32_t)(up
- b3
) * (50000 >> bmp085
.oversampling_setting
));
269 if (b7
< 0x80000000) {
270 pressure
= (b7
<< 1) / b4
;
272 pressure
= (b7
/ b4
) << 1;
277 x1
= (x1
* SMD500_PARAM_MG
) >> 16;
278 x2
= (pressure
* SMD500_PARAM_MH
) >> 16;
279 pressure
+= (x1
+ x2
+ SMD500_PARAM_MI
) >> 4; // pressure in Pa
284 static void bmp085StartUT(baroDev_t
*baro
)
286 isConversionComplete
= false;
288 busWriteRegisterStart(&baro
->dev
, BMP085_CTRL_MEAS_REG
, BMP085_T_MEASURE
);
291 static bool bmp085ReadUT(baroDev_t
*baro
)
293 if (busBusy(&baro
->dev
, NULL
)) {
297 // return old baro value if conversion time exceeds datasheet max when EOC is connected
298 if (isEOCConnected
&& !isConversionComplete
) {
302 busReadRegisterBufferStart(&baro
->dev
, BMP085_ADC_OUT_MSB_REG
, sensor_data
, BMP085_DATA_TEMP_SIZE
);
307 static bool bmp085GetUT(baroDev_t
*baro
)
309 if (busBusy(&baro
->dev
, NULL
)) {
313 bmp085_ut
= sensor_data
[0] << 8 | sensor_data
[1];
318 static void bmp085StartUP(baroDev_t
*baro
)
320 uint8_t ctrl_reg_data
;
322 ctrl_reg_data
= BMP085_P_MEASURE
+ (bmp085
.oversampling_setting
<< 6);
324 isConversionComplete
= false;
326 busWriteRegisterStart(&baro
->dev
, BMP085_CTRL_MEAS_REG
, ctrl_reg_data
);
329 static bool bmp085ReadUP(baroDev_t
*baro
)
331 if (busBusy(&baro
->dev
, NULL
)) {
335 // return old baro value if conversion time exceeds datasheet max when EOC is connected
336 if (isEOCConnected
&& !isConversionComplete
) {
340 busReadRegisterBufferStart(&baro
->dev
, BMP085_ADC_OUT_MSB_REG
, sensor_data
, BMP085_DATA_PRES_SIZE
);
345 /** read out up for pressure conversion
346 depending on the oversampling ratio setting up can be 16 to 19 bit
347 \return up parameter that represents the uncompensated pressure value
349 static bool bmp085GetUP(baroDev_t
*baro
)
351 if (busBusy(&baro
->dev
, NULL
)) {
355 bmp085_up
= (uint32_t)(sensor_data
[0] << 16 | sensor_data
[1] << 8 | sensor_data
[2])
356 >> (8 - bmp085
.oversampling_setting
);
361 STATIC_UNIT_TESTED
void bmp085Calculate(int32_t *pressure
, int32_t *temperature
)
365 temp
= bmp085GetTemperature(bmp085_ut
);
366 press
= bmp085GetPressure(bmp085_up
);
373 static void bmp085ReadCalibrarionParameters(const extDevice_t
*dev
)
376 busReadRegisterBuffer(dev
, BMP085_PROM_START__ADDR
, data
, BMP085_PROM_DATA__LEN
);
378 /*parameters AC1-AC6*/
379 bmp085
.cal_param
.ac1
= data
[0] << 8 | data
[1];
380 bmp085
.cal_param
.ac2
= data
[2] << 8 | data
[3];
381 bmp085
.cal_param
.ac3
= data
[4] << 8 | data
[5];
382 bmp085
.cal_param
.ac4
= data
[6] << 8 | data
[7];
383 bmp085
.cal_param
.ac5
= data
[8] << 8 | data
[9];
384 bmp085
.cal_param
.ac6
= data
[10] << 8 | data
[11];
387 bmp085
.cal_param
.b1
= data
[12] << 8 | data
[13];
388 bmp085
.cal_param
.b2
= data
[14] << 8 | data
[15];
390 /*parameters MB,MC,MD*/
391 bmp085
.cal_param
.mb
= data
[16] << 8 | data
[17];
392 bmp085
.cal_param
.mc
= data
[18] << 8 | data
[19];
393 bmp085
.cal_param
.md
= data
[20] << 8 | data
[21];
396 static bool bmp085TestEOCConnected(baroDev_t
*baro
, const bmp085Config_t
*config
)
401 if (!bmp085InitDone
&& eocIO
) {
402 // EOC should be low at this point. If not, assume EOC is not working
408 delayMicroseconds(UT_DELAY
* 2); // wait twice as long as normal, just to be sure
410 // conversion should have finished now so check if EOC is high
411 uint8_t status
= IORead(eocIO
);
420 return false; // assume EOC is not connected