software:firmware
MakAir Firmware
mass_flow_meter.cpp File Reference

Mass Flow meter management. More...

#include "../includes/mass_flow_meter.h"
#include <Arduino.h>
#include <HardwareSerial.h>
#include <IWatchdog.h>
#include <OneButton.h>
#include <Wire.h>
#include <math.h>
#include "../includes/buzzer_control.h"
#include "../includes/config.h"
#include "../includes/parameters.h"
#include "../includes/screen.h"

Go to the source code of this file.

Macros

#define MASS_FLOW_TIMER_FREQ   10000
 
#define MASS_FLOW_PERIOD   100
 
#define MFM_MEAN_SAMPLES   40
 
#define MFM_WAIT_RESET_PERIODS   13
 
#define MFM_WAIT_WARMUP_PERIODS   8
 
#define MFM_WAIT_SOFTRESET_PERIODS   3
 
#define MFM_WAIT_READSERIALR1_PERIODS   1
 

Functions

void MFM_Timer_Callback (HardwareTimer *)
 
bool MFM_init (void)
 Initialize Mass Flow Meter. More...
 
int32_t MFM_read_airflow (void)
 Read instant air flow. More...
 
int32_t MFM_expi_read_airflow (void)
 Read instant air flow. More...
 
void MFM_reset (void)
 Reset the volume counter. More...
 
void MFM_expi_reset (void)
 
uint32_t MFM_read_serial_number (void)
 Get the serial number of the inspiratory flow meter. More...
 
uint32_t MFM_expi_read_serial_number (void)
 return the serial number of the expiratory flow meter More...
 
int8_t MFM_calibrateZero (void)
 If the massflow meter needs to be calibrated, this function will be usefull. More...
 
int32_t MFM_getOffset (void)
 Get massflow meter offset. More...
 
int32_t MFM_read_milliliters (bool reset_after_read)
 Get the number of milliliters since last reset. More...
 
int32_t MFM_expi_read_milliliters (bool reset_after_read)
 Get the number of milliliters since last reset for expiratory sensor. More...
 

Variables

volatile uint16_t MFM_force_release_I2C = MFM_FORCE_RELEASE_I2C_FALSE
 
uint32_t mfmHoneywellHafSerialNumber = 0
 
uint32_t mfmSfm3300SerialNumberExpi = 0
 
uint32_t mfmSfm3019SerialNumber = 0
 
HardwareTimer * massFlowTimer = NULL
 
volatile bool mfmFaultCondition = false
 
volatile int32_t mfmInspiratoryCalibrationOffset = 0
 
volatile int32_t mfmInspiratoryAirVolumeSumMilliliters = 0
 
volatile int32_t mfmInspiratorySensorDetected = 0
 
volatile int32_t mfmInspiratoryInstantAirFlow = 0
 
volatile int32_t mfmExpiratoryCalibrationOffset = 0
 
volatile int32_t mfmExpiratoryAirVolumeSumMilliliters = 0
 
volatile int32_t mfmExpiratorySensorDetected = 0
 
volatile int32_t mfmExpiratoryInstantAirFlow = 0
 
volatile bool mfmInspiratoryInstantAirFlowRecord = false
 
volatile int32_t mfmInspiratoryInstantAirFlowLastValues [MFM_MEAN_SAMPLES]
 
volatile int16_t mfmInspiratoryInstantAirFlowLastValuesIndex = 0
 
int32_t mfmInspiratoryLastValue = 0
 
volatile int32_t mfmInspiratoryLastValueFixedFloat = 0
 
volatile int32_t mfmExpiratoryLastValueFixedFloat = 0
 
int32_t mfmResetStateMachine = MFM_WAIT_RESET_PERIODS
 
uint16_t mfmExpiSFM3300FailCounter = 0
 
union {
   uint16_t   i
 
   int16_t   si
 
