1686 lines
45 KiB
C++
1686 lines
45 KiB
C++
#include "LOLIN_HP303B.h"
|
|
|
|
|
|
|
|
const int32_t LOLIN_HP303B::scaling_facts[HP303B__NUM_OF_SCAL_FACTS]
|
|
= {524288, 1572864, 3670016, 7864320, 253952, 516096, 1040384, 2088960};
|
|
|
|
|
|
|
|
//////// Constructor, Destructor, begin, end ////////
|
|
|
|
|
|
/**
|
|
* Standard Constructor
|
|
*/
|
|
LOLIN_HP303B::LOLIN_HP303B(void)
|
|
{
|
|
//assume that initialization has failed before it has been done
|
|
m_initFail = 1U;
|
|
}
|
|
|
|
/**
|
|
* Standard Destructor
|
|
*/
|
|
LOLIN_HP303B::~LOLIN_HP303B(void)
|
|
{
|
|
end();
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Standard I2C begin function
|
|
*
|
|
* &bus: I2CBus which connects MC to HP303B
|
|
* slaveAddress: Address of the HP303B (0x77 or 0x76)
|
|
*/
|
|
uint8_t LOLIN_HP303B::begin(TwoWire &bus, uint8_t slaveAddress)
|
|
{
|
|
//this flag will show if the initialization was successful
|
|
m_initFail = 0U;
|
|
|
|
//Set I2C bus connection
|
|
m_SpiI2c = 1U;
|
|
m_i2cbus = &bus;
|
|
m_slaveAddress = slaveAddress;
|
|
|
|
// Init bus
|
|
m_i2cbus->begin();
|
|
|
|
delay(50); //startup time of HP303B
|
|
|
|
return init();
|
|
}
|
|
|
|
uint8_t LOLIN_HP303B::begin(uint8_t slaveAddress)
|
|
{
|
|
return begin(Wire,slaveAddress);
|
|
}
|
|
|
|
/**
|
|
* SPI begin function for HP303B with 4-wire SPI
|
|
*/
|
|
uint8_t LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect)
|
|
{
|
|
return begin(bus, chipSelect, 0U);
|
|
}
|
|
|
|
/**
|
|
* Standard SPI begin function
|
|
*
|
|
* &bus: SPI bus which connects MC to HP303B
|
|
* chipSelect: Number of the CS line for the HP303B
|
|
* threeWire: 1 if HP303B is connected with 3-wire SPI
|
|
* 0 if HP303B is connected with 4-wire SPI (standard)
|
|
*/
|
|
uint8_t LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire)
|
|
{
|
|
//this flag will show if the initialization was successful
|
|
m_initFail = 0U;
|
|
|
|
//Set SPI bus connection
|
|
m_SpiI2c = 0U;
|
|
m_spibus = &bus;
|
|
m_chipSelect = chipSelect;
|
|
|
|
// Init bus
|
|
m_spibus->begin();
|
|
m_spibus->setDataMode(SPI_MODE3);
|
|
|
|
pinMode(m_chipSelect, OUTPUT);
|
|
digitalWrite(m_chipSelect, HIGH);
|
|
|
|
delay(50); //startup time of HP303B
|
|
|
|
//switch to 3-wire mode if necessary
|
|
//do not use writeByteBitfield or check option to set SPI mode!
|
|
//Reading is not possible until SPI-mode is valid
|
|
if(threeWire)
|
|
{
|
|
m_threeWire = 1U;
|
|
if(writeByte(HP303B__REG_ADR_SPI3W, HP303B__REG_CONTENT_SPI3W))
|
|
{
|
|
m_initFail = 1U;
|
|
return 0U;
|
|
}
|
|
}
|
|
|
|
return init();
|
|
}
|
|
|
|
/**
|
|
* End function for HP303B
|
|
* Sets the sensor to idle mode
|
|
*/
|
|
void LOLIN_HP303B::end(void)
|
|
{
|
|
standby();
|
|
}
|
|
|
|
|
|
//////// Declaration of other public functions starts here ////////
|
|
|
|
|
|
/**
|
|
* returns the Product ID of the connected HP303B sensor
|
|
*/
|
|
uint8_t LOLIN_HP303B::getProductId(void)
|
|
{
|
|
return m_productID;
|
|
}
|
|
|
|
/**
|
|
* returns the Revision ID of the connected HP303B sensor
|
|
*/
|
|
uint8_t LOLIN_HP303B::getRevisionId(void)
|
|
{
|
|
return m_revisionID;
|
|
}
|
|
|
|
/**
|
|
* Sets the HP303B to standby mode
|
|
*
|
|
* returns: 0 on success
|
|
* -2 if object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::standby(void)
|
|
{
|
|
//set device to idling mode
|
|
int16_t ret = setOpMode(IDLE);
|
|
if(ret != HP303B__SUCCEEDED)
|
|
{
|
|
return ret;
|
|
}
|
|
//flush the FIFO
|
|
ret = writeByteBitfield(1U, HP303B__REG_INFO_FIFO_FL);
|
|
if(ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
//disable the FIFO
|
|
ret = writeByteBitfield(0U, HP303B__REG_INFO_FIFO_EN);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* performs one temperature measurement and writes result to the given address
|
|
*
|
|
* &result: reference to a 32-Bit signed Integer value where the result will be written
|
|
* It will not be written if result==NULL
|
|
* returns: 0 on success
|
|
* -4 if the HP303B is could not finish its measurement in time
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::measureTempOnce(float &result)
|
|
{
|
|
return measureTempOnce(result, m_slaveAddress, m_tempOsr);
|
|
}
|
|
|
|
/**
|
|
* performs one temperature measurement and writes result to the given address
|
|
*
|
|
* &result: reference to a 32-Bit signed Integer value where the result will be written
|
|
* It will not be written if result==NULL
|
|
* returns: 0 on success
|
|
* -4 if the HP303B is could not finish its measurement in time
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::measureTempOnce(float &result, uint8_t slaveAddress)
|
|
{
|
|
return measureTempOnce(result, slaveAddress, m_tempOsr);
|
|
}
|
|
|
|
/**
|
|
* performs one temperature measurement and writes result to the given address
|
|
* the desired precision can be set with oversamplingRate
|
|
*
|
|
* &result: reference to a 32-Bit signed Integer where the result will be written
|
|
* It will not be written if result==NULL
|
|
* oversamplingRate: a value from 0 to 7 that decides about the precision
|
|
* of the measurement
|
|
* If this value equals n, the HP303B will perform
|
|
* 2^n measurements and combine the results
|
|
* returns: 0 on success
|
|
* -4 if the HP303B is could not finish its measurement in time
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::measureTempOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate)
|
|
{
|
|
//Set I2C bus connection
|
|
m_slaveAddress = slaveAddress;
|
|
|
|
//Start measurement
|
|
int16_t ret = startMeasureTempOnce(oversamplingRate);
|
|
if(ret!=HP303B__SUCCEEDED)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
//wait until measurement is finished
|
|
delay(calcBusyTime(0U, m_tempOsr)/HP303B__BUSYTIME_SCALING);
|
|
delay(HP303B__BUSYTIME_FAILSAFE);
|
|
|
|
ret = getSingleResult(result);
|
|
if(ret!=HP303B__SUCCEEDED)
|
|
{
|
|
standby();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* starts a single temperature measurement
|
|
*
|
|
* returns: 0 on success
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::startMeasureTempOnce(void)
|
|
{
|
|
return startMeasureTempOnce(m_tempOsr);
|
|
}
|
|
|
|
/**
|
|
* starts a single temperature measurement
|
|
* The desired precision can be set with oversamplingRate
|
|
*
|
|
* oversamplingRate: a value from 0 to 7 that decides about the precision
|
|
* of the measurement
|
|
* If this value equals n, the HP303B will perform
|
|
* 2^n measurements and combine the results
|
|
* returns: 0 on success
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::startMeasureTempOnce(uint8_t oversamplingRate)
|
|
{
|
|
//abort if device is not in idling mode
|
|
if(m_opMode!=IDLE)
|
|
{
|
|
return HP303B__FAIL_TOOBUSY;
|
|
}
|
|
|
|
if(oversamplingRate!=m_tempOsr)
|
|
{
|
|
//configuration of oversampling rate
|
|
if(configTemp(0U, oversamplingRate) != HP303B__SUCCEEDED)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
//set device to temperature measuring mode
|
|
return setOpMode(0U, 1U, 0U);
|
|
}
|
|
|
|
/**
|
|
* performs one pressure measurement and writes result to the given address
|
|
*
|
|
* &result: reference to a 32-Bit signed Integer value where the result will be written
|
|
* It will not be written if result==NULL
|
|
* returns: 0 on success
|
|
* -4 if the HP303B is could not finish its measurement in time
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::measurePressureOnce(float &result)
|
|
{
|
|
return measurePressureOnce(result, m_slaveAddress, m_prsOsr);
|
|
}
|
|
|
|
/**
|
|
* performs one pressure measurement and writes result to the given address
|
|
*
|
|
* &result: reference to a 32-Bit signed Integer value where the result will be written
|
|
* It will not be written if result==NULL
|
|
* returns: 0 on success
|
|
* -4 if the HP303B is could not finish its measurement in time
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::measurePressureOnce(float &result, uint8_t slaveAddress)
|
|
{
|
|
return measurePressureOnce(result, slaveAddress, m_prsOsr);
|
|
}
|
|
|
|
/**
|
|
* performs one pressure measurement and writes result to the given address
|
|
* the desired precision can be set with oversamplingRate
|
|
*
|
|
* &result: reference to a 32-Bit signed Integer where the result will be written
|
|
* It will not be written if result==NULL
|
|
* oversamplingRate: a value from 0 to 7 that decides about the precision
|
|
* of the measurement
|
|
* If this value equals n, the HP303B will perform
|
|
* 2^n measurements and combine the results
|
|
* returns: 0 on success
|
|
* -4 if the HP303B is could not finish its measurement in time
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::measurePressureOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate)
|
|
{
|
|
//Set I2C bus connection
|
|
m_slaveAddress = slaveAddress;
|
|
|
|
//start the measurement
|
|
int16_t ret = startMeasurePressureOnce(oversamplingRate);
|
|
if(ret != HP303B__SUCCEEDED)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
//wait until measurement is finished
|
|
delay(calcBusyTime(0U, m_prsOsr)/HP303B__BUSYTIME_SCALING);
|
|
delay(HP303B__BUSYTIME_FAILSAFE);
|
|
|
|
ret = getSingleResult(result);
|
|
if(ret!=HP303B__SUCCEEDED)
|
|
{
|
|
standby();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* starts a single pressure measurement
|
|
*
|
|
* returns: 0 on success
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::startMeasurePressureOnce(void)
|
|
{
|
|
return startMeasurePressureOnce(m_prsOsr);
|
|
}
|
|
|
|
/**
|
|
* starts a single pressure measurement
|
|
* The desired precision can be set with oversamplingRate
|
|
*
|
|
* oversamplingRate: a value from 0 to 7 that decides about the precision
|
|
* of the measurement
|
|
* If this value equals n, the HP303B will perform
|
|
* 2^n measurements and combine the results
|
|
* returns: 0 on success
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::startMeasurePressureOnce(uint8_t oversamplingRate)
|
|
{
|
|
//abort if device is not in idling mode
|
|
if(m_opMode != IDLE)
|
|
{
|
|
return HP303B__FAIL_TOOBUSY;
|
|
}
|
|
//configuration of oversampling rate, lowest measure rate to avoid conflicts
|
|
if(oversamplingRate != m_prsOsr)
|
|
{
|
|
if(configPressure(0U, oversamplingRate))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
}
|
|
//set device to pressure measuring mode
|
|
return setOpMode(0U, 0U, 1U);
|
|
}
|
|
|
|
/**
|
|
* gets the result a single temperature or pressure measurement in °C or Pa
|
|
*
|
|
* &result: reference to a 32-Bit signed Integer value where the result will be written
|
|
* returns: 0 on success
|
|
* -4 if the HP303B is still busy
|
|
* -3 if the HP303B is not in command mode
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::getSingleResult(float &result)
|
|
{
|
|
//read finished bit for current opMode
|
|
int16_t rdy;
|
|
switch(m_opMode)
|
|
{
|
|
case CMD_TEMP: //temperature
|
|
rdy = readByteBitfield(HP303B__REG_INFO_TEMP_RDY);
|
|
break;
|
|
case CMD_PRS: //pressure
|
|
rdy = readByteBitfield(HP303B__REG_INFO_PRS_RDY);
|
|
break;
|
|
default: //HP303B not in command mode
|
|
return HP303B__FAIL_TOOBUSY;
|
|
}
|
|
|
|
//read new measurement result
|
|
switch(rdy)
|
|
{
|
|
case HP303B__FAIL_UNKNOWN: //could not read ready flag
|
|
return HP303B__FAIL_UNKNOWN;
|
|
case 0: //ready flag not set, measurement still in progress
|
|
return HP303B__FAIL_UNFINISHED;
|
|
case 1: //measurement ready, expected case
|
|
LOLIN_HP303B::Mode oldMode = m_opMode;
|
|
m_opMode = IDLE; //opcode was automatically reseted by HP303B
|
|
switch(oldMode)
|
|
{
|
|
case CMD_TEMP: //temperature
|
|
return getTemp(&result); //get and calculate the temperature value
|
|
case CMD_PRS: //pressure
|
|
return getPressure(&result); //get and calculate the pressure value
|
|
default:
|
|
return HP303B__FAIL_UNKNOWN; //should already be filtered above
|
|
}
|
|
}
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
|
|
/**
|
|
* starts a continuous temperature measurement
|
|
* The desired precision can be set with oversamplingRate
|
|
* The desired number of measurements per second can be set with measureRate
|
|
*
|
|
* measureRate: a value from 0 to 7 that decides about
|
|
* the number of measurements per second
|
|
* If this value equals n, the HP303B will perform
|
|
* 2^n measurements per second
|
|
* oversamplingRate: a value from 0 to 7 that decides about
|
|
* the precision of the measurements
|
|
* If this value equals m, the HP303B will perform
|
|
* 2^m internal measurements and combine the results
|
|
* to one more exact measurement
|
|
* returns: 0 on success
|
|
* -4 if measureRate or oversamplingRate is too high
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
* NOTE: If measure rate is n and oversampling rate is m,
|
|
* the HP303B performs 2^(n+m) internal measurements per second.
|
|
* The HP303B cannot operate with high precision and high speed
|
|
* at the same time.
|
|
* Consult the datasheet for more information.
|
|
*/
|
|
int16_t LOLIN_HP303B::startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate)
|
|
{
|
|
//abort if initialization failed
|
|
if(m_initFail)
|
|
{
|
|
return HP303B__FAIL_INIT_FAILED;
|
|
}
|
|
//abort if device is not in idling mode
|
|
if(m_opMode != IDLE)
|
|
{
|
|
return HP303B__FAIL_TOOBUSY;
|
|
}
|
|
//abort if speed and precision are too high
|
|
if(calcBusyTime(measureRate, oversamplingRate) >= HP303B__MAX_BUSYTIME)
|
|
{
|
|
return HP303B__FAIL_UNFINISHED;
|
|
}
|
|
//update precision and measuring rate
|
|
if(configTemp(measureRate, oversamplingRate))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//enable result FIFO
|
|
if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//Start measuring in background mode
|
|
if(setOpMode(1U, 1U, 0U))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
|
|
/**
|
|
* starts a continuous temperature measurement
|
|
* The desired precision can be set with oversamplingRate
|
|
* The desired number of measurements per second can be set with measureRate
|
|
*
|
|
* measureRate: a value from 0 to 7 that decides about
|
|
* the number of measurements per second
|
|
* If this value equals n, the HP303B will perform
|
|
* 2^n measurements per second
|
|
* oversamplingRate: a value from 0 to 7 that decides about the precision
|
|
* of the measurements
|
|
* If this value equals m, the HP303B will perform
|
|
* 2^m internal measurements
|
|
* and combine the results to one more exact measurement
|
|
* returns: 0 on success
|
|
* -4 if measureRate or oversamplingRate is too high
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
* NOTE: If measure rate is n and oversampling rate is m,
|
|
* the HP303B performs 2^(n+m) internal measurements per second.
|
|
* The HP303B cannot operate with high precision and high speed
|
|
* at the same time.
|
|
* Consult the datasheet for more information.
|
|
*/
|
|
int16_t LOLIN_HP303B::startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate)
|
|
{
|
|
//abort if initialization failed
|
|
if(m_initFail)
|
|
{
|
|
return HP303B__FAIL_INIT_FAILED;
|
|
}
|
|
//abort if device is not in idling mode
|
|
if(m_opMode != IDLE)
|
|
{
|
|
return HP303B__FAIL_TOOBUSY;
|
|
}
|
|
//abort if speed and precision are too high
|
|
if(calcBusyTime(measureRate, oversamplingRate) >= HP303B__MAX_BUSYTIME)
|
|
{
|
|
return HP303B__FAIL_UNFINISHED;
|
|
}
|
|
//update precision and measuring rate
|
|
if(configPressure(measureRate, oversamplingRate))
|
|
return HP303B__FAIL_UNKNOWN;
|
|
//enable result FIFO
|
|
if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//Start measuring in background mode
|
|
if(setOpMode(1U, 0U, 1U))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
/**
|
|
* starts a continuous temperature and pressure measurement
|
|
* The desired precision can be set with tempOsr and prsOsr
|
|
* The desired number of measurements per second can be set with tempMr and prsMr
|
|
*
|
|
* tempMr measure rate for temperature
|
|
* tempOsr oversampling rate for temperature
|
|
* prsMr measure rate for pressure
|
|
* prsOsr oversampling rate for pressure
|
|
* returns: 0 on success
|
|
* -4 if precision or speed is too high
|
|
* -3 if the HP303B is already busy
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
* NOTE: High precision and speed for both temperature and pressure
|
|
* can not be reached at the same time.
|
|
* Estimated time for temperature and pressure measurement
|
|
* is the sum of both values.
|
|
* This sum must not be more than 1 second.
|
|
* Consult the datasheet for more information.
|
|
*/
|
|
int16_t LOLIN_HP303B::startMeasureBothCont(uint8_t tempMr,
|
|
uint8_t tempOsr,
|
|
uint8_t prsMr,
|
|
uint8_t prsOsr)
|
|
{
|
|
//abort if initialization failed
|
|
if(m_initFail)
|
|
{
|
|
return HP303B__FAIL_INIT_FAILED;
|
|
}
|
|
//abort if device is not in idling mode
|
|
if(m_opMode!=IDLE)
|
|
{
|
|
return HP303B__FAIL_TOOBUSY;
|
|
}
|
|
//abort if speed and precision are too high
|
|
if(calcBusyTime(tempMr, tempOsr) + calcBusyTime(prsMr, prsOsr)>=HP303B__MAX_BUSYTIME)
|
|
{
|
|
return HP303B__FAIL_UNFINISHED;
|
|
}
|
|
//update precision and measuring rate
|
|
if(configTemp(tempMr, tempOsr))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//update precision and measuring rate
|
|
if(configPressure(prsMr, prsOsr))
|
|
return HP303B__FAIL_UNKNOWN;
|
|
//enable result FIFO
|
|
if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//Start measuring in background mode
|
|
if(setOpMode(1U, 1U, 1U))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
/**
|
|
* Gets the results from continuous measurements and writes them to given arrays
|
|
*
|
|
* *tempBuffer: The start address of the buffer where the temperature results
|
|
* are written
|
|
* If this is NULL, no temperature results will be written out
|
|
* &tempCount: This has to be a reference to a number which contains
|
|
* the size of the buffer for temperature results.
|
|
* When the function ends, it will contain
|
|
* the number of bytes written to the buffer
|
|
* *prsBuffer: The start address of the buffer where the pressure results
|
|
* are written
|
|
* If this is NULL, no pressure results will be written out
|
|
* &prsCount: This has to be a reference to a number which contains
|
|
* the size of the buffer for pressure results.
|
|
* When the function ends, it will contain
|
|
* the number of bytes written to the buffer
|
|
* returns: 0 on success
|
|
* -3 if HP303B is not in background mode
|
|
* -2 if the object initialization failed
|
|
* -1 on other fail
|
|
*/
|
|
int16_t LOLIN_HP303B::getContResults(float *tempBuffer,
|
|
uint8_t &tempCount,
|
|
float *prsBuffer,
|
|
uint8_t &prsCount)
|
|
{
|
|
if(m_initFail)
|
|
{
|
|
return HP303B__FAIL_INIT_FAILED;
|
|
}
|
|
//abort if device is not in background mode
|
|
if(!(m_opMode & INVAL_OP_CONT_NONE))
|
|
{
|
|
return HP303B__FAIL_TOOBUSY;
|
|
}
|
|
|
|
//prepare parameters for buffer length and count
|
|
uint8_t tempLen = tempCount;
|
|
uint8_t prsLen = prsCount;
|
|
tempCount = 0U;
|
|
prsCount = 0U;
|
|
|
|
//while FIFO is not empty
|
|
while(readByteBitfield(HP303B__REG_INFO_FIFO_EMPTY) == 0)
|
|
{
|
|
float result;
|
|
//read next result from FIFO
|
|
int16_t type = getFIFOvalue(&result);
|
|
switch(type)
|
|
{
|
|
case 0: //temperature
|
|
//calculate compensated pressure value
|
|
result = calcTemp(result);
|
|
//if buffer exists and is not full
|
|
//write result to buffer and increase temperature result counter
|
|
if(tempBuffer != NULL)
|
|
{
|
|
if(tempCount<tempLen)
|
|
{
|
|
tempBuffer[tempCount++] = result;
|
|
}
|
|
}
|
|
break;
|
|
case 1: //pressure
|
|
//calculate compensated pressure value
|
|
result = calcPressure(result);
|
|
//if buffer exists and is not full
|
|
//write result to buffer and increase pressure result counter
|
|
if(prsBuffer != NULL)
|
|
{
|
|
if(prsCount<prsLen)
|
|
{
|
|
prsBuffer[prsCount++] = result;
|
|
}
|
|
}
|
|
break;
|
|
case -1: //read failed
|
|
break; //continue while loop
|
|
//if connection failed permanently,
|
|
//while condition will become false
|
|
//if read failed only once, loop will try again
|
|
}
|
|
}
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
/**
|
|
* Sets the active state of the Interrupt pin
|
|
*
|
|
* polarity: If this is 0, the interrupt pin of the HP303B will be low-active
|
|
* If this is 1, the interrupt pin of the HP303B will be high-active
|
|
* returns: 0 on success,
|
|
* -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::setInterruptPolarity(uint8_t polarity)
|
|
{
|
|
//Interrupts are not supported with 4 Wire SPI
|
|
if(!m_SpiI2c & !m_threeWire)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
return writeByteBitfield(polarity, HP303B__REG_INFO_INT_HL);
|
|
}
|
|
|
|
/**
|
|
* Sets the sources that are able to cause interrupts
|
|
*
|
|
* fifoFull: if this is 1, an interrupt will be generated
|
|
* when the FIFO is full
|
|
* if this is 0, the FIFO will not generate any interrupts
|
|
* tempReady: if this is 1, an interrupt will be generated
|
|
* when a temperature measurement is finished
|
|
* if this is 0, no interrupt will be generated
|
|
* after finishing a temperature measurement
|
|
* prsReady: if this is 1, an interrupt will be generated
|
|
* when a pressure measurement is finished
|
|
* if this is 0, no interrupt will be generated
|
|
* after finishing a pressure measurement
|
|
* returns: 0 on success, -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::setInterruptSources(uint8_t fifoFull, uint8_t tempReady, uint8_t prsReady)
|
|
{
|
|
//Interrupts are not supported with 4 Wire SPI
|
|
if(!m_SpiI2c & !m_threeWire)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//mask parameters
|
|
fifoFull &= HP303B__REG_MASK_INT_EN_FIFO >> HP303B__REG_SHIFT_INT_EN_FIFO;
|
|
tempReady &= HP303B__REG_MASK_INT_EN_TEMP >> HP303B__REG_SHIFT_INT_EN_TEMP;
|
|
prsReady &= HP303B__REG_MASK_INT_EN_PRS >> HP303B__REG_SHIFT_INT_EN_PRS;
|
|
//read old value from register
|
|
int16_t regData = readByte(HP303B__REG_ADR_INT_EN_FIFO);
|
|
if(regData <0)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
uint8_t toWrite = (uint8_t)regData;
|
|
//update FIFO enable bit
|
|
toWrite &= ~HP303B__REG_MASK_INT_EN_FIFO; //clear bit
|
|
toWrite |= fifoFull << HP303B__REG_SHIFT_INT_EN_FIFO; //set new bit
|
|
//update TempReady enable bit
|
|
toWrite &= ~HP303B__REG_MASK_INT_EN_TEMP;
|
|
toWrite |= tempReady << HP303B__REG_SHIFT_INT_EN_TEMP;
|
|
//update PrsReady enable bit
|
|
toWrite &= ~HP303B__REG_MASK_INT_EN_PRS;
|
|
toWrite |= prsReady << HP303B__REG_SHIFT_INT_EN_PRS;
|
|
//write updated value to register
|
|
return writeByte(HP303B__REG_ADR_INT_EN_FIFO, toWrite);
|
|
}
|
|
|
|
/**
|
|
* Gets the interrupt status flag of the FIFO
|
|
*
|
|
* Returns: 1 if the FIFO is full and caused an interrupt
|
|
* 0 if the FIFO is not full or FIFO interrupt is disabled
|
|
* -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::getIntStatusFifoFull(void)
|
|
{
|
|
return readByteBitfield(HP303B__REG_INFO_INT_FLAG_FIFO);
|
|
}
|
|
|
|
/**
|
|
* Gets the interrupt status flag that indicates a finished temperature measurement
|
|
*
|
|
* Returns: 1 if a finished temperature measurement caused an interrupt
|
|
* 0 if there is no finished temperature measurement
|
|
* or interrupts are disabled
|
|
* -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::getIntStatusTempReady(void)
|
|
{
|
|
return readByteBitfield(HP303B__REG_INFO_INT_FLAG_TEMP);
|
|
}
|
|
|
|
/**
|
|
* Gets the interrupt status flag that indicates a finished pressure measurement
|
|
*
|
|
* Returns: 1 if a finished pressure measurement caused an interrupt
|
|
* 0 if there is no finished pressure measurement
|
|
* or interrupts are disabled
|
|
* -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::getIntStatusPrsReady(void)
|
|
{
|
|
return readByteBitfield(HP303B__REG_INFO_INT_FLAG_PRS);
|
|
}
|
|
|
|
/**
|
|
* Function to fix a hardware problem on some devices
|
|
* You have this problem if you measure a temperature which is too high (e.g. 60°C when temperature is around 20°C)
|
|
* Call correctTemp() directly after begin() to fix this issue
|
|
*/
|
|
int16_t LOLIN_HP303B::correctTemp(void)
|
|
{
|
|
if(m_initFail)
|
|
{
|
|
return HP303B__FAIL_INIT_FAILED;
|
|
}
|
|
writeByte(0x0E, 0xA5);
|
|
writeByte(0x0F, 0x96);
|
|
writeByte(0x62, 0x02);
|
|
writeByte(0x0E, 0x00);
|
|
writeByte(0x0F, 0x00);
|
|
|
|
//perform a first temperature measurement (again)
|
|
//the most recent temperature will be saved internally
|
|
//and used for compensation when calculating pressure
|
|
float trash;
|
|
measureTempOnce(trash);
|
|
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
|
|
|
|
//////// Declaration of private functions starts here ////////
|
|
|
|
|
|
/**
|
|
* Initializes the sensor.
|
|
* This function has to be called from begin()
|
|
* and requires a valid bus initialization.
|
|
*/
|
|
uint8_t LOLIN_HP303B::init(void)
|
|
{
|
|
int16_t prodId = readByteBitfield(HP303B__REG_INFO_PROD_ID);
|
|
if(prodId != HP303B__PROD_ID)
|
|
{
|
|
//Connected device is not a HP303B
|
|
m_initFail = 1U;
|
|
return 0U;
|
|
}
|
|
m_productID = prodId;
|
|
|
|
int16_t revId = readByteBitfield(HP303B__REG_INFO_REV_ID);
|
|
if(revId < 0)
|
|
{
|
|
m_initFail = 1U;
|
|
return 0U;
|
|
}
|
|
m_revisionID = revId;
|
|
|
|
//find out which temperature sensor is calibrated with coefficients...
|
|
int16_t sensor = readByteBitfield(HP303B__REG_INFO_TEMP_SENSORREC);
|
|
if(sensor < 0)
|
|
{
|
|
m_initFail = 1U;
|
|
return 0U;
|
|
}
|
|
|
|
//...and use this sensor for temperature measurement
|
|
m_tempSensor = sensor;
|
|
if(writeByteBitfield((uint8_t)sensor, HP303B__REG_INFO_TEMP_SENSOR) < 0)
|
|
{
|
|
m_initFail = 1U;
|
|
return 0U;
|
|
}
|
|
|
|
//read coefficients
|
|
if(readcoeffs() < 0)
|
|
{
|
|
m_initFail = 1U;
|
|
return 0U;
|
|
}
|
|
|
|
//set to standby for further configuration
|
|
standby();
|
|
|
|
//set measurement precision and rate to standard values;
|
|
configTemp(HP303B__TEMP_STD_MR, HP303B__TEMP_STD_OSR);
|
|
configPressure(HP303B__PRS_STD_MR, HP303B__PRS_STD_OSR);
|
|
|
|
//perform a first temperature measurement
|
|
//the most recent temperature will be saved internally
|
|
//and used for compensation when calculating pressure
|
|
float trash;
|
|
measureTempOnce(trash);
|
|
|
|
//make sure the HP303B is in standby after initialization
|
|
standby();
|
|
|
|
// Fix IC with a fuse bit problem, which lead to a wrong temperature
|
|
// Should not affect ICs without this problem
|
|
correctTemp();
|
|
|
|
return 1U;
|
|
}
|
|
|
|
|
|
/**
|
|
* reads the compensation coefficients from the HP303B
|
|
* this is called once from init(), which is called from begin()
|
|
*
|
|
* returns: 0 on success, -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::readcoeffs(void)
|
|
{
|
|
uint8_t buffer[HP303B__REG_LEN_COEF];
|
|
//read COEF registers to buffer
|
|
int16_t ret = readBlock(HP303B__REG_ADR_COEF,
|
|
HP303B__REG_LEN_COEF,
|
|
buffer);
|
|
//abort if less than REG_LEN_COEF bytes were read
|
|
if(ret < HP303B__REG_LEN_COEF)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
|
|
//compose coefficients from buffer content
|
|
m_c0Half = ((uint32_t)buffer[0] << 4)
|
|
| (((uint32_t)buffer[1] >> 4) & 0x0F);
|
|
//this construction recognizes non-32-bit negative numbers
|
|
//and converts them to 32-bit negative numbers with 2's complement
|
|
if(m_c0Half & ((uint32_t)1 << 11))
|
|
{
|
|
m_c0Half -= (uint32_t)1 << 12;
|
|
}
|
|
//c0 is only used as c0*0.5, so c0_half is calculated immediately
|
|
m_c0Half = m_c0Half / 2U;
|
|
|
|
//now do the same thing for all other coefficients
|
|
m_c1 = (((uint32_t)buffer[1] & 0x0F) << 8) | (uint32_t)buffer[2];
|
|
if(m_c1 & ((uint32_t)1 << 11))
|
|
{
|
|
m_c1 -= (uint32_t)1 << 12;
|
|
}
|
|
|
|
m_c00 = ((uint32_t)buffer[3] << 12)
|
|
| ((uint32_t)buffer[4] << 4)
|
|
| (((uint32_t)buffer[5] >> 4) & 0x0F);
|
|
if(m_c00 & ((uint32_t)1 << 19))
|
|
{
|
|
m_c00 -= (uint32_t)1 << 20;
|
|
}
|
|
|
|
m_c10 = (((uint32_t)buffer[5] & 0x0F) << 16)
|
|
| ((uint32_t)buffer[6] << 8)
|
|
| (uint32_t)buffer[7];
|
|
if(m_c10 & ((uint32_t)1<<19))
|
|
{
|
|
m_c10 -= (uint32_t)1 << 20;
|
|
}
|
|
|
|
m_c01 = ((uint32_t)buffer[8] << 8)
|
|
| (uint32_t)buffer[9];
|
|
if(m_c01 & ((uint32_t)1 << 15))
|
|
{
|
|
m_c01 -= (uint32_t)1 << 16;
|
|
}
|
|
|
|
m_c11 = ((uint32_t)buffer[10] << 8)
|
|
| (uint32_t)buffer[11];
|
|
if(m_c11 & ((uint32_t)1 << 15))
|
|
{
|
|
m_c11 -= (uint32_t)1 << 16;
|
|
}
|
|
|
|
m_c20 = ((uint32_t)buffer[12] << 8)
|
|
| (uint32_t)buffer[13];
|
|
if(m_c20 & ((uint32_t)1 << 15))
|
|
{
|
|
m_c20 -= (uint32_t)1 << 16;
|
|
}
|
|
|
|
m_c21 = ((uint32_t)buffer[14] << 8)
|
|
| (uint32_t)buffer[15];
|
|
if(m_c21 & ((uint32_t)1 << 15))
|
|
{
|
|
m_c21 -= (uint32_t)1 << 16;
|
|
}
|
|
|
|
m_c30 = ((uint32_t)buffer[16] << 8)
|
|
| (uint32_t)buffer[17];
|
|
if(m_c30 & ((uint32_t)1 << 15))
|
|
{
|
|
m_c30 -= (uint32_t)1 << 16;
|
|
}
|
|
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
/**
|
|
* Sets the Operation Mode of the HP303B
|
|
*
|
|
* background: determines the general behavior of the HP303B
|
|
* 0 enables command mode (only measure on commands)
|
|
* 1 enables background mode (continuous work in background)
|
|
* temperature: set 1 to measure temperature
|
|
* pressure: set 1 to measure pressure
|
|
* return: 0 on success, -1 on fail
|
|
*
|
|
* NOTE!
|
|
* You cannot set background to 1 without setting temperature and pressure
|
|
* You cannot set both temperature and pressure when background mode is disabled
|
|
*/
|
|
int16_t LOLIN_HP303B::setOpMode(uint8_t background, uint8_t temperature, uint8_t pressure)
|
|
{
|
|
uint8_t opMode = (background & HP303B__LSB) << 2U
|
|
| (temperature & HP303B__LSB) << 1U
|
|
| (pressure & HP303B__LSB);
|
|
return setOpMode(opMode);
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the Operation Mode of the HP303B
|
|
*
|
|
* opMode: the new OpMode that has to be set
|
|
* return: 0 on success, -1 on fail
|
|
*
|
|
* NOTE!
|
|
* You cannot set background to 1 without setting temperature and pressure
|
|
* You cannot set both temperature and pressure when background mode is disabled
|
|
*/
|
|
int16_t LOLIN_HP303B::setOpMode(uint8_t opMode)
|
|
{
|
|
//Filter irrelevant bits
|
|
opMode &= HP303B__REG_MASK_OPMODE >> HP303B__REG_SHIFT_OPMODE;
|
|
//Filter invalid OpModes
|
|
if(opMode == INVAL_OP_CMD_BOTH || opMode == INVAL_OP_CONT_NONE)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//Set OpMode
|
|
if(writeByte(HP303B__REG_ADR_OPMODE, opMode))
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
m_opMode = (LOLIN_HP303B::Mode)opMode;
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
/**
|
|
* Configures temperature measurement
|
|
*
|
|
* tempMr: the new measure rate for temperature
|
|
* This can be a value from 0U to 7U.
|
|
* Actual measure rate will be 2^tempMr,
|
|
* so this will be a value from 1 to 128.
|
|
* tempOsr: the new oversampling rate for temperature
|
|
* This can be a value from 0U to 7U.
|
|
* Actual measure rate will be 2^tempOsr,
|
|
* so this will be a value from 1 to 128.
|
|
* returns: 0 normally or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::configTemp(uint8_t tempMr, uint8_t tempOsr)
|
|
{
|
|
//mask parameters
|
|
tempMr &= HP303B__REG_MASK_TEMP_MR >> HP303B__REG_SHIFT_TEMP_MR;
|
|
tempOsr &= HP303B__REG_MASK_TEMP_OSR >> HP303B__REG_SHIFT_TEMP_OSR;
|
|
|
|
//set config register according to parameters
|
|
uint8_t toWrite = tempMr << HP303B__REG_SHIFT_TEMP_MR;
|
|
toWrite |= tempOsr << HP303B__REG_SHIFT_TEMP_OSR;
|
|
//using recommended temperature sensor
|
|
toWrite |= HP303B__REG_MASK_TEMP_SENSOR
|
|
& (m_tempSensor << HP303B__REG_SHIFT_TEMP_SENSOR);
|
|
int16_t ret = writeByte(HP303B__REG_ADR_TEMP_MR, toWrite);
|
|
//abort immediately on fail
|
|
if(ret != HP303B__SUCCEEDED)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
|
|
//set TEMP SHIFT ENABLE if oversampling rate higher than eight(2^3)
|
|
if(tempOsr > HP303B__OSR_SE)
|
|
{
|
|
ret=writeByteBitfield(1U, HP303B__REG_INFO_TEMP_SE);
|
|
}
|
|
else
|
|
{
|
|
ret=writeByteBitfield(0U, HP303B__REG_INFO_TEMP_SE);
|
|
}
|
|
|
|
if(ret == HP303B__SUCCEEDED)
|
|
{ //save new settings
|
|
m_tempMr = tempMr;
|
|
m_tempOsr = tempOsr;
|
|
}
|
|
else
|
|
{
|
|
//try to rollback on fail avoiding endless recursion
|
|
//this is to make sure that shift enable and oversampling rate
|
|
//are always consistent
|
|
if(tempMr != m_tempMr || tempOsr != m_tempOsr)
|
|
{
|
|
configTemp(m_tempMr, m_tempOsr);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Configures pressure measurement
|
|
*
|
|
* prsMr: the new measure rate for pressure
|
|
* This can be a value from 0U to 7U.
|
|
* Actual measure rate will be 2^prs_mr,
|
|
* so this will be a value from 1 to 128.
|
|
* prsOs: the new oversampling rate for temperature
|
|
* This can be a value from 0U to 7U.
|
|
* Actual measure rate will be 2^prsOsr,
|
|
* so this will be a value from 1 to 128.
|
|
* returns: 0 normally or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::configPressure(uint8_t prsMr, uint8_t prsOsr)
|
|
{
|
|
//mask parameters
|
|
prsMr &= HP303B__REG_MASK_PRS_MR >> HP303B__REG_SHIFT_PRS_MR;
|
|
prsOsr &= HP303B__REG_MASK_PRS_OSR >> HP303B__REG_SHIFT_PRS_OSR;
|
|
|
|
//set config register according to parameters
|
|
uint8_t toWrite = prsMr << HP303B__REG_SHIFT_PRS_MR;
|
|
toWrite |= prsOsr << HP303B__REG_SHIFT_PRS_OSR;
|
|
int16_t ret = writeByte(HP303B__REG_ADR_PRS_MR, toWrite);
|
|
//abort immediately on fail
|
|
if(ret != HP303B__SUCCEEDED)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
|
|
//set PM SHIFT ENABLE if oversampling rate higher than eight(2^3)
|
|
if(prsOsr > HP303B__OSR_SE)
|
|
{
|
|
ret = writeByteBitfield(1U, HP303B__REG_INFO_PRS_SE);
|
|
}
|
|
else
|
|
{
|
|
ret = writeByteBitfield(0U, HP303B__REG_INFO_PRS_SE);
|
|
}
|
|
|
|
if(ret == HP303B__SUCCEEDED)
|
|
{ //save new settings
|
|
m_prsMr = prsMr;
|
|
m_prsOsr = prsOsr;
|
|
}
|
|
else
|
|
{ //try to rollback on fail avoiding endless recursion
|
|
//this is to make sure that shift enable and oversampling rate
|
|
//are always consistent
|
|
if(prsMr != m_prsMr || prsOsr != m_prsOsr)
|
|
{
|
|
configPressure(m_prsMr, m_prsOsr);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* calculates the time that the HP303B needs for 2^mr measurements
|
|
* with an oversampling rate of 2^osr
|
|
*
|
|
* mr: Measure rate for temperature or pressure
|
|
* osr: Oversampling rate for temperature or pressure
|
|
* returns: time that the HP303B needs for this measurement
|
|
* a value of 10000 equals 1 second
|
|
* NOTE! The measurement time for temperature and pressure
|
|
* in sum must not be more than 1 second!
|
|
* Timing behavior of pressure and temperature sensors
|
|
* can be considered as equal.
|
|
*/
|
|
uint16_t LOLIN_HP303B::calcBusyTime(uint16_t mr, uint16_t osr)
|
|
{
|
|
//mask parameters first
|
|
mr &= HP303B__REG_MASK_TEMP_MR >> HP303B__REG_SHIFT_TEMP_MR;
|
|
osr &= HP303B__REG_MASK_TEMP_OSR >> HP303B__REG_SHIFT_TEMP_OSR;
|
|
//formula from datasheet (optimized)
|
|
return ((uint32_t)20U << mr) + ((uint32_t)16U << (osr + mr));
|
|
}
|
|
|
|
/**
|
|
* Gets the next temperature measurement result in degrees of Celsius
|
|
*
|
|
* result: address where the result will be written
|
|
* returns: 0 on success
|
|
* -1 on fail;
|
|
*/
|
|
int16_t LOLIN_HP303B::getTemp(float *result)
|
|
{
|
|
unsigned char buffer[3] = {0};
|
|
//read raw pressure data to buffer
|
|
|
|
int16_t i = readBlock(HP303B__REG_ADR_TEMP,
|
|
HP303B__REG_LEN_TEMP,
|
|
buffer);
|
|
if(i != HP303B__REG_LEN_TEMP)
|
|
{
|
|
//something went wrong
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
|
|
//compose raw temperature value from buffer
|
|
float temp = buffer[0] << 16
|
|
| buffer[1] << 8
|
|
| buffer[2];
|
|
//recognize non-32-bit negative numbers
|
|
//and convert them to 32-bit negative numbers using 2's complement
|
|
if(temp > 0x7FFFFF)
|
|
{
|
|
temp = temp - 0x1000000;
|
|
}
|
|
|
|
//return temperature
|
|
*result = calcTemp(temp);
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
/**
|
|
* Gets the next pressure measurement result in Pa
|
|
*
|
|
* result: address where the result will be written
|
|
* returns: 0 on success
|
|
* -1 on fail;
|
|
*/
|
|
int16_t LOLIN_HP303B::getPressure(float *result)
|
|
{
|
|
unsigned char buffer[3] = {0};
|
|
//read raw pressure data to buffer
|
|
int16_t i = readBlock(HP303B__REG_ADR_PRS,
|
|
HP303B__REG_LEN_PRS,
|
|
buffer);
|
|
if(i != HP303B__REG_LEN_PRS)
|
|
{
|
|
//something went wrong
|
|
//negative pressure is not allowed
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
|
|
//compose raw pressure value from buffer
|
|
float prs = buffer[0] << 16 | buffer[1] << 8 | buffer[2];
|
|
//recognize non-32-bit negative numbers
|
|
//and convert them to 32-bit negative numbers using 2's complement
|
|
if(prs > 0x7FFFFF)
|
|
{
|
|
prs = prs - 0x1000000;
|
|
}
|
|
|
|
*result = calcPressure(prs);
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
|
|
/**
|
|
* reads the next raw value from the HP303B FIFO
|
|
*
|
|
* value: address where the value will be written
|
|
* returns: -1 on fail
|
|
* 0 if result is a temperature raw value
|
|
* 1 if result is a pressure raw value
|
|
*/
|
|
int16_t LOLIN_HP303B::getFIFOvalue(float *value)
|
|
{
|
|
//abort on invalid argument
|
|
if(value == NULL)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
|
|
unsigned char buffer[HP303B__REG_LEN_PRS] = {0};
|
|
//always read from pressure raw value register
|
|
int16_t i = readBlock(HP303B__REG_ADR_PRS,
|
|
HP303B__REG_LEN_PRS,
|
|
buffer);
|
|
if(i != HP303B__REG_LEN_PRS)
|
|
{
|
|
//something went wrong
|
|
//return error code
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//compose raw pressure value from buffer
|
|
*value = buffer[0] << 16
|
|
| buffer[1] << 8
|
|
| buffer[2];
|
|
//recognize non-32-bit negative numbers
|
|
//and convert them to 32-bit negative numbers using 2's complement
|
|
if(*value > 0x7FFFFF)
|
|
{
|
|
*value = *value - 0x1000000;
|
|
}
|
|
|
|
//least significant bit shows measurement type
|
|
return buffer[2] & HP303B__LSB;
|
|
}
|
|
|
|
/**
|
|
* Calculates a scaled and compensated pressure value from raw data
|
|
* raw: raw temperature value read from HP303B
|
|
* returns: temperature value in °C
|
|
*/
|
|
float LOLIN_HP303B::calcTemp(float raw)
|
|
{
|
|
double temp = raw;
|
|
|
|
//scale temperature according to scaling table and oversampling
|
|
temp /= scaling_facts[m_tempOsr];
|
|
|
|
//update last measured temperature
|
|
//it will be used for pressure compensation
|
|
m_lastTempScal = temp;
|
|
|
|
//Calculate compensated temperature
|
|
temp = m_c0Half + m_c1 * temp;
|
|
|
|
//return temperature
|
|
return (float)temp;
|
|
}
|
|
|
|
/**
|
|
* Calculates a scaled and compensated pressure value from raw data
|
|
* raw: raw pressure value read from HP303B
|
|
* returns: pressure value in Pa
|
|
*/
|
|
float LOLIN_HP303B::calcPressure(float raw)
|
|
{
|
|
double prs = raw;
|
|
|
|
//scale pressure according to scaling table and oversampling
|
|
prs /= scaling_facts[m_prsOsr];
|
|
|
|
//Calculate compensated pressure
|
|
prs = m_c00
|
|
+ prs * (m_c10 + prs * (m_c20 + prs * m_c30))
|
|
+ m_lastTempScal * (m_c01 + prs * (m_c11 + prs * m_c21));
|
|
|
|
//return pressure
|
|
return (float)prs;
|
|
}
|
|
|
|
/**
|
|
* reads a byte from HP303B
|
|
*
|
|
* regAdress: Address that has to be read
|
|
* returns: register content or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::readByte(uint8_t regAddress)
|
|
{
|
|
//delegate to specialized function if HP303B is connected via SPI
|
|
if(m_SpiI2c==0)
|
|
{
|
|
return readByteSPI(regAddress);
|
|
}
|
|
|
|
m_i2cbus->beginTransmission(m_slaveAddress);
|
|
m_i2cbus->write(regAddress);
|
|
m_i2cbus->endTransmission(0);
|
|
//request 1 byte from slave
|
|
if(m_i2cbus->requestFrom(m_slaveAddress, 1U, 1U) > 0)
|
|
{
|
|
return m_i2cbus->read(); //return this byte on success
|
|
}
|
|
else
|
|
{
|
|
return HP303B__FAIL_UNKNOWN; //if 0 bytes were read successfully
|
|
}
|
|
}
|
|
|
|
/**
|
|
* reads a byte from HP303B via SPI
|
|
* this function is automatically called by readByte
|
|
* if HP303B is connected via SPI
|
|
*
|
|
* regAdress: Address that has to be read
|
|
* returns: register content or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::readByteSPI(uint8_t regAddress)
|
|
{
|
|
//this function is only made for communication via SPI
|
|
if(m_SpiI2c != 0)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//mask regAddress
|
|
regAddress &= ~HP303B__SPI_RW_MASK;
|
|
//reserve and initialize bus
|
|
m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
|
|
MSBFIRST,
|
|
SPI_MODE3));
|
|
//enable ChipSelect for HP303B
|
|
digitalWrite(m_chipSelect, LOW);
|
|
//send address with read command to HP303B
|
|
m_spibus->transfer(regAddress | HP303B__SPI_READ_CMD);
|
|
//receive register content from HP303B
|
|
uint8_t ret = m_spibus->transfer(0xFF); //send a dummy byte while receiving
|
|
//disable ChipSelect for HP303B
|
|
digitalWrite(m_chipSelect, HIGH);
|
|
//close current SPI transaction
|
|
m_spibus->endTransaction();
|
|
//return received data
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* reads a block from HP303B
|
|
*
|
|
* regAdress: Address that has to be read
|
|
* length: Length of data block
|
|
* buffer: Buffer where data will be stored
|
|
* returns: number of bytes that have been read successfully
|
|
* NOTE! This is not always equal to length
|
|
* due to rx-Buffer overflow etc.
|
|
*/
|
|
int16_t LOLIN_HP303B::readBlock(uint8_t regAddress, uint8_t length, uint8_t *buffer)
|
|
{
|
|
//delegate to specialized function if HP303B is connected via SPI
|
|
if(m_SpiI2c == 0)
|
|
{
|
|
return readBlockSPI(regAddress, length, buffer);
|
|
}
|
|
//do not read if there is no buffer
|
|
if(buffer == NULL)
|
|
{
|
|
return 0; //0 bytes read successfully
|
|
}
|
|
|
|
m_i2cbus->beginTransmission(m_slaveAddress);
|
|
m_i2cbus->write(regAddress);
|
|
m_i2cbus->endTransmission(0);
|
|
//request length bytes from slave
|
|
int16_t ret = m_i2cbus->requestFrom(m_slaveAddress, length, 1U);
|
|
//read all received bytes to buffer
|
|
for(int16_t count = 0; count < ret; count++)
|
|
{
|
|
buffer[count] = m_i2cbus->read();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* reads a block from HP303B via SPI
|
|
*
|
|
* regAdress: Address that has to be read
|
|
* length: Length of data block
|
|
* readbuffer: Buffer where data will be stored
|
|
* returns: number of bytes that have been read successfully
|
|
* NOTE! This is not always equal to length
|
|
* due to rx-Buffer overflow etc.
|
|
*/
|
|
int16_t LOLIN_HP303B::readBlockSPI(uint8_t regAddress, uint8_t length, uint8_t *buffer)
|
|
{
|
|
//this function is only made for communication via SPI
|
|
if(m_SpiI2c != 0)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//do not read if there is no buffer
|
|
if(buffer == NULL)
|
|
{
|
|
return 0; //0 bytes were read successfully
|
|
}
|
|
//mask regAddress
|
|
regAddress &= ~HP303B__SPI_RW_MASK;
|
|
//reserve and initialize bus
|
|
m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
|
|
MSBFIRST,
|
|
SPI_MODE3));
|
|
//enable ChipSelect for HP303B
|
|
digitalWrite(m_chipSelect, LOW);
|
|
//send address with read command to HP303B
|
|
m_spibus->transfer(regAddress | HP303B__SPI_READ_CMD);
|
|
|
|
//receive register contents from HP303B
|
|
for(uint8_t count = 0; count < length; count++)
|
|
{
|
|
buffer[count] = m_spibus->transfer(0xFF);//send a dummy byte while receiving
|
|
}
|
|
|
|
//disable ChipSelect for HP303B
|
|
digitalWrite(m_chipSelect, HIGH);
|
|
//close current SPI transaction
|
|
m_spibus->endTransaction();
|
|
//return received data
|
|
return length;
|
|
}
|
|
|
|
/**
|
|
* writes a given byte to a given register of HP303B without checking
|
|
*
|
|
* regAdress: Address of the register that has to be updated
|
|
* data: Byte that will be written to the register
|
|
* return: 0 if byte was written successfully
|
|
* or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::writeByte(uint8_t regAddress, uint8_t data)
|
|
{
|
|
return writeByte(regAddress, data, 0U);
|
|
}
|
|
|
|
/**
|
|
* writes a given byte to a given register of HP303B
|
|
*
|
|
* regAdress: Address of the register that has to be updated
|
|
* data: Byte that will be written to the register
|
|
* check: If this is true, register content will be read after writing
|
|
* to check if update was successful
|
|
* return: 0 if byte was written successfully
|
|
* or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::writeByte(uint8_t regAddress, uint8_t data, uint8_t check)
|
|
{
|
|
//delegate to specialized function if HP303B is connected via SPI
|
|
if(m_SpiI2c==0)
|
|
{
|
|
return writeByteSpi(regAddress, data, check);
|
|
}
|
|
m_i2cbus->beginTransmission(m_slaveAddress);
|
|
m_i2cbus->write(regAddress); //Write Register number to buffer
|
|
m_i2cbus->write(data); //Write data to buffer
|
|
if(m_i2cbus->endTransmission() != 0) //Send buffer content to slave
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
if(check == 0) return 0; //no checking
|
|
if(readByte(regAddress) == data) //check if desired by calling function
|
|
{
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
else
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* writes a given byte to a given register of HP303B via SPI
|
|
*
|
|
* regAdress: Address of the register that has to be updated
|
|
* data: Byte that will be written to the register
|
|
* check: If this is true, register content will be read after writing
|
|
* to check if update was successful
|
|
* return: 0 if byte was written successfully
|
|
* or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::writeByteSpi(uint8_t regAddress, uint8_t data, uint8_t check)
|
|
{
|
|
//this function is only made for communication via SPI
|
|
if(m_SpiI2c != 0)
|
|
{
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
//mask regAddress
|
|
regAddress &= ~HP303B__SPI_RW_MASK;
|
|
//reserve and initialize bus
|
|
m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
|
|
MSBFIRST,
|
|
SPI_MODE3));
|
|
//enable ChipSelect for HP303B
|
|
digitalWrite(m_chipSelect, LOW);
|
|
//send address with read command to HP303B
|
|
m_spibus->transfer(regAddress | HP303B__SPI_WRITE_CMD);
|
|
|
|
//write register content from HP303B
|
|
m_spibus->transfer(data);
|
|
|
|
//disable ChipSelect for HP303B
|
|
digitalWrite(m_chipSelect, HIGH);
|
|
//close current SPI transaction
|
|
m_spibus->endTransaction();
|
|
|
|
//check if necessary
|
|
if(check == 0)
|
|
{
|
|
//no checking necessary
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
//checking necessary
|
|
if(readByte(regAddress) == data)
|
|
{
|
|
//check passed
|
|
return HP303B__SUCCEEDED;
|
|
}
|
|
else
|
|
{
|
|
//check failed
|
|
return HP303B__FAIL_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* updates some given bits of a given register of HP303B without checking
|
|
*
|
|
* regAdress: Address of the register that has to be updated
|
|
* data: BitValues that will be written to the register
|
|
* shift: Amount of bits the data byte is shifted (left) before being masked
|
|
* mask: Masks the bits of the register that have to be updated
|
|
* Bits with value 1 are updated
|
|
* Bits with value 0 are not changed
|
|
* return: 0 if byte was written successfully
|
|
* or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::writeByteBitfield(uint8_t data,
|
|
uint8_t regAddress,
|
|
uint8_t mask,
|
|
uint8_t shift)
|
|
{
|
|
return writeByteBitfield(data, regAddress, mask, shift, 0U);
|
|
}
|
|
|
|
/**
|
|
* updates some given bits of a given register of HP303B
|
|
*
|
|
* regAdress: Address of the register that has to be updated
|
|
* data: BitValues that will be written to the register
|
|
* shift: Amount of bits the data byte is shifted (left) before being masked
|
|
* mask: Masks the bits of the register that have to be updated
|
|
* Bits with value 1 are updated
|
|
* Bits with value 0 are not changed
|
|
* check: enables/disables check after writing
|
|
* 0 disables check
|
|
* if check fails, -1 will be returned
|
|
* return: 0 if byte was written successfully
|
|
* or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::writeByteBitfield(uint8_t data,
|
|
uint8_t regAddress,
|
|
uint8_t mask,
|
|
uint8_t shift,
|
|
uint8_t check)
|
|
{
|
|
int16_t old = readByte(regAddress);
|
|
if(old < 0)
|
|
{
|
|
//fail while reading
|
|
return old;
|
|
}
|
|
return writeByte(regAddress, ((uint8_t)old & ~mask)|((data << shift) & mask), check);
|
|
}
|
|
|
|
/**
|
|
* reads some given bits of a given register of HP303B
|
|
*
|
|
* regAdress: Address of the register that has to be updated
|
|
* mask: Masks the bits of the register that have to be updated
|
|
* Bits masked with value 1 are read
|
|
* Bits masked with value 0 are set 0
|
|
* shift: Amount of bits the data byte is shifted (right) after being masked
|
|
* return: read and processed bits
|
|
* or -1 on fail
|
|
*/
|
|
int16_t LOLIN_HP303B::readByteBitfield(uint8_t regAddress, uint8_t mask, uint8_t shift)
|
|
{
|
|
int16_t ret = readByte(regAddress);
|
|
if(ret<0)
|
|
{
|
|
return ret;
|
|
}
|
|
return (((uint8_t)ret) & mask) >> shift;
|
|
}
|