1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-30 08:24:11 +01:00
LibrePilot/flight/pios/common/pios_bmp085.c
Richard Flay (Hyper) a2d8544931 OP-931: adds -Wextra compiler option for the flight code, and makes the bazillion code changes required
to make the flight code compile again. Needs careful review, particularly all the fixes for the
signed vs unsigned comparisons.

+review OPReview-459
2013-05-05 16:32:24 +09:30

335 lines
8.8 KiB
C

/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_BMP085 BMP085 Functions
* @brief Hardware functions to deal with the altitude pressure sensor
* @{
*
* @file pios_bmp085.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief BMP085 Pressure Sensor Routines
* @see The GNU Public License (GPL) Version 3
*
******************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_BMP085
#ifndef PIOS_INCLUDE_EXTI
#error PIOS_EXTI must be included in the project
#endif /* PIOS_INCLUDE_EXTI */
/* Glocal Variables */
ConversionTypeTypeDef CurrentRead;
/* Local Variables */
static BMP085CalibDataTypeDef CalibData;
/* Straight from the datasheet */
static int32_t X1, X2, X3, B3, B5, B6, P;
static uint32_t B4, B7;
static volatile uint16_t RawTemperature;
static volatile uint32_t RawPressure;
static volatile uint32_t Pressure;
static volatile uint16_t Temperature;
#ifdef PIOS_BMP085_HAS_GPIOS
#if defined(PIOS_INCLUDE_FREERTOS)
xSemaphoreHandle PIOS_BMP085_EOC;
#else
int32_t PIOS_BMP085_EOC;
#endif
void PIOS_BMP085_EndOfConversion (void)
{
#if defined(PIOS_INCLUDE_FREERTOS)
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
#endif
/* Read the ADC Value */
#if defined(PIOS_INCLUDE_FREERTOS)
xSemaphoreGiveFromISR(PIOS_BMP085_EOC, &xHigherPriorityTaskWoken);
#else
PIOS_BMP085_EOC=1;
#endif
#if defined(PIOS_INCLUDE_FREERTOS)
/* Yield From ISR if needed */
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
#endif
}
static const struct pios_exti_cfg pios_exti_bmp085_cfg __exti_config = {
.vector = PIOS_BMP085_EndOfConversion,
.line = PIOS_BMP085_EOC_EXTI_LINE,
.pin = {
.gpio = PIOS_BMP085_EOC_GPIO_PORT,
.init = {
.GPIO_Pin = PIOS_BMP085_EOC_GPIO_PIN,
.GPIO_Mode = GPIO_Mode_IN_FLOATING,
},
},
.irq = {
.init = {
.NVIC_IRQChannel = PIOS_BMP085_EOC_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_BMP085_EOC_PRIO,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.exti = {
.init = {
.EXTI_Line = PIOS_BMP085_EOC_EXTI_LINE,
.EXTI_Mode = EXTI_Mode_Interrupt,
.EXTI_Trigger = EXTI_Trigger_Rising,
.EXTI_LineCmd = ENABLE,
},
},
};
#endif /* PIOS_BMP085_HAS_GPIOS */
/**
* Initialise the BMP085 sensor
*/
void PIOS_BMP085_Init(void)
{
#ifdef PIOS_BMP085_HAS_GPIOS
#if defined(PIOS_INCLUDE_FREERTOS)
/* Semaphore used by ISR to signal End-Of-Conversion */
vSemaphoreCreateBinary(PIOS_BMP085_EOC);
/* Must start off empty so that first transfer waits for EOC */
xSemaphoreTake(PIOS_BMP085_EOC, portMAX_DELAY);
#else
PIOS_BMP085_EOC = 0;
#endif
/* Enable EOC GPIO clock */
RCC_APB2PeriphClockCmd(PIOS_BMP085_EOC_CLK | RCC_APB2Periph_AFIO, ENABLE);
if (PIOS_EXTI_Init(&pios_exti_bmp085_cfg)) {
PIOS_Assert(0);
}
/* Configure XCLR pin as push/pull alternate funtion output */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = PIOS_BMP085_XCLR_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(PIOS_BMP085_XCLR_GPIO_PORT, &GPIO_InitStructure);
#endif /* PIOS_BMP085_HAS_GPIOS */
/* Read all 22 bytes of calibration data in one transfer, this is a very optimized way of doing things */
uint8_t Data[BMP085_CALIB_LEN];
while (PIOS_BMP085_Read(BMP085_CALIB_ADDR, Data, BMP085_CALIB_LEN) != 0)
continue;
/* Parameters AC1-AC6 */
CalibData.AC1 = (Data[0] << 8) | Data[1];
CalibData.AC2 = (Data[2] << 8) | Data[3];
CalibData.AC3 = (Data[4] << 8) | Data[5];
CalibData.AC4 = (Data[6] << 8) | Data[7];
CalibData.AC5 = (Data[8] << 8) | Data[9];
CalibData.AC6 = (Data[10] << 8) | Data[11];
/* Parameters B1, B2 */
CalibData.B1 = (Data[12] << 8) | Data[13];
CalibData.B2 = (Data[14] << 8) | Data[15];
/* Parameters MB, MC, MD */
CalibData.MB = (Data[16] << 8) | Data[17];
CalibData.MC = (Data[18] << 8) | Data[19];
CalibData.MD = (Data[20] << 8) | Data[21];
}
/**
* Start the ADC conversion
* \param[in] PresOrTemp BMP085_PRES_ADDR or BMP085_TEMP_ADDR
* \return Raw ADC value
*/
void PIOS_BMP085_StartADC(ConversionTypeTypeDef Type)
{
/* Start the conversion */
if (Type == TemperatureConv) {
while (PIOS_BMP085_Write(BMP085_CTRL_ADDR, BMP085_TEMP_ADDR) != 0)
continue;
} else if (Type == PressureConv) {
while (PIOS_BMP085_Write(BMP085_CTRL_ADDR, BMP085_PRES_ADDR) != 0)
continue;
}
CurrentRead = Type;
}
/**
* Read the ADC conversion value (once ADC conversion has completed)
* \param[in] PresOrTemp BMP085_PRES_ADDR or BMP085_TEMP_ADDR
* \return Raw ADC value
*/
void PIOS_BMP085_ReadADC(void)
{
uint8_t Data[3];
Data[0] = 0;
Data[1] = 0;
Data[2] = 0;
/* Read and store the 16bit result */
if (CurrentRead == TemperatureConv) {
/* Read the temperature conversion */
while (PIOS_BMP085_Read(BMP085_ADC_MSB, Data, 2) != 0)
continue;
RawTemperature = ((Data[0] << 8) | Data[1]);
X1 = (RawTemperature - CalibData.AC6) * CalibData.AC5 >> 15;
X2 = ((int32_t) CalibData.MC << 11) / (X1 + CalibData.MD);
B5 = X1 + X2;
Temperature = (B5 + 8) >> 4;
} else {
/* Read the pressure conversion */
while (PIOS_BMP085_Read(BMP085_ADC_MSB, Data, 3) != 0)
continue;
RawPressure = ((Data[0] << 16) | (Data[1] << 8) | Data[2]) >> (8 - BMP085_OVERSAMPLING);
B6 = B5 - 4000;
X1 = (CalibData.B2 * (B6 * B6 >> 12)) >> 11;
X2 = CalibData.AC2 * B6 >> 11;
X3 = X1 + X2;
B3 = ((((int32_t) CalibData.AC1 * 4 + X3) << BMP085_OVERSAMPLING) + 2) >> 2;
X1 = CalibData.AC3 * B6 >> 13;
X2 = (CalibData.B1 * (B6 * B6 >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = (CalibData.AC4 * (uint32_t) (X3 + 32768)) >> 15;
B7 = ((uint32_t) RawPressure - B3) * (50000 >> BMP085_OVERSAMPLING);
P = B7 < 0x80000000 ? (B7 * 2) / B4 : (B7 / B4) * 2;
X1 = (P >> 8) * (P >> 8);
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * P) >> 16;
Pressure = P + ((X1 + X2 + 3791) >> 4);
}
}
int16_t PIOS_BMP085_GetTemperature(void)
{
return Temperature;
}
int32_t PIOS_BMP085_GetPressure(void)
{
return Pressure;
}
/**
* Reads one or more bytes into a buffer
* \param[in] address BMP085 register address (depends on size)
* \param[out] buffer destination buffer
* \param[in] len number of bytes which should be read
* \return 0 if operation was successful
* \return -1 if error during I2C transfer
* \return -2 if BMP085 blocked by another task (retry it!)
* \return -4 if invalid length
*/
bool PIOS_BMP085_Read(uint8_t address, uint8_t * buffer, uint8_t len)
{
uint8_t addr_buffer[] = {
address,
};
const struct pios_i2c_txn txn_list[] = {
{
.info = __func__,
.addr = BMP085_I2C_ADDR,
.rw = PIOS_I2C_TXN_WRITE,
.len = sizeof(addr_buffer),
.buf = addr_buffer,
}
,
{
.info = __func__,
.addr = BMP085_I2C_ADDR,
.rw = PIOS_I2C_TXN_READ,
.len = len,
.buf = buffer,
}
};
return PIOS_I2C_Transfer(PIOS_I2C_BMP085_ADAPTER, txn_list, NELEMENTS(txn_list));
}
/**
* Writes one or more bytes to the BMP085
* \param[in] address Register address
* \param[in] buffer source buffer
* \return 0 if operation was successful
* \return -1 if error during I2C transfer
* \return -2 if BMP085 blocked by another task (retry it!)
*/
bool PIOS_BMP085_Write(uint8_t address, uint8_t buffer)
{
uint8_t data[] = {
address,
buffer,
};
const struct pios_i2c_txn txn_list[] = {
{
.info = __func__,
.addr = BMP085_I2C_ADDR,
.rw = PIOS_I2C_TXN_WRITE,
.len = sizeof(data),
.buf = data,
}
,
};
return PIOS_I2C_Transfer(PIOS_I2C_BMP085_ADAPTER, txn_list, NELEMENTS(txn_list));
}
/**
* @brief Run self-test operation.
* \return 0 if self-test failed
* \return any non-0 number if test passed
*/
int32_t PIOS_BMP085_Test()
{
// TODO: Is there a better way to test this than just checking that pressure/temperature has changed?
uint32_t passed = 1;
uint32_t cur_value = 0;
cur_value = Temperature;
PIOS_BMP085_StartADC(TemperatureConv);
PIOS_DELAY_WaitmS(5);
PIOS_BMP085_ReadADC();
if (cur_value == Temperature)
passed = 0;
cur_value=Pressure;
PIOS_BMP085_StartADC(PressureConv);
PIOS_DELAY_WaitmS(26);
PIOS_BMP085_ReadADC();
if (cur_value == Pressure)
passed = 0;
return passed;
}
#endif /* PIOS_INCLUDE_BMP085 */