Digital Pressure Sensor

BMP180.cpp

Committer:
mcm
Date:
2018-09-11
Revision:
3:60816c745222
Parent:
2:3a52d110213a

File content as of revision 3:60816c745222:

/**
 * @brief       BMP180.cpp
 * @details     Digital Pressure Sensor.
 *              Functions file.
 *
 *
 * @return      N/A
 *
 * @author      Manuel Caballero
 * @date        11/September/2018
 * @version     11/September/2018    The ORIGIN
 * @pre         N/A
 * @warning     N/A
 * @pre         This code belongs to Nimbus Centre ( http://www.nimbus.cit.ie ).
 */

#include "BMP180.h"


BMP180::BMP180 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq )
    : _i2c         ( sda, scl )
    , _BMP180_Addr  ( addr )
{
    _i2c.frequency( freq );
}


BMP180::~BMP180()
{
}



/**
 * @brief       BMP180_GetID    ( BMP180_chip_id_data_t* )
 * @details     It gets the chip-ID.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myID:   Chip-ID
 *
 *
 * @return      Status of BMP180_GetID.
 *
 * @author      Manuel Caballero
 * @date        11/September/2018
 * @version     11/September/2018    The ORIGIN
 * @pre         It must be 0x55.
 * @warning     N/A.
 */
BMP180::BMP180_status_t  BMP180::BMP180_GetID ( BMP180_chip_id_data_t* myID )
{
    char      cmd   =    0U;
    uint32_t  aux;


    /* Get ID    */
    cmd  =   BMP180_ID;
    aux  =   _i2c.write ( _BMP180_Addr, &cmd, 1U, true );
    aux  =   _i2c.read  ( _BMP180_Addr, (char*)&myID->id, 1U );




    if ( aux == I2C_SUCCESS ) {
        return   BMP180_SUCCESS;
    } else {
        return   BMP180_FAILURE;
    }
}



/**
* @brief       BMP180_SoftReset   ( void )
* @details     It performs a soft reset.
*
* @param[in]    N/A.
*
* @param[out]   N/A
*
*
* @return      Status of BMP180_SoftReset.
*
* @author      Manuel Caballero
* @date        11/September/2018
* @version     11/September/2018        The ORIGIN
* @pre         N/A
* @warning     N/A.
*/
BMP180::BMP180_status_t  BMP180::BMP180_SoftReset   ( void )
{
    char     cmd[]   =   { 0, 0 };
    uint32_t aux;


    cmd[0]   =   BMP180_SOFT;
    cmd[1]   =   SOFT_SOFT_RESET;
    aux      =   _i2c.write ( _BMP180_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );




    if ( aux == I2C_SUCCESS ) {
        return   BMP180_SUCCESS;
    } else {
        return   BMP180_FAILURE;
    }
}


