2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_BMP085 BMP085 Functions
6 * @brief Hardware functions to deal with the altitude pressure sensor
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
11 * @brief BMP085 Pressure Sensor Routines
12 * @see The GNU Public License (GPL) Version 3
14 ******************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include <pios_bmp085.h>
33 #ifdef PIOS_INCLUDE_BMP085
35 #ifndef PIOS_INCLUDE_EXTI
36 #error PIOS_EXTI must be included in the project
37 #endif /* PIOS_INCLUDE_EXTI */
39 /* Glocal Variables */
40 ConversionTypeTypeDef CurrentRead
;
43 static BMP085CalibDataTypeDef CalibData
;
45 /* Straight from the datasheet */
46 static int32_t X1
, X2
, X3
, B3
, B5
, B6
, P
;
47 static uint32_t B4
, B7
;
48 static volatile uint16_t RawTemperature
;
49 static volatile uint32_t RawPressure
;
50 static volatile uint32_t Pressure
;
51 static volatile uint16_t Temperature
;
53 #ifdef PIOS_BMP085_HAS_GPIOS
55 #if defined(PIOS_INCLUDE_FREERTOS)
56 xSemaphoreHandle PIOS_BMP085_EOC
;
58 int32_t PIOS_BMP085_EOC
;
61 void PIOS_BMP085_EndOfConversion(void)
63 #if defined(PIOS_INCLUDE_FREERTOS)
64 portBASE_TYPE xHigherPriorityTaskWoken
= pdFALSE
;
67 /* Read the ADC Value */
68 #if defined(PIOS_INCLUDE_FREERTOS)
69 xSemaphoreGiveFromISR(PIOS_BMP085_EOC
, &xHigherPriorityTaskWoken
);
74 #if defined(PIOS_INCLUDE_FREERTOS)
75 /* Yield From ISR if needed */
76 portEND_SWITCHING_ISR(xHigherPriorityTaskWoken
);
80 static const struct pios_exti_cfg pios_exti_bmp085_cfg __exti_config
= {
81 .vector
= PIOS_BMP085_EndOfConversion
,
82 .line
= PIOS_BMP085_EOC_EXTI_LINE
,
84 .gpio
= PIOS_BMP085_EOC_GPIO_PORT
,
86 .GPIO_Pin
= PIOS_BMP085_EOC_GPIO_PIN
,
87 .GPIO_Mode
= GPIO_Mode_IN_FLOATING
,
92 .NVIC_IRQChannel
= PIOS_BMP085_EOC_IRQn
,
93 .NVIC_IRQChannelPreemptionPriority
= PIOS_BMP085_EOC_PRIO
,
94 .NVIC_IRQChannelSubPriority
= 0,
95 .NVIC_IRQChannelCmd
= ENABLE
,
100 .EXTI_Line
= PIOS_BMP085_EOC_EXTI_LINE
,
101 .EXTI_Mode
= EXTI_Mode_Interrupt
,
102 .EXTI_Trigger
= EXTI_Trigger_Rising
,
103 .EXTI_LineCmd
= ENABLE
,
108 #endif /* PIOS_BMP085_HAS_GPIOS */
110 * Initialise the BMP085 sensor
112 void PIOS_BMP085_Init(void)
114 #ifdef PIOS_BMP085_HAS_GPIOS
116 #if defined(PIOS_INCLUDE_FREERTOS)
117 /* Semaphore used by ISR to signal End-Of-Conversion */
118 vSemaphoreCreateBinary(PIOS_BMP085_EOC
);
119 /* Must start off empty so that first transfer waits for EOC */
120 xSemaphoreTake(PIOS_BMP085_EOC
, portMAX_DELAY
);
125 /* Enable EOC GPIO clock */
126 RCC_APB2PeriphClockCmd(PIOS_BMP085_EOC_CLK
| RCC_APB2Periph_AFIO
, ENABLE
);
128 if (PIOS_EXTI_Init(&pios_exti_bmp085_cfg
)) {
132 /* Configure XCLR pin as push/pull alternate funtion output */
133 GPIO_InitTypeDef GPIO_InitStructure
;
134 GPIO_InitStructure
.GPIO_Pin
= PIOS_BMP085_XCLR_GPIO_PIN
;
135 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_AF_PP
;
136 GPIO_Init(PIOS_BMP085_XCLR_GPIO_PORT
, &GPIO_InitStructure
);
138 #endif /* PIOS_BMP085_HAS_GPIOS */
140 /* Read all 22 bytes of calibration data in one transfer, this is a very optimized way of doing things */
141 uint8_t Data
[BMP085_CALIB_LEN
];
142 while (PIOS_BMP085_Read(BMP085_CALIB_ADDR
, Data
, BMP085_CALIB_LEN
) != 0) {
146 /* Parameters AC1-AC6 */
147 CalibData
.AC1
= (Data
[0] << 8) | Data
[1];
148 CalibData
.AC2
= (Data
[2] << 8) | Data
[3];
149 CalibData
.AC3
= (Data
[4] << 8) | Data
[5];
150 CalibData
.AC4
= (Data
[6] << 8) | Data
[7];
151 CalibData
.AC5
= (Data
[8] << 8) | Data
[9];
152 CalibData
.AC6
= (Data
[10] << 8) | Data
[11];
154 /* Parameters B1, B2 */
155 CalibData
.B1
= (Data
[12] << 8) | Data
[13];
156 CalibData
.B2
= (Data
[14] << 8) | Data
[15];
158 /* Parameters MB, MC, MD */
159 CalibData
.MB
= (Data
[16] << 8) | Data
[17];
160 CalibData
.MC
= (Data
[18] << 8) | Data
[19];
161 CalibData
.MD
= (Data
[20] << 8) | Data
[21];
165 * Start the ADC conversion
166 * \param[in] PresOrTemp BMP085_PRES_ADDR or BMP085_TEMP_ADDR
167 * \return Raw ADC value
169 void PIOS_BMP085_StartADC(ConversionTypeTypeDef Type
)
171 /* Start the conversion */
172 if (Type
== TemperatureConv
) {
173 while (PIOS_BMP085_Write(BMP085_CTRL_ADDR
, BMP085_TEMP_ADDR
) != 0) {
176 } else if (Type
== PressureConv
) {
177 while (PIOS_BMP085_Write(BMP085_CTRL_ADDR
, BMP085_PRES_ADDR
) != 0) {
186 * Read the ADC conversion value (once ADC conversion has completed)
187 * \param[in] PresOrTemp BMP085_PRES_ADDR or BMP085_TEMP_ADDR
188 * \return Raw ADC value
190 void PIOS_BMP085_ReadADC(void)
198 /* Read and store the 16bit result */
199 if (CurrentRead
== TemperatureConv
) {
200 /* Read the temperature conversion */
201 while (PIOS_BMP085_Read(BMP085_ADC_MSB
, Data
, 2) != 0) {
204 RawTemperature
= ((Data
[0] << 8) | Data
[1]);
206 X1
= (RawTemperature
- CalibData
.AC6
) * CalibData
.AC5
>> 15;
207 X2
= ((int32_t)CalibData
.MC
<< 11) / (X1
+ CalibData
.MD
);
209 Temperature
= (B5
+ 8) >> 4;
211 /* Read the pressure conversion */
212 while (PIOS_BMP085_Read(BMP085_ADC_MSB
, Data
, 3) != 0) {
215 RawPressure
= ((Data
[0] << 16) | (Data
[1] << 8) | Data
[2]) >> (8 - BMP085_OVERSAMPLING
);
218 X1
= (CalibData
.B2
* (B6
* B6
>> 12)) >> 11;
219 X2
= CalibData
.AC2
* B6
>> 11;
221 B3
= ((((int32_t)CalibData
.AC1
* 4 + X3
) << BMP085_OVERSAMPLING
) + 2) >> 2;
222 X1
= CalibData
.AC3
* B6
>> 13;
223 X2
= (CalibData
.B1
* (B6
* B6
>> 12)) >> 16;
224 X3
= ((X1
+ X2
) + 2) >> 2;
225 B4
= (CalibData
.AC4
* (uint32_t)(X3
+ 32768)) >> 15;
226 B7
= ((uint32_t)RawPressure
- B3
) * (50000 >> BMP085_OVERSAMPLING
);
227 P
= B7
< 0x80000000 ? (B7
* 2) / B4
: (B7
/ B4
) * 2;
229 X1
= (P
>> 8) * (P
>> 8);
230 X1
= (X1
* 3038) >> 16;
231 X2
= (-7357 * P
) >> 16;
232 Pressure
= P
+ ((X1
+ X2
+ 3791) >> 4);
236 int16_t PIOS_BMP085_GetTemperature(void)
241 int32_t PIOS_BMP085_GetPressure(void)
247 * Reads one or more bytes into a buffer
248 * \param[in] address BMP085 register address (depends on size)
249 * \param[out] buffer destination buffer
250 * \param[in] len number of bytes which should be read
251 * \return 0 if operation was successful
252 * \return -1 if error during I2C transfer
253 * \return -2 if BMP085 blocked by another task (retry it!)
254 * \return -4 if invalid length
256 bool PIOS_BMP085_Read(uint8_t address
, uint8_t *buffer
, uint8_t len
)
258 uint8_t addr_buffer
[] = {
262 const struct pios_i2c_txn txn_list
[] = {
265 .addr
= BMP085_I2C_ADDR
,
266 .rw
= PIOS_I2C_TXN_WRITE
,
267 .len
= sizeof(addr_buffer
),
273 .addr
= BMP085_I2C_ADDR
,
274 .rw
= PIOS_I2C_TXN_READ
,
280 return PIOS_I2C_Transfer(PIOS_I2C_BMP085_ADAPTER
, txn_list
, NELEMENTS(txn_list
));
284 * Writes one or more bytes to the BMP085
285 * \param[in] address Register address
286 * \param[in] buffer source buffer
287 * \return 0 if operation was successful
288 * \return -1 if error during I2C transfer
289 * \return -2 if BMP085 blocked by another task (retry it!)
291 bool PIOS_BMP085_Write(uint8_t address
, uint8_t buffer
)
298 const struct pios_i2c_txn txn_list
[] = {
301 .addr
= BMP085_I2C_ADDR
,
302 .rw
= PIOS_I2C_TXN_WRITE
,
309 return PIOS_I2C_Transfer(PIOS_I2C_BMP085_ADAPTER
, txn_list
, NELEMENTS(txn_list
));
313 * @brief Run self-test operation.
314 * \return 0 if self-test failed
315 * \return any non-0 number if test passed
317 int32_t PIOS_BMP085_Test()
319 // TODO: Is there a better way to test this than just checking that pressure/temperature has changed?
321 uint32_t cur_value
= 0;
323 cur_value
= Temperature
;
324 PIOS_BMP085_StartADC(TemperatureConv
);
325 PIOS_DELAY_WaitmS(5);
326 PIOS_BMP085_ReadADC();
327 if (cur_value
== Temperature
) {
331 cur_value
= Pressure
;
332 PIOS_BMP085_StartADC(PressureConv
);
333 PIOS_DELAY_WaitmS(26);
334 PIOS_BMP085_ReadADC();
335 if (cur_value
== Pressure
) {
342 #endif /* PIOS_INCLUDE_BMP085 */