   unsigned char   c [2]
 
mfmLastData
 

Detailed Description

Mass Flow meter management.

Author
Makers For Life

SFM3300-D sensirion mass flow meter is connected on I2C bus. To perform the integral of the mass flow, I2C polling must be done in a high priority timer.

Definition in file mass_flow_meter.cpp.

Macro Definition Documentation

◆ MASS_FLOW_PERIOD

#define MASS_FLOW_PERIOD   100

Definition at line 42 of file mass_flow_meter.cpp.

◆ MASS_FLOW_TIMER_FREQ

#define MASS_FLOW_TIMER_FREQ   10000

Definition at line 39 of file mass_flow_meter.cpp.

◆ MFM_MEAN_SAMPLES

#define MFM_MEAN_SAMPLES   40

Definition at line 66 of file mass_flow_meter.cpp.

◆ MFM_WAIT_READSERIALR1_PERIODS

#define MFM_WAIT_READSERIALR1_PERIODS   1

Definition at line 83 of file mass_flow_meter.cpp.

◆ MFM_WAIT_RESET_PERIODS

#define MFM_WAIT_RESET_PERIODS   13

Definition at line 80 of file mass_flow_meter.cpp.

◆ MFM_WAIT_SOFTRESET_PERIODS

#define MFM_WAIT_SOFTRESET_PERIODS   3

Definition at line 82 of file mass_flow_meter.cpp.

◆ MFM_WAIT_WARMUP_PERIODS

#define MFM_WAIT_WARMUP_PERIODS   8

Definition at line 81 of file mass_flow_meter.cpp.

Function Documentation

◆ MFM_calibrateZero()

int8_t MFM_calibrateZero ( void  )

If the massflow meter needs to be calibrated, this function will be usefull.

Calibrate the zero of the sensor.

Definition at line 604 of file mass_flow_meter.cpp.

604  {
605  int8_t ret = MFM_CALIBRATION_OK;
606  // activate table fill with last valid value
609  // wait for the table to fill in
610  delay(2 + (MFM_MEAN_SAMPLES * (MASS_FLOW_PERIOD / 10)));
611  // Check that table is full (record must be false)
612  // If it is not, there is a sensor problem
613  // In case of problem, do not update mfmInspiratoryCalibrationOffset
615  int32_t zeroFlow = 0;
616  for (int16_t i = 0; i < MFM_MEAN_SAMPLES; i++) {
618  }
619  zeroFlow /= MFM_MEAN_SAMPLES;
620  // check that value is credible: [-10 10] SLPM
621  if ((zeroFlow < 10000) && (zeroFlow > -10000)) {
623  } else {
625  }
626  } else {
628  }
629  return ret;
630 }
volatile int32_t mfmInspiratoryInstantAirFlowLastValues[MFM_MEAN_SAMPLES]
volatile int32_t mfmInspiratoryCalibrationOffset
uint16_t i
#define MASS_FLOW_PERIOD
volatile int16_t mfmInspiratoryInstantAirFlowLastValuesIndex
#define MFM_MEAN_SAMPLES
volatile bool mfmInspiratoryInstantAirFlowRecord
#define MFM_CALIBRATION_IMPOSSIBLE
#define MFM_CALIBRATION_OUT_OF_RANGE
#define MFM_CALIBRATION_OK

◆ MFM_expi_read_airflow()

int32_t MFM_expi_read_airflow ( void  )

Read instant air flow.

Definition at line 566 of file mass_flow_meter.cpp.

566  {
567  int32_t r;
568  if (mfmFaultCondition) {
570  } else {
572  }
573  return r;
574 }
volatile int32_t mfmExpiratoryInstantAirFlow
volatile int32_t mfmExpiratoryCalibrationOffset
volatile bool mfmFaultCondition
#define MASS_FLOW_ERROR_VALUE
Definition: parameters.h:302

◆ MFM_expi_read_milliliters()

int32_t MFM_expi_read_milliliters ( bool  reset_after_read)

Get the number of milliliters since last reset for expiratory sensor.

Parameters
reset_after_readIf true, performs the volume reset in the same atomic operation
Returns
Volume of air that went through sensor since last reset in mL

Definition at line 654 of file mass_flow_meter.cpp.

654  {
655  int32_t result = MASS_FLOW_ERROR_VALUE;
656 
657 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
658  result = mfmFaultCondition
661 #endif
662  if (reset_after_read) {
663  MFM_expi_reset();
664  }
665 
666  return result;
667 }
volatile int32_t mfmExpiratoryAirVolumeSumMilliliters
void MFM_expi_reset(void)

◆ MFM_expi_read_serial_number()

uint32_t MFM_expi_read_serial_number ( void  )

return the serial number of the expiratory flow meter

Get the serial number of the expiratory flow meter.

Note
returns 0 before init, or if init failed.