/**
* @brief       BMP180_Get_Cal_Param   ( BMP180_calibration_data_t* )
* @details     It reads the calibration data.
*
* @param[in]    N/A.
*
* @param[out]   myCalibrationData: Calibration data from the sensor.
*
*
* @return      Status of BMP180_Get_Cal_Param.
*
* @author      Manuel Caballero
* @date        11/September/2018
* @version     11/September/2018        The ORIGIN
* @pre         N/A
* @warning     N/A
*/
BMP180::BMP180_status_t  BMP180::BMP180_Get_Cal_Param ( BMP180_calibration_data_t* myCalibrationData )
{
    char     cmd[22]    =    { 0U };
    uint32_t aux;


    /* Read out all calibration data from the sensor ( auto-increment )    */
    cmd[0]   =   BMP180_AC1_MSB;
    aux      =   _i2c.write ( _BMP180_Addr, &cmd[0], 1U, true );
    aux      =   _i2c.read  ( _BMP180_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );


    /* Parse the data  */
    myCalibrationData->ac1    =   cmd[0];
    myCalibrationData->ac1  <<=   8U;
    myCalibrationData->ac1   |=   cmd[1];

    myCalibrationData->ac2    =   cmd[2];
    myCalibrationData->ac2  <<=   8U;
    myCalibrationData->ac2   |=   cmd[3];

    myCalibrationData->ac3    =   cmd[4];
    myCalibrationData->ac3  <<=   8U;
    myCalibrationData->ac3   |=   cmd[5];

    myCalibrationData->ac4    =   cmd[6];
    myCalibrationData->ac4  <<=   8U;
    myCalibrationData->ac4   |=   cmd[7];

    myCalibrationData->ac5    =   cmd[8];
    myCalibrationData->ac5  <<=   8U;
    myCalibrationData->ac5   |=   cmd[9];

    myCalibrationData->ac6    =   cmd[10];
    myCalibrationData->ac6  <<=   8U;
    myCalibrationData->ac6   |=   cmd[11];

    myCalibrationData->b1     =   cmd[12];
    myCalibrationData->b1   <<=   8U;
    myCalibrationData->b1    |=   cmd[13];

    myCalibrationData->b2     =   cmd[14];
    myCalibrationData->b2   <<=   8U;
    myCalibrationData->b2    |=   cmd[15];

    myCalibrationData->mb     =   cmd[16];
    myCalibrationData->mb   <<=   8U;
    myCalibrationData->mb    |=   cmd[17];

    myCalibrationData->mc     =   cmd[18];
    myCalibrationData->mc   <<=   8U;
    myCalibrationData->mc    |=   cmd[19];

    myCalibrationData->md     =   cmd[20];
    myCalibrationData->md   <<=   8U;
    myCalibrationData->md    |=   cmd[21];





    if ( aux == I2C_SUCCESS ) {
        return   BMP180_SUCCESS;
    } else {
        return   BMP180_FAILURE;
    }
}



/**
 * @brief       BMP180_Get_UT   ( BMP180_uncompensated_data_t* )
 * @details     It reads uncompensated temperature value.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myUT:              Uncompensated temperature value.
 *
 *
 * @return      Status of BMP180_Get_UT.
 *
 * @author      Manuel Caballero
 * @date        11/September/2018
 * @version     11/September/2018        The ORIGIN
 * @pre         This function checks the bit SCO until the conversion is complete instead of
 *              4.5ms.
 * @warning     N/A
 */
BMP180::BMP180_status_t  BMP180::BMP180_Get_UT ( BMP180_uncompensated_data_t* myUT )
{
    char     cmd[]      =    { 0U, 0U };
    uint32_t myTimeout  =    0U;
    uint32_t aux;


    /* Read out the uncompensated temperature data    */
    cmd[0]   =   BMP180_CTRL_MEAS;
    cmd[1]   =   BMP180_TRIGGER_TEMPERATURE;
    aux      =   _i2c.write ( _BMP180_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );


    /* Wait until conversion is complete or timeout  */
    myTimeout    =   0x232323;
    do {
        cmd[0]   =   BMP180_CTRL_MEAS;
        aux      =   _i2c.write ( _BMP180_Addr, &cmd[0], 1U, true );
        aux      =   _i2c.read  ( _BMP180_Addr, &cmd[0], 1U );
        myTimeout--;
    } while ( ( ( cmd[0] & CTRL_MEAS_SCO_MASK ) == CTRL_MEAS_SCO_CONVERSION_IN_PROGRESS ) && ( myTimeout > 0U ) );


    /* Parse the data only if not timeout    */
    if ( myTimeout > 0U ) {
        cmd[0]   =   BMP180_OUT_MSB;
        aux      =   _i2c.write ( _BMP180_Addr, &cmd[0], 1U, true );
        aux      =   _i2c.read  ( _BMP180_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );

        /* Parse the data  */
        myUT->ut    =   cmd[0];
        myUT->ut  <<=   8U;
        myUT->ut   |=   cmd[1];
    }





    if ( ( aux == I2C_SUCCESS ) && ( myTimeout > 0U ) ) {
        return   BMP180_SUCCESS;
    } else {
        return   BMP180_FAILURE;
    }
}



