Skip to content
This repository was archived by the owner on Jul 23, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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