Definition at line 597 of file mass_flow_meter.cpp.

597 { return mfmSfm3300SerialNumberExpi; }
uint32_t mfmSfm3300SerialNumberExpi

◆ MFM_expi_reset()

void MFM_expi_reset ( void  )

Definition at line 578 of file mass_flow_meter.cpp.

◆ MFM_getOffset()

int32_t MFM_getOffset ( void  )

Get massflow meter offset.

Definition at line 635 of file mass_flow_meter.cpp.

◆ MFM_init()

bool MFM_init ( void  )

Initialize Mass Flow Meter.

Returns
True if there is a Mass Flow Meter connected
Warning
If no Mass Flow Meter is detected, you will always read volume = 0 mL

Definition at line 321 of file mass_flow_meter.cpp.

321  {
323  // cppcheck-suppress unreadVariable
324  uint32_t errorCount = 0;
325  // Set power on (hardware v3)
326  pinMode(MFM_POWER_CONTROL, OUTPUT);
327  digitalWrite(MFM_POWER_CONTROL, MFM_POWER_ON);
328  delay(100); // sfm3300 worst case boot time.
329 
330  // Set the timer
331  massFlowTimer = new HardwareTimer(MASS_FLOW_TIMER);
332 
333  // Prescaler; stm32f411 clock is 100 mHz
334  massFlowTimer->setPrescaleFactor((massFlowTimer->getTimerClkFreq() / MASS_FLOW_TIMER_FREQ) - 1);
335 
336  // Set the period
337  massFlowTimer->setOverflow(MASS_FLOW_PERIOD);
338  massFlowTimer->setMode(MASS_FLOW_CHANNEL, TIMER_OUTPUT_COMPARE, NC);
339  massFlowTimer->attachInterrupt(MFM_Timer_Callback);
340 
341  // Interrupt priority is documented here:
342  // https://stm32f4-discovery.net/2014/05/stm32f4-stm32f429-nvic-or-nested-vector-interrupt-controller/
343  // WARNING : since 1.9.0 lib, I2C is on level 2. must be under...
344  massFlowTimer->setInterruptPriority(3, 0);
345 
346  // default Wire instance is on PB8 BP9, anyway
347  Wire.setSDA(PIN_I2C_SDA);
348  Wire.setSCL(PIN_I2C_SCL);
349  // Wire.setClock(400000); // honeywell do support, but no information about sfm3300d
350 
351 #if MASS_FLOW_METER_SENSOR == MFM_SFM3019
352  Wire.begin();
353  Wire.beginTransmission(0x00);
354  Wire.write(0x06);
355  Wire.endTransmission();
356  Wire.end();
357  delay(4);
358 
359  // // start air continuous measurement
360  // Wire.begin();
361  // Wire.beginTransmission(MFM_SFM3019_I2C_ADDRESS);
362  // Wire.write(0x36);
363  // Wire.write(0x08);
364  // errorCount += Wire.endTransmission();
365  // Wire.end();
366 
367  // delay(2);
368  // //Stop continuous measurement 0x3FF9
369  // Wire.begin();
370  // Wire.beginTransmission(0x2E);
371  // Wire.write(0x3F);
372  // Wire.write(0xF9);
373  // Wire.endTransmission();
374  // Wire.end();
375 
376  // delay(2);
377  // //Read Scale Factor, Offset, and Flow Unit 0x3661
378  // Wire.begin();
379  // Wire.beginTransmission(0x2E);
380  // Wire.write(0x36);
381  // Wire.write(0x61);
382  // Wire.endTransmission();
383  // Wire.end();
384  // delay(2);
385  // Wire.begin();
386  // int ccc = Wire.requestFrom(0x2E, 8);
387  // Serial.print(ccc);
388  // Serial.print(" ");
389  // Serial.print(Wire.read()); Serial.print(",");
390  // Serial.print(Wire.read()); Serial.print(",");
391  // Serial.print(Wire.read()); Serial.print(",");
392  // Serial.print(Wire.read()); Serial.print(",");
393  // Serial.print(Wire.read()); Serial.print(",");
394  // Serial.print(Wire.read()); Serial.print(",");
395  // Serial.print(Wire.read()); Serial.print(",");
396  // Serial.print(Wire.read()); Serial.print(",");
397 
398  // Wire.end();
399 
400  delay(5);
401  // Read serial number
402  Wire.begin();
403  Wire.beginTransmission(MFM_SFM3019_I2C_ADDRESS);
404  Wire.write(0xE1);
405  Wire.write(0x02);
406  errorCount = Wire.endTransmission();
407 
408  delay(1);
409  errorCount += ((18u == Wire.requestFrom(MFM_SFM3019_I2C_ADDRESS, 18)) ? 0u : 1u);
410  if (errorCount == 0u) {
411  // the serial number is 64 bits wide, but it will never be used until year 2042.
412  // The serial number can be converted from binary into decimal,
413  // whereby in decimal it has the following format::
414  // yywwxxxxxx, where: yy: last to digits of calibration year, ww:
415  // calibration week, xxxxxx: unique 6-digit sequential number
416  // within the calibration week.
417  uint32_t sn_inspi = 0;
418  Wire.read();
419  Wire.read(); // product number part 1
420  Wire.read(); // crc
421  Wire.read();
422  Wire.read(); // product number part 2
423  Wire.read(); // crc
424 
425  Wire.read();
426  Wire.read(); // ignore this part of serial
427  Wire.read(); // ignore inlined crc
428  Wire.read();
429  Wire.read(); // ignore this part of serial
430  Wire.read(); // ignore inlined crc
431  sn_inspi |= Wire.read();
432  sn_inspi <<= 8;
433  sn_inspi |= Wire.read();
434  sn_inspi <<= 8;
435  Wire.read(); // ignore inlined crc
436  sn_inspi |= Wire.read();
437  sn_inspi <<= 8;
438  sn_inspi |= Wire.read();
439  Wire.read(); // ignore inlined crc
440  mfmSfm3019SerialNumber = sn_inspi;
441  }
442  delay(1);
443 
444  // start air continuous measurement
445  Wire.begin();
446  Wire.beginTransmission(MFM_SFM3019_I2C_ADDRESS);
447  Wire.write(0x36);
448  Wire.write(0x08);
449  errorCount += Wire.endTransmission();
450  Wire.end();
451 
452  delay(40); // the first measurement result will be available after 12ms
453  // small accuracy deviations (few % of reading) can occur during the first 30ms
454 
455  // delay(10000);
456  if (errorCount != 0u) {
457  mfmFaultCondition = true;
459  }
460 #endif
461 
462 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
463  Wire.begin(); // Join I2C bus (address is optional for master)
464  Wire.beginTransmission(MFM_SFM_3300D_I2C_ADDRESS);
465  Wire.write(0x20); // 0x2000 soft reset
466  Wire.write(0x00);
467  errorCount = Wire.endTransmission();
468  delay(5); // end of reset
469 
470  Wire.beginTransmission(MFM_SFM_3300D_I2C_ADDRESS);
471  Wire.write(0x31); // 0x31AE read serial
472  Wire.write(0xAE);
473  errorCount += Wire.endTransmission();
474 
475  errorCount += ((6u == Wire.requestFrom(MFM_SFM_3300D_I2C_ADDRESS, 6)) ? 0u : 1u);
476  if (errorCount == 0u) {
477  u_int32_t sn_expi = 0;
478  sn_expi = Wire.read();
479  sn_expi <<= 8;
480  sn_expi |= Wire.read();
481  sn_expi <<= 8;
482  Wire.read(); // ignore inlined crc
483  sn_expi |= Wire.read();
484  sn_expi <<= 8;
485  sn_expi |= Wire.read();
486  Wire.read(); // ignore inlined crc
487  mfmSfm3300SerialNumberExpi = sn_expi;
488  }
489  delay(10);
490  Wire.beginTransmission(MFM_SFM_3300D_I2C_ADDRESS);
491  Wire.write(0x10); // 0x1000 start measurement
492  Wire.write(0x00);
493  errorCount += Wire.endTransmission();
494  Wire.end();
495  delay(100); // wait 100ms before having available data.
496 
497  if (errorCount != 0u) {
498  mfmFaultCondition = true;
500  }
501 #endif
502 
503 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
504 
505  /*
506  Init sequence for Honeywell Zephyr mass flow sensor:
507  1st read operation: the sensor will send 0x0000
508  2nd read operation: the sensor will send the first part of the serial number
509  3rd read operation: the sensor will send the second part of the serial number
510  Subsequent read operations: the sensor will send calibrated mass air flow values with two
511  leading 0
512  */
513  Wire.begin();
514  Wire.beginTransmission(MFM_HONEYWELL_HAF_I2C_ADDRESS);
515  Wire.write(0x02); // Force reset
516  uint8_t txOk = Wire.endTransmission();
517  Wire.end();
518  delay(30);
519 
520  u_int32_t sn = 0;
521  Wire.begin();
522  Wire.beginTransmission(MFM_HONEYWELL_HAF_I2C_ADDRESS);
523  uint8_t rxcount = Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
524  sn = Wire.read();
525  sn <<= 8;
526  sn |= Wire.read(); // first transmission is serial number register 0
527  sn <<= 8;
528  delay(2); // if you do not wait, sensor will send again register 0
529  rxcount += Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
530  sn |= Wire.read();
531  sn <<= 8;
532  sn |= Wire.read(); // second transmission is serial number register 1
533 
534  if ((txOk != 0u) || (rxcount != 4u)) { // If transmission failed
535  mfmFaultCondition = true;
537  } else {
539  }
540  Wire.end();
541 
542 #if MODE == MODE_MFM_TESTS
543  Serial.println("Read 1");
544  Serial.println(mfmLastData.i);
545  Serial.println("fault condition:");
546  Serial.println(mfmFaultCondition ? "failure" : "no failure");
547 #endif
548  delay(100);
549 #endif
550 
551  massFlowTimer->resume();
552  return !mfmFaultCondition;
553 }
uint32_t mfmSfm3019SerialNumber
volatile int32_t mfmInspiratoryAirVolumeSumMilliliters
union @0 mfmLastData
HardwareTimer * massFlowTimer
int32_t mfmResetStateMachine
#define MASS_FLOW_TIMER_FREQ
void MFM_Timer_Callback(HardwareTimer *)
#define MFM_WAIT_RESET_PERIODS
uint32_t mfmHoneywellHafSerialNumber
#define MFM_SFM_3300D_I2C_ADDRESS
#define MFM_SFM3019_I2C_ADDRESS
#define MFM_HONEYWELL_HAF_I2C_ADDRESS
#define MASS_FLOW_CHANNEL
Definition: parameters.h:294
#define MASS_FLOW_TIMER
Definition: parameters.h:293
#define PIN_I2C_SCL
Definition: parameters.h:296
#define MFM_POWER_ON
Definition: parameters.h:300
#define MFM_POWER_CONTROL
Definition: parameters.h:298
#define PIN_I2C_SDA
Definition: parameters.h:295