/**
 * @brief       BMP180_Get_UP   ( BMP180_pressure_resolution_t , BMP180_uncompensated_data_t* )
 * @details     It reads uncompensated pressure value.
 *
 * @param[in]    myPressureResolutionMode:  Resolution mode.
 *
 * @param[out]   myUP:                      Uncompensated pressure value.
 *
 *
 * @return      Status of BMP180_Get_UP.
 *
 * @author      Manuel Caballero
 * @date        11/September/2018
 * @version     11/September/2018        The ORIGIN
 * @pre         This function checks the bit SCO until the conversion is complete instead of
 *              the delay depending of the resolution mode:
 *                  - Ultra low power mode           4.5ms ( max. )
 *                  - Standard mode                  7.5ms ( max. )
 *                  - High resolution mode          13.5ms ( max. )
 *                  - Ultra high resolution mode    25.5ms ( max. )
 * @warning     N/A
 */
BMP180::BMP180_status_t  BMP180::BMP180_Get_UP ( BMP180_pressure_resolution_t myPressureResolutionMode, BMP180_uncompensated_data_t* myUP )
{
    char     cmd[]      =    { 0U, 0U, 0U };
    uint32_t myTimeout  =    0U;
    uint32_t aux;


    /* Read out the uncompensated pressure data according to the chosen resolution mode    */
    cmd[0]   =   BMP180_CTRL_MEAS;
    cmd[1]   =   ( BMP180_TRIGGER_PRESSURE | myPressureResolutionMode ) ;
    aux      =   _i2c.write ( _BMP180_Addr, &cmd[0], 2U, false );


    /* Wait until conversion is complete or timeout  */
    myTimeout    =   0x232323;
    do {
        cmd[0]   =   BMP180_CTRL_MEAS;
        aux      =   _i2c.write ( _BMP180_Addr, &cmd[0], 1U, true );
        aux      =   _i2c.read  ( _BMP180_Addr, &cmd[0], 1U );
        myTimeout--;
    } while ( ( ( cmd[0] & CTRL_MEAS_SCO_MASK ) == CTRL_MEAS_SCO_CONVERSION_IN_PROGRESS ) && ( myTimeout > 0U ) );


    /* Parse the data only if not timeout    */
    if ( myTimeout > 0U ) {
        cmd[0]   =   BMP180_OUT_MSB;
        aux      =   _i2c.write ( _BMP180_Addr, &cmd[0], 1U, true );
        aux      =   _i2c.read  ( _BMP180_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );

        /* Parse the data  */
        myUP->up    =   cmd[0];
        myUP->up  <<=   8U;
        myUP->up   |=   cmd[1];
        myUP->up  <<=   8U;
        myUP->up   |=   cmd[2];
        myUP->up  >>=   ( 8U - ( myPressureResolutionMode >> 6U ) );
    }





    if ( ( aux == I2C_SUCCESS ) && ( myTimeout > 0U ) ) {
        return   BMP180_SUCCESS;
    } else {
        return   BMP180_FAILURE;
    }
}



/**
 * @brief       BMP180_Get_Temperature   ( BMP180_calibration_data_t , BMP180_uncompensated_data_t )
 * @details     It calculates true temperature.
 *
 * @param[in]    myCalibrationData: Calibration data.
 * @param[in]    myUT:              Uncompensated temperature value.
 *
 * @param[out]   N/A.
 *
 *
 * @return      True temperature.
 *
 * @author      Manuel Caballero
 * @date        11/September/2018
 * @version     11/September/2018        The ORIGIN
 * @pre         True temperature in 0.1 C.
 * @pre         It is sufficient to measure the temperature only once per second and use this value for all pressure measurements during the same period.
 * @warning     This function should have been called at least once: BMP180_Get_Cal_Param.
 * @warning     This function should have been called before: BMP180_Get_UT.
 */
