Skip to content
This repository has been archived by the owner on Jul 23, 2020. It is now read-only.

Master hold #3

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
27 changes: 7 additions & 20 deletions flowi2chelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,19 @@
bool I2CHelper::readFromI2C(uint8_t i2cAddress, const uint8_t* i2cCommand, uint8_t commandLength, uint8_t* data, uint8_t dataLength)
{
Wire.beginTransmission(i2cAddress);
for (int i = 0; i < commandLength; ++i) {
if (Wire.write(i2cCommand[i]) != 1) {
return false;
}
}
if (Wire.endTransmission(false) != 0) {
Serial.println("NACK");
Wire.write(i2cCommand, commandLength);
if (Wire.endTransmission(0 == dataLength) != 0) {
return false;
}

Wire.requestFrom(i2cAddress, dataLength);
if (dataLength != 0) {
if (dataLength > Wire.requestFrom(i2cAddress, dataLength))
return false;

// there should be no reason for this to not be ready, since we're using clock stretching mode,
// but just in case we'll try a few times
uint8_t tries = 1;
while (Wire.available() < dataLength) {
delay(1);
if (tries++ >= MAX_READ_TRIES) {
return false;
for (int i = 0; i < dataLength; ++i) {
data[i] = Wire.read();
}
}

for (int i = 0; i < dataLength; ++i) {
data[i] = Wire.read();
}
return true;
}


118 changes: 99 additions & 19 deletions sensirionflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,55 +42,135 @@ SensirionFlow::SensirionFlow(uint8_t i2cAddress)
{
}

void SensirionFlow::init()
bool SensirionFlow::init()
{
const uint8_t CMD_LENGTH = 1;
const uint8_t CMD_READ_USER_REGISTER[CMD_LENGTH] = { 0xE3 };
const uint8_t DATA_LENGTH = 6; // 2 data, 1 crc
uint8_t data[DATA_LENGTH];

// - read user register
if (!I2CHelper::readFromI2C(mI2cAddress, CMD_READ_USER_REGISTER, CMD_LENGTH, data, 3)) {
Serial.print("Failed to read from I2C 1\n");
return;
register_value_t baseAddress;
if (!readRegister(user_reg, &baseAddress)) {
return false;
}

int16_t baseAddress = (data[0] << 8) + data[1];

baseAddress &= 0x70; // EEPROM base address is bits <6..4>
baseAddress >>= 4;
baseAddress *= 0x300;

// - read scale factor
int16_t scaleFactorAddress = (baseAddress + 0x02B6);
uint16_t scaleFactorAddress = (baseAddress + 0x02B6);
scaleFactorAddress <<= 4; // address is a left aligned 12-bit value

uint8_t cmdReadRegister[] = { 0xFA, (scaleFactorAddress >> 8), scaleFactorAddress & 0x00FF };
uint8_t cmdReadRegister[] = { 0xFA, (uint8_t)(scaleFactorAddress >> 8), (uint8_t)(scaleFactorAddress & 0x00FF) };
if (!I2CHelper::readFromI2C(mI2cAddress, cmdReadRegister, 3, data, DATA_LENGTH)) {
Serial.print("Failed to read from I2C 2\n");
return;
return false;
}
mScaleFactor = (data[0] << 8) + data[1]; // data[2] = crc

uint16_t measurementUnit = (data[3] << 8) + data[4]; // data[2] = crc
mDimension = measurementUnit & 0xF;
mTimeBase = (measurementUnit >> 4) & 0xF;
mVolumePressureUnit = (measurementUnit >> 8) & 0x1F;
return true;
}

void SensirionFlow::reset()
{
const uint8_t CMD_LENGTH = 1;
const uint8_t CMD_RESET[CMD_LENGTH] = { 0xFE };
I2CHelper::readFromI2C(mI2cAddress, CMD_RESET, CMD_LENGTH, NULL, 0);
}

float SensirionFlow::readSample()
{
float measurement;
if (!triggerMeasurement(true) || !readMeasurement(&measurement))
{
measurement = 0;
}
return measurement;
}

bool SensirionFlow::triggerMeasurement(bool masterHold)
{
const uint8_t cmdLength = 1;
static uint8_t command[cmdLength] = { 0xF1 };

// new
Wire.beginTransmission(mI2cAddress);
Wire.write(command, cmdLength);
if (Wire.endTransmission(false) != 0) {
return false;
}
// if not master hold, we need to perform a read to trigger the measurement
if (!masterHold) {
Wire.requestFrom(mI2cAddress, (uint8_t)0);
}

return true;
}

bool SensirionFlow::readMeasurement(float *measurement)
{
const uint8_t dataLength = 2;
uint8_t command[cmdLength];
uint8_t data[dataLength];

command[0] = 0xF1;
if (!I2CHelper::readFromI2C(mI2cAddress, command, 1, data, dataLength)) {
Serial.print("Failed to read from I2C 4\n");
return 0;

if (dataLength > Wire.requestFrom(mI2cAddress, dataLength))
return false;

for (int i = 0; i < dataLength; ++i) {
data[i] = Wire.read();
}

float measurementValue = ((data[0] << 8) + data[1]);
return (measurementValue / mScaleFactor);
*measurement = measurementValue / mScaleFactor;
return true;
}

bool SensirionFlow::readRegister(register_id_t reg, register_value_t *buffer)
{
const static uint8_t commands[] = { 0xE3, 0xE5, 0xE7, 0xE9 };
const uint8_t dataLength = 2;

if (reg >= 4) {
return false;
}

uint8_t data[dataLength];

if (!I2CHelper::readFromI2C(mI2cAddress, &commands[reg], 1, data, dataLength)) {
return false;
}

*buffer = (data[0] << 8) | data[1];
return true;
}

bool SensirionFlow::writeRegister(register_id_t reg, register_value_t data)
{
const static uint8_t commands[] = { 0xE2, 0xE4 };
const uint8_t commandLength = 3;

if (reg >= 2) {
return false;
}

uint8_t command[commandLength];
command[0] = commands[reg];
command[1] = data >> 8;
command[2] = data & 0x00FF;

return I2CHelper::readFromI2C(mI2cAddress, &command[0], commandLength, NULL, 0);
}

bool SensirionFlow::modifyRegister(register_id_t reg, register_value_t data, register_value_t mask)
{
register_value_t value;
if (!readRegister(reg, &value)) {
return false;
}

value &= ~mask; // zero out bits to modify
value |= data & mask; // set 1-bits to modify
return writeRegister(reg, value);
}
35 changes: 32 additions & 3 deletions sensirionflow.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,43 @@ class SensirionFlow
{
public:
SensirionFlow(uint8_t i2cAddress);
void init();

bool init();
void reset();

/**
* Original function kept for compatibility.
*/
float readSample();

/**
* Trigger measurement, return true if successful.
*/
bool triggerMeasurement(bool masterHold = true);
/**
* Master hold: Trigger a measurement with triggerMeasurement, then use readMeasurement to read it (blocking).
* No master hold: Trigger a measurement with triggerMeasurement, then poll with readMeasurement until returning true.
* Please note that you may need to modify the relevant sensor register first to disable master hold.
*/
bool readMeasurement(float *measurement);

uint8_t getDimension() const { return mDimension; };
uint8_t getTimeBase() const { return mTimeBase; };
uint8_t getVolumePressureUnit() const { return mVolumePressureUnit; };


typedef enum
{
user_reg = 0,
adv_user_reg,
readonly_1,
readonly_2
} register_id_t;

typedef uint16_t register_value_t;

bool readRegister(register_id_t reg, register_value_t *buffer);
bool writeRegister(register_id_t reg, register_value_t data);
bool modifyRegister(register_id_t reg, register_value_t data, register_value_t mask);

private:
uint8_t mI2cAddress;
int16_t mScaleFactor;
Expand Down