◆ MFM_read_airflow()

int32_t MFM_read_airflow ( void  )

Read instant air flow.

Definition at line 555 of file mass_flow_meter.cpp.

555  {
556  int32_t r;
557  if (mfmFaultCondition) {
559  } else {
561  }
562  return r;
563 }
volatile int32_t mfmInspiratoryInstantAirFlow

◆ MFM_read_milliliters()

int32_t MFM_read_milliliters ( bool  reset_after_read)

Get the number of milliliters since last reset.

Parameters
reset_after_readIf true, performs the volume reset in the same atomic operation
Returns
Volume of air that went through sensor since last reset in mL

Definition at line 637 of file mass_flow_meter.cpp.

637  {
638  int32_t result = MASS_FLOW_ERROR_VALUE;
639 
640 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF || MASS_FLOW_METER_SENSOR == MFM_SFM3019
641  // period is MASS_FLOW_PERIOD / 10000 (100 µs prescaler)
642  result = mfmFaultCondition
645 #endif
646 
647  if (reset_after_read) {
648  MFM_reset();
649  }
650 
651  return result;
652 }
void MFM_reset(void)
Reset the volume counter.

◆ MFM_read_serial_number()

uint32_t MFM_read_serial_number ( void  )

Get the serial number of the inspiratory flow meter.

