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
];
50 static extiCallbackRec_t exti
;
52 static void bmp085ExtiHandler(extiCallbackRec_t
* cb
)
55 isConversionComplete
= true;
70 } bmp085_smd500_calibration_param_t
;
73 bmp085_smd500_calibration_param_t cal_param
;
75 uint8_t chip_id
, ml_version
, al_version
;
78 int16_t oversampling_setting
;
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
)
153 bool defaultAddressApplied
= false;
155 if (bmp085InitDone
) {
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
);
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 */
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;
216 if (defaultAddressApplied
) {
217 dev
->busType_u
.i2c
.address
= 0;
223 static int32_t bmp085GetTemperature(uint32_t ut
)
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)
236 static int32_t bmp085GetPressure(uint32_t up
)
238 int32_t pressure
, x1
, x2
, x3
, b3
, b6
;
241 b6
= bmp085
.param_b5
- 4000;
242 // *****calculate B3************
243 x1
= (b6
* b6
) >> 12;
244 x1
*= bmp085
.cal_param
.b2
;
247 x2
= (bmp085
.cal_param
.ac2
* b6
);
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
;
264 pressure
= (b7
/ b4
) << 1;
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
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
)) {
289 // return old baro value if conversion time exceeds datasheet max when EOC is connected
290 if (isEOCConnected
&& !isConversionComplete
) {
294 busReadRegisterBufferStart(&baro
->dev
, BMP085_ADC_OUT_MSB_REG
, sensor_data
, BMP085_DATA_TEMP_SIZE
);
299 static bool bmp085GetUT(baroDev_t
*baro
)
301 if (busBusy(&baro
->dev
, NULL
)) {
305 bmp085_ut
= sensor_data
[0] << 8 | sensor_data
[1];
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
)) {
327 // return old baro value if conversion time exceeds datasheet max when EOC is connected
328 if (isEOCConnected
&& !isConversionComplete
) {
332 busReadRegisterBufferStart(&baro
->dev
, BMP085_ADC_OUT_MSB_REG
, sensor_data
, BMP085_DATA_PRES_SIZE
);
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
)) {
347 bmp085_up
= (uint32_t)(sensor_data
[0] << 16 | sensor_data
[1] << 8 | sensor_data
[2])
348 >> (8 - bmp085
.oversampling_setting
);
353 STATIC_UNIT_TESTED
void bmp085Calculate(int32_t *pressure
, int32_t *temperature
)
357 temp
= bmp085GetTemperature(bmp085_ut
);
358 press
= bmp085GetPressure(bmp085_up
);
365 static void bmp085ReadCalibrarionParameters(const extDevice_t
*dev
)
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];
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
)
392 if (!bmp085InitDone
&& eocIO
) {
393 // EOC should be low at this point. If not, assume EOC is not working
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
);
408 return false; // assume EOC is not connected