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>
361 lines
9.4 KiB
C
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;
|
|
}
|