Returns
The serial number, or 0 if before init or if init failed

Definition at line 581 of file mass_flow_meter.cpp.

581  {
582 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
584 #elif MASS_FLOW_METER_SENSOR == MFM_SFM3019
585  return mfmSfm3019SerialNumber;
586 #endif
587  return 0;
588 }

◆ MFM_reset()

void MFM_reset ( void  )

Reset the volume counter.

Definition at line 576 of file mass_flow_meter.cpp.

◆ MFM_Timer_Callback()

void MFM_Timer_Callback ( HardwareTimer *  )

Definition at line 102 of file mass_flow_meter.cpp.

106 {
107 #if MODE == MODE_MFM_TESTS
108  // cppcheck-suppress misra-c2012-12.3
109  digitalWrite(PIN_LED_START, HIGH);
110  // it takes typically 350 µs to read the value.
111 #endif
112  if (MFM_force_release_I2C != static_cast<uint16_t>(MFM_FORCE_RELEASE_I2C_TRUE)) {
113  if (!mfmFaultCondition) {
114 #if MASS_FLOW_METER_SENSOR == MFM_SFM3019
115  Wire.begin();
116  uint8_t readCountbis = Wire.requestFrom(MFM_SFM3019_I2C_ADDRESS, 3);
117  mfmLastData.c[1] = Wire.read();
118  mfmLastData.c[0] = Wire.read();
119  Wire.end();
120  // Hardware reset if not able to read two bytes.
121  if (readCountbis != 3u) {
122  mfmFaultCondition = true;
124  mfmInspiratoryAirVolumeSumMilliliters = 1000000000; // 1e9
125  }
126  mfmInspiratoryLastValueFixedFloat = (1000 * (mfmLastData.si + 24576)) / 170;
127 
128 #endif
129 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
130 
131  // begin() and end() everytime you read... the lib never free buffers if you don't do
132  // this.
133  Wire.begin();
134  uint8_t readCount = Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
135  mfmLastData.c[0] = Wire.read();
136  mfmLastData.c[1] = Wire.read();
137  // Wire.endTransmission() send a new write order followed by a stop. Useless and the
138  // sensor often nack it.
139  Wire.end();
140 
141  // Hardware reset if not able to read two bytes.
142  if (readCount != 2u) {
143  mfmFaultCondition = true;
145  mfmInspiratoryAirVolumeSumMilliliters = 1000000000; // 1e9
146  }
147 
148  mfmInspiratoryLastValue = (uint32_t)(mfmLastData.c[1] & 0xFFu);
149  mfmInspiratoryLastValue |= (((uint32_t)mfmLastData.c[0]) << 8) & 0x0000FF00u;
150 
151  // Theorical formula: Flow(slpm) = 200*((rawvalue/16384)-0.1)/0.8
152  // float implementation, 1 liter per minute unit
153  // mfmLastValueFloat =
154  // MFM_RANGE * (((uint32_t)mfmInspiratoryLastValue / 16384.0) - 0.1) / 0.8;
155  // (Output value in SLPM)
156 
157  // fixed float implementation, 1 milliliter per minute unit
159  (((10 * mfmInspiratoryLastValue) - 16384) * 1526) / 1000;
160 
161  // 100 value per second, 100 slpm during 10 minutes: sum will be 1.2e9. it fits in a
162  // int32 int32 max with milliliters = 2e6 liters.
163 
164 #endif
165 
166 #if MASS_FLOW_METER_SENSOR == MFM_SFM3019 || MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
167  // The sensor (100 SPLM version anyway) tends to output spurrious values located at
168  // around 500 SLM, which are obviously not correct. Let's filter them out based on the
169  // range of the sensor + 10%.
172  if (mfmInspiratoryLastValueFixedFloat > 500) { // less than 0.5 SPLM is noise
175  }
176  // also fill the last values table used to compute average, and update the index
184  // table full, stops
186  }
187  }
188  }
189 #endif
190 
191 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
192  // begin() and end() everytime you read... the lib never free buffers if you don't do
193  // this.
194  Wire.begin();
195  // do not request crc, only two bytes
196  uint8_t readCountExpi = Wire.requestFrom(MFM_SFM_3300D_I2C_ADDRESS, 2);
197  mfmLastData.c[1] = Wire.read();
198  mfmLastData.c[0] = Wire.read();
199  Wire.end();
200 
201  // conversion in milliter per minute flow: ((int32_t)(mfmLastData.i) - 32768) * 1000 /
202  // 120 but 1000/120 = 8.333. So *8 and *1/3
204  (((int32_t)(mfmLastData.i) - 32768) * 8) + (((int32_t)(mfmLastData.i) - 32768) / 3);
205 
206  if (readCountExpi != 2u) {
208  // sfm 3300d needs 100ms after start of measurement before sending data.
209  // in case of bus failure, mfmFaultCondition is already true at this point
211  mfmFaultCondition = true;
213  mfmExpiratoryAirVolumeSumMilliliters = 1000000000; // 1e9
214  }
215  } else {
216  // valid data
219  || (mfmExpiratoryLastValueFixedFloat < -500)) { // less than 0.5 SPLM is noise
222  }
223  }
224 
225 #endif
226  } else {
228  // Reset attempt
229  // I2C sensors
230  Wire.flush();
231  Wire.end();
232 
233  // Set power off (available since hw3)
234  digitalWrite(MFM_POWER_CONTROL, MFM_POWER_OFF);
235  // also set SDA and SCL to 0 to avoid sensor to be powered by I2C bus.
236  pinMode(PIN_I2C_SDA, OUTPUT);
237  pinMode(PIN_I2C_SCL, OUTPUT);
238  digitalWrite(PIN_I2C_SCL, LOW);
239  __NOP();
240  digitalWrite(PIN_I2C_SDA, LOW);
241  }
242 
244 
245  // x period before end of reset cycle, power on again
247  // Set power on (available since hw v3)
248  digitalWrite(MFM_POWER_CONTROL, MFM_POWER_ON);
249  pinMode(PIN_I2C_SDA, INPUT);
250  pinMode(PIN_I2C_SCL, INPUT);
251  }
252 
253 #if MASS_FLOW_METER_SENSOR == MFM_SFM3019
255  // start air continuous measurement
256  Wire.begin();
257  Wire.beginTransmission(MFM_SFM3019_I2C_ADDRESS);
258  Wire.write(0x36);
259  Wire.write(0x08);
260  mfmFaultCondition = (0 != Wire.endTransmission()) || mfmFaultCondition;
261  Wire.end();
262  }
263 
264 #endif
265 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
267  Wire.begin();
268  Wire.beginTransmission(MFM_HONEYWELL_HAF_I2C_ADDRESS);
269  Wire.write(0x02); // Force reset
270  uint8_t status = Wire.endTransmission(); // actually send the data
271  Wire.end();
272  if (status != 0u) { // still a problem
274  }
275  }
277  Wire.begin();
278  // read first serial number register
279  uint8_t rxcount = Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
280  Wire.end();
281  if (rxcount != 2u) { // still a problem
283  }
284  }
285 #endif
286 
287  if (mfmResetStateMachine == 0) {
288  mfmFaultCondition = false;
289  // MFM_WAIT_RESET_PERIODS cycles later, try again to init the sensor
290 
291 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
292  Wire.begin();
293  // read second serial number register
294  uint8_t rxcount = Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
295  Wire.end();
296  mfmFaultCondition = (rxcount != 2u) || mfmFaultCondition;
297 #endif
298 
299 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
300  Wire.begin();
301  Wire.beginTransmission(MFM_SFM_3300D_I2C_ADDRESS);
302  Wire.write(0x10);
303  Wire.write(0x00);
304  mfmFaultCondition = (0 != Wire.endTransmission()) || mfmFaultCondition;
306  Wire.end();
307 #endif
308 
309  if (mfmFaultCondition) {
311  }
312  }
313  }
314  }
315 #if MODE == MODE_MFM_TESTS
316  digitalWrite(PIN_LED_START, LOW);
317  digitalWrite(PIN_LED_GREEN, mfmFaultCondition ? HIGH : LOW);
318 #endif
319 }
#define MFM_RANGE
Defines the range of the Mass Flow Meter in SLM (standard liter per minute)
Definition: config.h:48
int32_t mfmInspiratoryLastValue
#define MFM_WAIT_SOFTRESET_PERIODS
volatile int32_t mfmInspiratoryLastValueFixedFloat
volatile int32_t mfmExpiratoryLastValueFixedFloat
volatile uint16_t MFM_force_release_I2C
#define MFM_WAIT_WARMUP_PERIODS
uint16_t mfmExpiSFM3300FailCounter
#define MFM_WAIT_READSERIALR1_PERIODS
#define MFM_FORCE_RELEASE_I2C_TRUE
#define PIN_LED_GREEN
Definition: parameters.h:253
#define PIN_LED_START
Definition: parameters.h:252
#define MFM_POWER_OFF
Definition: parameters.h:299

