Files
upm/src/bmpx8x/bmpx8x.c
Jon Trulson c57a0d2c30 bmpx8x: rewrite in C; FTI; C++ wraps C
This driver has been rewritten from scratch.

See docs/apichanges.md for a list of API compatibility changes
compared to the original driver.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
2017-04-05 11:29:08 -06:00

361 lines
9.4 KiB
C

/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* This driver was rewritten based on the original driver written by:
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <unistd.h>
#include <assert.h>
#include "upm_utilities.h"
#include "upm_math.h"
#include "bmpx8x.h"
// UT is uncompensated temperature
static int32_t _bmpx8x_computeB5(const bmpx8x_context dev, int32_t UT)
{
assert(dev != NULL);
int32_t X1 = (UT - (int32_t)dev->ac6) * ((int32_t)dev->ac5) >> 15;
int32_t X2 = ((int32_t)dev->mc << 11) / (X1+(int32_t)dev->md);
return X1 + X2;
}
static upm_result_t _bmpx8x_read_calibration_data(const bmpx8x_context dev)
{
assert(dev != NULL);
const int dataLen = 22;
uint8_t calData[dataLen];
if (bmpx8x_read_regs(dev, BMPX8X_CAL_AC1, calData, dataLen) != dataLen)
return UPM_ERROR_OPERATION_FAILED;
dev->ac1 = (int16_t)( (calData[0] << 8) | calData[1] );
dev->ac2 = (int16_t)( (calData[2] << 8) | calData[3] );
dev->ac3 = (int16_t)( (calData[4] << 8) | calData[5] );
dev->ac4 = (uint16_t)( (calData[6] << 8) | calData[7] );
dev->ac5 = (uint16_t)( (calData[8] << 8) | calData[9] );
dev->ac6 = (uint16_t)( (calData[10] << 8) | calData[11] );
dev->b1 = (int16_t)( (calData[12] << 8) | calData[13] );
dev->b2 = (int16_t)( (calData[14] << 8) | calData[15] );
dev->mb = (int16_t)( (calData[16] << 8) | calData[17] );
dev->mc = (int16_t)( (calData[18] << 8) | calData[19] );
dev->md = (int16_t)( (calData[20] << 8) | calData[21] );
return UPM_SUCCESS;
}
// init
bmpx8x_context bmpx8x_init(int bus, int addr)
{
bmpx8x_context dev =
(bmpx8x_context)malloc(sizeof(struct _bmpx8x_context));
if (!dev)
return NULL;
// zero out context
memset((void *)dev, 0, sizeof(struct _bmpx8x_context));
// make sure MRAA is initialized
if (mraa_init() != MRAA_SUCCESS)
{
printf("%s: mraa_init() failed.\n", __FUNCTION__);
bmpx8x_close(dev);
return NULL;
}
if (!(dev->i2c = mraa_i2c_init(bus)))
{
printf("%s: mraa_i2c_init() failed.\n", __FUNCTION__);
bmpx8x_close(dev);
return NULL;
}
if (mraa_i2c_address(dev->i2c, addr))
{
printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__);
bmpx8x_close(dev);
return NULL;
}
// check the chip id
uint8_t chipID = bmpx8x_get_chip_id(dev);
if (chipID != BMPX8X_DEFAULT_CHIPID)
{
printf("%s: invalid chip id: %02x. Expected %02x\n",
__FUNCTION__, chipID, BMPX8X_DEFAULT_CHIPID);
bmpx8x_close(dev);
return NULL;
}
// call devinit with a default ultrahigh resolution mode
if (bmpx8x_devinit(dev, BMPX8X_OSS_ULTRAHIGHRES))
{
printf("%s: bmpx8x_devinit() failed.\n", __FUNCTION__);
bmpx8x_close(dev);
return NULL;
}
return dev;
}
void bmpx8x_close(bmpx8x_context dev)
{
assert(dev != NULL);
if (dev->i2c)
mraa_i2c_stop(dev->i2c);
free(dev);
}
upm_result_t bmpx8x_devinit(const bmpx8x_context dev,
BMPX8X_OSS_T oss)
{
assert(dev != NULL);
// first read calibration data
if (_bmpx8x_read_calibration_data(dev))
{
printf("%s: _bmpx8x_read_calibration_data() failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// now set our oversampling mode
bmpx8x_set_oversampling(dev, oss);
return UPM_SUCCESS;
}
uint8_t bmpx8x_get_chip_id(const bmpx8x_context dev)
{
assert(dev != NULL);
return bmpx8x_read_reg(dev, BMPX8X_CHIP_ID);
}
upm_result_t bmpx8x_reset(const bmpx8x_context dev)
{
assert(dev != NULL);
if (bmpx8x_write_reg(dev, BMPX8X_RESET, BMPX8X_RESET_BYTE))
return UPM_ERROR_OPERATION_FAILED;
upm_delay(1);
return UPM_SUCCESS;
}
void bmpx8x_set_oversampling(const bmpx8x_context dev,
BMPX8X_OSS_T oss)
{
assert(dev != NULL);
dev->oversampling = oss;
}
upm_result_t bmpx8x_update(const bmpx8x_context dev)
{
assert(dev != NULL);
const int maxLen = 3; // maximum number of bytes we will read
uint8_t buffer[maxLen];
// first we need to read the temperature
// send the measurement command, and sleep the required time
// before reading it
if (bmpx8x_write_reg(dev, BMPX8X_CTRL_MEAS, BMPX8X_CMD_READ_TEMP))
{
printf("%s: bmpx8x_write_reg(tempcmd) failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
upm_delay_ms(5);
if (bmpx8x_read_regs(dev, BMPX8X_OUTDATA_MSB, buffer, maxLen) != maxLen)
{
printf("%s: bmpx8x_read_regs(temp) failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// we only need the first 2 bytes, uncompensated temperature
int32_t UT = (int32_t)( (buffer[0] << 8) | buffer[1] );
// now read in the uncompensated pressure - the delay time depends
// on the oversampling value
uint8_t reg = BMPX8X_CMD_READ_PRESSURE |
(dev->oversampling << _BMPX8X_CTRL_MEAS_OSS_SHIFT);
if (bmpx8x_write_reg(dev, BMPX8X_CTRL_MEAS, reg))
{
printf("%s: bmpx8x_write_reg(prescmd) failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
switch(dev->oversampling)
{
case BMPX8X_OSS_ULTRALOWPOWER:
upm_delay_ms(5);
break;
case BMPX8X_OSS_STANDARD:
upm_delay_ms(8);
break;
case BMPX8X_OSS_HIGHRES:
upm_delay_ms(14);
break;
case BMPX8X_OSS_ULTRAHIGHRES:
upm_delay_ms(26);
break;
}
if (bmpx8x_read_regs(dev, BMPX8X_OUTDATA_MSB, buffer, maxLen) != maxLen)
{
printf("%s: bmpx8x_read_regs(pres) failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// uncompensated pressure
int32_t UP = ( (buffer[0] << 16) | (buffer[1] << 8) | buffer[2] );
UP >>= (8 - dev->oversampling);
// now, compensate and store
int32_t B3, B5, B6, X1, X2, X3, p;
uint32_t B4, B7;
// temperature
B5 = _bmpx8x_computeB5(dev, UT);
dev->temperature = (float)( (B5 + 8) >> 4 );
dev->temperature /= 10.0;
// pressure
B6 = B5 - 4000;
X1 = ((int32_t)dev->b2 * ( (B6 * B6)>>12 )) >> 11;
X2 = ((int32_t)dev->ac2 * B6) >> 11;
X3 = X1 + X2;
B3 = ((((int32_t)dev->ac1*4 + X3) << dev->oversampling) + 2) / 4;
X1 = ((int32_t)dev->ac3 * B6) >> 13;
X2 = ((int32_t)dev->b1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = ((uint32_t)dev->ac4 * (uint32_t)(X3 + 32768)) >> 15;
B7 = ((uint32_t)UP - B3) * (uint32_t)( 50000UL >> dev->oversampling );
if (B7 < 0x80000000)
p = (B7 * 2) / B4;
else
p = (B7 / B4) * 2;
X1 = (p >> 8) * (p >> 8);
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * p) >> 16;
dev->pressure = p + ((X1 + X2 + (int32_t)3791)>>4);
return UPM_SUCCESS;
}
int bmpx8x_get_pressure(const bmpx8x_context dev)
{
assert(dev != NULL);
return dev->pressure;
}
float bmpx8x_get_temperature(const bmpx8x_context dev)
{
assert(dev != NULL);
return dev->temperature;
}
int bmpx8x_get_sealevel_pressure(const bmpx8x_context dev,
float altitude)
{
assert(dev != NULL);
return ((float)dev->pressure / powf(1.0-altitude/44330.0, 5.255));
}
float bmpx8x_get_altitude(const bmpx8x_context dev, int sealevel)
{
assert(dev != NULL);
// avoid potential divide-by-0, and set the default to 101325 Pa
if (sealevel <= 0)
sealevel = 101325;
return 44307.69 * (1.0 - powf((float)dev->pressure / (float)sealevel,
0.190284));
}
uint8_t bmpx8x_read_reg(const bmpx8x_context dev, uint8_t reg)
{
assert(dev != NULL);
return (uint8_t)mraa_i2c_read_byte_data(dev->i2c, reg);
}
int bmpx8x_read_regs(const bmpx8x_context dev, uint8_t reg,
uint8_t *buffer, int len)
{
assert(dev != NULL);
if (mraa_i2c_read_bytes_data(dev->i2c, reg, buffer, len) != len)
return -1;
return len;
}
upm_result_t bmpx8x_write_reg(const bmpx8x_context dev,
uint8_t reg, uint8_t val)
{
assert(dev != NULL);
if (mraa_i2c_write_byte_data(dev->i2c, val, reg))
{
printf("%s: mraa_i2c_write_byte_data() failed.\n",
__FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}