2009-12-10 02:59:46 +01:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
*
|
|
|
|
* @file pios_bmp085.c
|
2010-01-31 18:56:54 +01:00
|
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
2009-12-10 02:59:46 +01:00
|
|
|
* @brief IRQ Enable/Disable routines
|
|
|
|
* @see The GNU Public License (GPL) Version 3
|
2009-12-10 05:28:21 +01:00
|
|
|
* @defgroup PIOS_BMP085 BMP085 Functions
|
2009-12-10 02:59:46 +01:00
|
|
|
* @{
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2009-12-10 07:08:28 +01:00
|
|
|
/*
|
|
|
|
Example of how to use this module:
|
|
|
|
PIOS_BMP085_Init();
|
|
|
|
|
|
|
|
PIOS_BMP085_StartADC(Temperature);
|
|
|
|
(Interrupt reads the ADC)
|
|
|
|
|
|
|
|
Somwhere inbetween these 2 calls we need to wait for the first one to finish
|
|
|
|
|
|
|
|
PIOS_BMP085_StartADC(Pressure);
|
|
|
|
(Interrupt reads the ADC)
|
|
|
|
|
|
|
|
PIOS_BMP085_GetValues(&Pressure, &Altitude, &Temperature);
|
|
|
|
*/
|
2009-12-10 02:59:46 +01:00
|
|
|
|
|
|
|
/* Project Includes */
|
|
|
|
#include "pios.h"
|
|
|
|
|
2009-12-11 01:24:03 +01:00
|
|
|
|
2009-12-10 05:28:21 +01:00
|
|
|
/* Glocal Variables */
|
|
|
|
ConversionTypeTypeDef CurrentRead;
|
2009-12-10 02:59:46 +01:00
|
|
|
|
2009-12-11 01:24:03 +01:00
|
|
|
|
2009-12-10 02:59:46 +01:00
|
|
|
/* Local Variables */
|
|
|
|
static BMP085CalibDataTypeDef CalibData;
|
2009-12-10 05:28:21 +01:00
|
|
|
static uint16_t RawPressure;
|
2009-12-11 01:24:03 +01:00
|
|
|
static uint32_t RawTemperature;
|
2009-12-10 05:28:21 +01:00
|
|
|
|
2009-12-10 02:59:46 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialise the BMP085 sensor
|
|
|
|
*/
|
|
|
|
void PIOS_BMP085_Init(void)
|
|
|
|
{
|
2009-12-10 07:08:28 +01:00
|
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
|
|
EXTI_InitTypeDef EXTI_InitStructure;
|
|
|
|
NVIC_InitTypeDef NVIC_InitStructure;
|
|
|
|
|
|
|
|
/* Enable EOC GPIO clock */
|
|
|
|
RCC_APB2PeriphClockCmd(BMP085_EOC_CLK | RCC_APB2Periph_AFIO, ENABLE);
|
|
|
|
|
|
|
|
/* Configure EOC pin as input floating */
|
|
|
|
GPIO_InitStructure.GPIO_Pin = BMP085_EOC_GPIO_PIN;
|
|
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
|
|
|
GPIO_Init(BMP085_EOC_GPIO_PORT, &GPIO_InitStructure);
|
|
|
|
|
|
|
|
/* Configure the End Of Conversion (EOC) interrup */
|
|
|
|
GPIO_EXTILineConfig(BMP085_EOC_PORT_SOURCE, BMP085_EOC_PIN_SOURCE);
|
|
|
|
EXTI_InitStructure.EXTI_Line = BMP085_EOC_EXTI_LINE;
|
|
|
|
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
|
|
|
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
|
|
|
|
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
|
|
|
|
EXTI_Init(&EXTI_InitStructure);
|
|
|
|
|
|
|
|
/* Enable and set EOC EXTI Interrupt to the lowest priority */
|
|
|
|
NVIC_InitStructure.NVIC_IRQChannel = BMP085_EOC_IRQn;
|
|
|
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
|
|
|
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 15;
|
|
|
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
|
|
|
NVIC_Init(&NVIC_InitStructure);
|
|
|
|
|
2009-12-11 01:24:03 +01:00
|
|
|
/* Read all 22 bytes of calibration data in one transfer, this is a very optimised way of doing things */
|
|
|
|
uint8_t Data[22];
|
|
|
|
PIOS_BMP085_Read(BMP085_CALIB_ADDR, Data, BMP085_CALIB_LEN);
|
|
|
|
|
|
|
|
/* 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];
|
2009-12-10 02:59:46 +01:00
|
|
|
}
|
|
|
|
|
2009-12-10 05:28:21 +01:00
|
|
|
|
2009-12-10 02:59:46 +01:00
|
|
|
/**
|
|
|
|
* Start the ADC conversion
|
|
|
|
* \param[in] PresOrTemp BMP085_PRES_ADDR or BMP085_TEMP_ADDR
|
|
|
|
* \return Raw ADC value
|
|
|
|
*/
|
2009-12-10 05:28:21 +01:00
|
|
|
void PIOS_BMP085_StartADC(ConversionTypeTypeDef Type)
|
2009-12-10 02:59:46 +01:00
|
|
|
{
|
|
|
|
/* Start the conversion */
|
2009-12-10 05:28:21 +01:00
|
|
|
if(Type == Temperature) {
|
2009-12-11 01:24:03 +01:00
|
|
|
PIOS_BMP085_Write(BMP085_CTRL_ADDR, (uint8_t *)BMP085_TEMP_ADDR, 1);
|
2009-12-10 05:28:21 +01:00
|
|
|
} else if(Type == Pressure) {
|
2009-12-11 01:24:03 +01:00
|
|
|
PIOS_BMP085_Write(BMP085_CTRL_ADDR, (uint8_t *)BMP085_PRES_ADDR, 1);
|
2009-12-10 05:28:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CurrentRead = Type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read the ADC conversion value (once ADC converion has completed)
|
|
|
|
* \param[in] PresOrTemp BMP085_PRES_ADDR or BMP085_TEMP_ADDR
|
|
|
|
* \return Raw ADC value
|
|
|
|
*/
|
|
|
|
void PIOS_BMP085_ReadADC(void)
|
|
|
|
{
|
2009-12-11 01:24:03 +01:00
|
|
|
uint8_t Data[3];
|
2009-12-10 05:28:21 +01:00
|
|
|
|
2009-12-11 01:24:03 +01:00
|
|
|
/* Read and store the 16bit result */
|
2009-12-10 05:28:21 +01:00
|
|
|
if(CurrentRead == Temperature) {
|
2009-12-11 01:24:03 +01:00
|
|
|
/* Read the temperature conversion */
|
|
|
|
PIOS_BMP085_Read(BMP085_ADC_MSB, Data, 2);
|
|
|
|
RawTemperature = ((Data[0] << 8) | Data[1]);
|
2009-12-10 05:28:21 +01:00
|
|
|
} else {
|
2009-12-11 01:24:03 +01:00
|
|
|
/* Read the pressure conversion */
|
|
|
|
PIOS_BMP085_Read(BMP085_ADC_MSB, Data, 3);
|
|
|
|
RawPressure = ((Data[0] << 16) | (Data[1] << 8) | Data[2]) >> (8 - BMP085_OVERSAMPLING);
|
2009-12-10 05:28:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the converted raw values
|
|
|
|
* \param[out] Pressure Pointer to the pressure variable
|
|
|
|
* \param[out] Altitude Pointer to the altitude variable
|
|
|
|
* \param[out] Temperature Pointer to the temperature variable
|
|
|
|
*/
|
|
|
|
void PIOS_BMP085_GetValues(uint16_t *Pressure, uint16_t *Altitude, uint16_t *Temperature)
|
|
|
|
{
|
|
|
|
/* Straight from the datasheet */
|
|
|
|
int32_t X1, X2, X3, B3, B5, B6, P;
|
|
|
|
uint32_t B4, B7;
|
|
|
|
|
|
|
|
/* Convert Temperatre */
|
|
|
|
X1 = (RawTemperature - CalibData.AC6) * CalibData.AC5 >> 15;
|
|
|
|
X2 = ((int32_t) CalibData.MC << 11) / (X1 + CalibData.MD);
|
|
|
|
B5 = X1 + X2;
|
|
|
|
*Temperature = (B5 + 8) >> 4;
|
|
|
|
|
|
|
|
/* Calculate Pressure */
|
|
|
|
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 + 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;
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Calculate Altitude */
|
|
|
|
*Altitude = (uint16_t) 44330 * (1 - (pow((*Pressure/BMP085_P0), (1/5.255))));
|
2009-12-10 02:59:46 +01:00
|
|
|
}
|
|
|
|
|
2009-12-10 07:08:28 +01:00
|
|
|
|
2009-12-10 02:59:46 +01:00
|
|
|
/**
|
|
|
|
* 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 (1..64)
|
|
|
|
* \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
|
|
|
|
*/
|
|
|
|
int32_t PIOS_BMP085_Read(uint16_t address, uint8_t *buffer, uint8_t len)
|
|
|
|
{
|
|
|
|
/* Try to get the IIC peripheral */
|
|
|
|
if(PIOS_I2C_TransferBegin(I2C_Non_Blocking) < 0) {
|
|
|
|
/* Request a retry */
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send I2C address and EEPROM address */
|
|
|
|
/* To avoid issues with litte/big endian: copy address into temporary buffer */
|
|
|
|
uint8_t addr_buffer[2] = {(uint8_t)(address>>8), (uint8_t)address};
|
2009-12-11 01:24:03 +01:00
|
|
|
int32_t error = PIOS_I2C_Transfer(I2C_Write_WithoutStop, BMP085_I2C_ADDR, addr_buffer, 2);
|
2009-12-10 02:59:46 +01:00
|
|
|
|
|
|
|
if(!error) {
|
|
|
|
error = PIOS_I2C_TransferWait();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now receive byte(s) */
|
|
|
|
if(!error) {
|
2009-12-11 01:24:03 +01:00
|
|
|
error = PIOS_I2C_Transfer(I2C_Read, BMP085_I2C_ADDR, buffer, len);
|
2009-12-10 02:59:46 +01:00
|
|
|
}
|
|
|
|
if(!error) {
|
|
|
|
error = PIOS_I2C_TransferWait();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release I2C peripheral */
|
|
|
|
PIOS_I2C_TransferFinished();
|
|
|
|
|
|
|
|
/* Return error status */
|
|
|
|
return error < 0 ? -1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes one or more bytes to the BMP085
|
|
|
|
* \param[in] address BankStick address (depends on size)
|
|
|
|
* \param[in] buffer source buffer
|
|
|
|
* \param[in] len number of bytes which should be written (1..64)
|
|
|
|
* \return 0 if operation was successful
|
|
|
|
* \return -1 if error during IIC transfer
|
|
|
|
* \return -2 if BankStick blocked by another task (retry it!)
|
|
|
|
* \note Use \ref PIOS_I2C_BS_CheckWriteFinished to check when the write operation
|
|
|
|
* has been finished - this can take up to 5 mS!
|
|
|
|
*/
|
|
|
|
int32_t PIOS_BMP085_Write(uint16_t address, uint8_t *buffer, uint8_t len)
|
|
|
|
{
|
|
|
|
/* Try to get the IIC peripheral */
|
|
|
|
if(PIOS_I2C_TransferBegin(I2C_Non_Blocking) < 0) {
|
|
|
|
/* Request a retry */
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2009-12-11 01:24:03 +01:00
|
|
|
/* Send I2C address and data */
|
|
|
|
uint8_t WriteBuffer[64+2];
|
|
|
|
WriteBuffer[0] = (uint8_t) (address >> 8);
|
|
|
|
WriteBuffer[1] = (uint8_t) address;
|
2009-12-10 02:59:46 +01:00
|
|
|
|
2009-12-11 01:24:03 +01:00
|
|
|
uint8_t i;
|
|
|
|
for(i = 0; i < len; i++) {
|
|
|
|
WriteBuffer[i+2] = buffer[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t error = PIOS_I2C_Transfer(I2C_Write, BMP085_I2C_ADDR, WriteBuffer, len+2);
|
|
|
|
|
2009-12-10 02:59:46 +01:00
|
|
|
if(!error) {
|
|
|
|
error = PIOS_I2C_TransferWait();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release I2C peripheral */
|
|
|
|
PIOS_I2C_TransferFinished();
|
|
|
|
|
|
|
|
/* Return error status */
|
|
|
|
return error < 0 ? -1 : 0;
|
|
|
|
}
|
|
|
|
|
2009-12-10 07:08:28 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This function handles External lines 15 to 10 interrupt request
|
|
|
|
*/
|
|
|
|
void EXTI15_10_IRQHandler(void)
|
|
|
|
{
|
|
|
|
if(EXTI_GetITStatus(BMP085_EOC_EXTI_LINE) != RESET) {
|
|
|
|
/* Disable interrupts */
|
|
|
|
PIOS_IRQ_Disable();
|
|
|
|
|
|
|
|
/* Read the ADC Value */
|
|
|
|
PIOS_BMP085_ReadADC();
|
|
|
|
|
|
|
|
/* Clear the EOC EXTI line pending bit */
|
|
|
|
EXTI_ClearITPendingBit(BMP085_EOC_EXTI_LINE);
|
|
|
|
|
|
|
|
/* Enable interrupts */
|
|
|
|
PIOS_IRQ_Enable();
|
|
|
|
}
|
|
|
|
}
|