Variable Documentation

◆ c

unsigned char c[2]

Definition at line 93 of file mass_flow_meter.cpp.

◆ i

uint16_t i

Definition at line 91 of file mass_flow_meter.cpp.

◆ massFlowTimer

HardwareTimer* massFlowTimer = NULL

Definition at line 48 of file mass_flow_meter.cpp.

◆ MFM_force_release_I2C

volatile uint16_t MFM_force_release_I2C = MFM_FORCE_RELEASE_I2C_FALSE

Definition at line 32 of file mass_flow_meter.cpp.

◆ mfmExpiratoryAirVolumeSumMilliliters

volatile int32_t mfmExpiratoryAirVolumeSumMilliliters = 0

Definition at line 61 of file mass_flow_meter.cpp.

◆ mfmExpiratoryCalibrationOffset

volatile int32_t mfmExpiratoryCalibrationOffset = 0

Definition at line 60 of file mass_flow_meter.cpp.

◆ mfmExpiratoryInstantAirFlow

volatile int32_t mfmExpiratoryInstantAirFlow = 0

Definition at line 63 of file mass_flow_meter.cpp.

◆ mfmExpiratoryLastValueFixedFloat

volatile int32_t mfmExpiratoryLastValueFixedFloat = 0

Definition at line 75 of file mass_flow_meter.cpp.