BMP180::BMP180_temperature_data_t  BMP180::BMP180_Get_Temperature ( BMP180_calibration_data_t myCalibrationData, BMP180_uncompensated_data_t myUT )
{
    int32_t x1 = 0, x2 = 0;

    BMP180_temperature_data_t myTrueData;


    /* Calculate X1  */
    x1   =   ( myUT.ut - myCalibrationData.ac6 ) * myCalibrationData.ac5 / 32768.0f;

    /* Calculate X2  */
    x2   =   ( myCalibrationData.mc * 2048.0f );
    x2  /=   ( x1 + myCalibrationData.md );

    /* Calculate B5  */
    myTrueData.b5    =   ( x1 + x2 );

    /* Calculate True Temperature  */
    myTrueData.temp   =  ( myTrueData.b5 + 8.0f ) / 16.0f;



    return   myTrueData;
}



/**
 * @brief       BMP180_Get_CalPressure   ( BMP180_calibration_data_t , BMP180_data_t , BMP180_pressure_resolution_t , BMP180_uncompensated_data_t )
 * @details     It calculates true pressure.
 *
 * @param[in]    myCalibrationData:         Calibration data.
 * @param[in]    myB5:                      Temperature parameter value.
 * @param[in]    myPressureResolutionMode:  Resolution mode.
 * @param[in]    myUP:                      Uncompensated pressure value.
 *
 * @param[out]   N/A.
 *
 *
 * @return      True Pressure.
 *
 * @author      Manuel Caballero
 * @date        11/September/2018
 * @version     11/September/2018        The ORIGIN
 * @pre         True temperature in Pa.
 * @pre         It is sufficient to measure the temperature only once per second and use this value for all pressure measurements during the same period.
 * @warning     These functions should have been called at least once: BMP180_Get_Cal_Param and BMP180_Get_Temperature.
 * @warning     This function should have been called before: BMP180_Get_UP.
 */
BMP180::BMP180_pressure_data_t  BMP180::BMP180_Get_CalPressure ( BMP180_calibration_data_t myCalibrationData, BMP180_temperature_data_t myB5, BMP180_pressure_resolution_t myPressureResolutionMode, BMP180_uncompensated_data_t myUP )
{
    int32_t  b6 = 0, x1 = 0, x2 = 0, x3 = 0, b3 = 0;
    uint32_t b4 = 0, b7 = 0;

    BMP180_pressure_data_t myTrueData;


    /* Calculate B6  */
    b6   =   ( myB5.b5 - 4000.0f );

    /* Calculate X1  */
    x1   =   ( myCalibrationData.b2 * ( b6 * b6 / 4096.0f ) ) / 2048.0f;

    /* Calculate X2  */
    x2   =   myCalibrationData.ac2 * b6 / 4096.0f;

    /* Calculate X3  */
    x3   =   x1 + x2;

    /* Calculate B3  */
    b3   =   ( ( ( ( (long)myCalibrationData.ac1 * 4 + x3 ) << ( myPressureResolutionMode >> 6U ) ) + 2 ) ) / 4.0f;

    /* Re-calculate X1  */
    x1   =   ( myCalibrationData.ac3 * b6 ) / 524288.0f;

    /* Re-calculate X2  */
    x2   =   ( myCalibrationData.b1 * ( b6 * b6 / 4096.0f ) ) / 65536.0f;

    /* Re-calculate X3  */
    x3   =   ( ( x1 + x2 ) + 2.0f ) / 4.0f;

    /* Calculate B4  */
    b4   =   myCalibrationData.ac4 * (unsigned long)( x3 + 32768.0f ) / 32768.0f;

    /* Calculate B7  */
    b7   =   ( (unsigned long)myUP.up - b3 ) * ( 50000 >> ( myPressureResolutionMode >> 6U ) );


    if ( b7 < 0x80000000 ) {
        myTrueData.press     =   ( b7 * 2.0f ) / b4;
    } else {
        myTrueData.press     =   ( b7 / b4 ) * 2.0f;
    }

    /* Re-calculate X1  */
    x1   =   ( myTrueData.press / 256.0f ) * ( myTrueData.press / 256.0f );
    x1   =   ( x1 * 3038.0f ) / 65536.0f;

    /* Re-calculate X2  */
    x2   =   ( -7357.0f * myTrueData.press ) / 65536.0f;

    /* Calculate True Pressure  */
    myTrueData.press  +=  ( x1 + x2 + 3791.0f ) / 16.0f;



    return   myTrueData;
}