◆ mfmExpiratorySensorDetected

volatile int32_t mfmExpiratorySensorDetected = 0

Definition at line 62 of file mass_flow_meter.cpp.

◆ mfmExpiSFM3300FailCounter

uint16_t mfmExpiSFM3300FailCounter = 0

Definition at line 87 of file mass_flow_meter.cpp.

◆ mfmFaultCondition

volatile bool mfmFaultCondition = false

Definition at line 50 of file mass_flow_meter.cpp.

◆ mfmHoneywellHafSerialNumber

uint32_t mfmHoneywellHafSerialNumber = 0

Definition at line 44 of file mass_flow_meter.cpp.

◆ mfmInspiratoryAirVolumeSumMilliliters

volatile int32_t mfmInspiratoryAirVolumeSumMilliliters = 0

Definition at line 56 of file mass_flow_meter.cpp.

◆ mfmInspiratoryCalibrationOffset

volatile int32_t mfmInspiratoryCalibrationOffset = 0

Definition at line 55 of file mass_flow_meter.cpp.

◆ mfmInspiratoryInstantAirFlow

volatile int32_t mfmInspiratoryInstantAirFlow = 0

Definition at line 58 of file mass_flow_meter.cpp.

◆ mfmInspiratoryInstantAirFlowLastValues

volatile int32_t mfmInspiratoryInstantAirFlowLastValues[MFM_MEAN_SAMPLES]

Definition at line 68 of file mass_flow_meter.cpp.

◆ mfmInspiratoryInstantAirFlowLastValuesIndex

volatile int16_t mfmInspiratoryInstantAirFlowLastValuesIndex = 0

Definition at line 70 of file mass_flow_meter.cpp.

◆ mfmInspiratoryInstantAirFlowRecord

volatile bool mfmInspiratoryInstantAirFlowRecord = false

Definition at line 67 of file mass_flow_meter.cpp.

◆ mfmInspiratoryLastValue

int32_t mfmInspiratoryLastValue = 0

Definition at line 72 of file mass_flow_meter.cpp.

◆ mfmInspiratoryLastValueFixedFloat

volatile int32_t mfmInspiratoryLastValueFixedFloat = 0

Definition at line 73 of file mass_flow_meter.cpp.

◆ mfmInspiratorySensorDetected

volatile int32_t mfmInspiratorySensorDetected = 0

Definition at line 57 of file mass_flow_meter.cpp.

◆ 

union { ... } mfmLastData

◆ mfmResetStateMachine

int32_t mfmResetStateMachine = MFM_WAIT_RESET_PERIODS

Definition at line 85 of file mass_flow_meter.cpp.

◆ mfmSfm3019SerialNumber

uint32_t mfmSfm3019SerialNumber = 0

Definition at line 47 of file mass_flow_meter.cpp.

◆ mfmSfm3300SerialNumberExpi

uint32_t mfmSfm3300SerialNumberExpi = 0

Definition at line 46 of file mass_flow_meter.cpp.

◆ si

int16_t si

Definition at line 92 of file mass_flow_meter.cpp.