Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of MAX30100 by
Revision 0:010b908e2187, committed 2016-11-25
- Comitter:
- AVELARDEV
- Date:
- Fri Nov 25 00:52:54 2016 +0000
- Child:
- 1:4cce508186cf
- Commit message:
- max30100 example
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100.cpp Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,199 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "MAX30100.h"
+
+I2C Wire(I2C_SDA , I2C_SCL );
+
+MAX30100::MAX30100()
+{
+
+}
+
+bool MAX30100::begin()
+{
+// Wire.begin();
+// Wire.setClock(I2C_BUS_SPEED);
+
+ Wire.frequency(I2C_BUS_SPEED);
+
+ if(!setMode(DEFAULT_MODE))
+ return false;
+ if(!setLedsPulseWidth(DEFAULT_PULSE_WIDTH))
+ return false;
+ if(!setSamplingRate(DEFAULT_SAMPLING_RATE))
+ return false;
+ if(!setLedsCurrent(DEFAULT_IR_LED_CURRENT, DEFAULT_RED_LED_CURRENT))
+ return false;
+ if(!setHighresModeEnabled(true))
+ return false;
+
+ return true;
+}
+
+bool MAX30100::setMode(Mode mode)
+{
+ if(!writeRegister(MAX30100_REG_MODE_CONFIGURATION, mode))
+ return false;
+ else
+ return true;
+}
+
+bool MAX30100::setLedsPulseWidth(LEDPulseWidth ledPulseWidth)
+{
+ uint8_t previous;
+ if(readRegister(MAX30100_REG_SPO2_CONFIGURATION, &previous))
+ if(!writeRegister(MAX30100_REG_SPO2_CONFIGURATION, (previous & 0xfc) | ledPulseWidth))
+ return false;
+ else
+ return true;
+ else
+ return false;
+}
+
+bool MAX30100::setSamplingRate(SamplingRate samplingRate)
+{
+ uint8_t previous;
+ if(readRegister(MAX30100_REG_SPO2_CONFIGURATION, &previous))
+ if(!writeRegister(MAX30100_REG_SPO2_CONFIGURATION, (previous & 0xe3) | (samplingRate << 2)))
+ return false;
+ else
+ return true;
+ else
+ return false;
+}
+
+bool MAX30100::setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent)
+{
+ if(!writeRegister(MAX30100_REG_LED_CONFIGURATION, redLedCurrent << 4 | irLedCurrent))
+ return false;
+ else
+ return true;
+}
+
+bool MAX30100::setHighresModeEnabled(bool enabled)
+{
+ uint8_t previous;
+ if(readRegister(MAX30100_REG_SPO2_CONFIGURATION, &previous))
+ if (enabled) {
+ if(!writeRegister(MAX30100_REG_SPO2_CONFIGURATION, previous | MAX30100_SPC_SPO2_HI_RES_EN))
+ return false;
+ else
+ return true;
+ } else {
+ if(!writeRegister(MAX30100_REG_SPO2_CONFIGURATION, previous & ~MAX30100_SPC_SPO2_HI_RES_EN))
+ return false;
+ else
+ return true;
+ }
+ else
+ return false;
+}
+
+
+bool MAX30100::update()
+{
+ if(!readFifoData())
+ return false;
+ else
+ return true;
+}
+
+
+/*
+uint8_t MAX30100::readRegister(uint8_t address)
+{
+ Wire.beginTransmission(MAX30100_I2C_ADDRESS);
+ Wire.write(address);
+ Wire.endTransmission(false);
+ Wire.requestFrom(MAX30100_I2C_ADDRESS, 1);
+
+ return Wire.read();
+}
+*/
+
+bool MAX30100::readRegister(uint8_t uch_addr, uint8_t *puch_data)
+/**
+* \brief Read a MAX30102 register
+* \par Details
+* This function reads a MAX30102 register
+*
+* \param[in] uch_addr - register address
+* \param[out] puch_data - pointer that stores the register data
+*
+* \retval true on success
+*/
+{
+ char ch_i2c_data;
+ ch_i2c_data=uch_addr;
+ if(Wire.write(I2C_WRITE_ADDR, &ch_i2c_data, 1, true)!=0)
+ return false;
+ if(Wire.read(I2C_READ_ADDR, &ch_i2c_data, 1, false)==0)
+ {
+ *puch_data=(uint8_t) ch_i2c_data;
+ return true;
+ }
+ else
+ return false;
+}
+
+/*
+void MAX30100::writeRegister(uint8_t address, uint8_t data)
+{
+ Wire.beginTransmission(MAX30100_I2C_ADDRESS);
+ Wire.write(address);
+ Wire.write(data);
+ Wire.endTransmission();
+}
+*/
+
+bool MAX30100::writeRegister(uint8_t uch_addr, uint8_t uch_data)
+/**
+* \brief Write a value to a MAX30102 register
+* \par Details
+* This function writes a value to a MAX30102 register
+*
+* \param[in] uch_addr - register address
+* \param[in] uch_data - register data
+*
+* \retval true on success
+*/
+{
+ char ach_i2c_data[2];
+ ach_i2c_data[0]=uch_addr;
+ ach_i2c_data[1]=uch_data;
+
+ if(Wire.write(I2C_WRITE_ADDR, ach_i2c_data, 2, false)==0)
+ return true;
+ else
+ return false;
+}
+
+bool MAX30100::readFifoData()
+{
+ char ach_i2c_data[4];
+
+ ach_i2c_data[0]=MAX30100_REG_FIFO_DATA;
+ if(Wire.write(I2C_WRITE_ADDR, ach_i2c_data, 1, true)!=0)
+ return false;
+ if(Wire.read(I2C_READ_ADDR, ach_i2c_data, 4, false)!=0)
+ return false;
+
+ // Warning: the values are always left-aligned
+ rawIRValue = (ach_i2c_data[0] << 8) | ach_i2c_data[1];
+ rawRedValue = (ach_i2c_data[2] << 8) | ach_i2c_data[3];
+
+ return true;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100.h Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,58 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MAX30100_H
+#define MAX30100_H
+
+#include <stdint.h>
+#include "mbed.h"
+#include "MAX30100_Registers.h"
+
+#define DEFAULT_MODE MAX30100_MODE_HRONLY
+#define DEFAULT_SAMPLING_RATE MAX30100_SAMPRATE_100HZ
+#define DEFAULT_PULSE_WIDTH MAX30100_SPC_PW_1600US_16BITS
+#define DEFAULT_RED_LED_CURRENT MAX30100_LED_CURR_50MA
+#define DEFAULT_IR_LED_CURRENT MAX30100_LED_CURR_50MA
+
+#define I2C_BUS_SPEED 400000UL
+
+class MAX30100 {
+public:
+ MAX30100();
+ bool begin();
+ bool setMode(Mode mode);
+ bool setLedsPulseWidth(LEDPulseWidth ledPulseWidth);
+ bool setSamplingRate(SamplingRate samplingRate);
+ bool setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent);
+ bool setHighresModeEnabled(bool enabled);
+ bool update();
+
+ uint16_t rawIRValue;
+ uint16_t rawRedValue;
+
+private:
+ /*
+ uint8_t readRegister(uint8_t address);
+ void writeRegister(uint8_t address, uint8_t data);
+ void burstRead(uint8_t baseAddress, uint8_t *buffer, uint8_t length);
+ void readFifoData();
+ */
+
+ bool writeRegister(uint8_t uch_addr, uint8_t uch_data);
+ bool readRegister(uint8_t uch_addr, uint8_t *puch_data);
+ bool readFifoData();
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100_BeatDetector.cpp Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,124 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "MAX30100_BeatDetector.h"
+
+BeatDetector::BeatDetector() :
+ state(BEATDETECTOR_STATE_INIT),
+ threshold(BEATDETECTOR_MIN_THRESHOLD),
+ beatPeriod(0),
+ lastMaxValue(0),
+ tsLastBeat(0)
+{
+ t.start();
+}
+
+bool BeatDetector::addSample(float sample)
+{
+ return checkForBeat(sample);
+}
+
+float BeatDetector::getRate()
+{
+ if (beatPeriod != 0) {
+ return 1 / beatPeriod * 1000 * 60;
+ } else {
+ return 0;
+ }
+}
+
+float BeatDetector::getCurrentThreshold()
+{
+ return threshold;
+}
+
+bool BeatDetector::checkForBeat(float sample)
+{
+ bool beatDetected = false;
+
+ switch (state) {
+ case BEATDETECTOR_STATE_INIT:
+ if (t.read_ms() > BEATDETECTOR_INIT_HOLDOFF) {
+ state = BEATDETECTOR_STATE_WAITING;
+ }
+ break;
+
+ case BEATDETECTOR_STATE_WAITING:
+ if (sample > threshold) {
+ threshold = std::min((uint32_t)sample, (uint32_t)BEATDETECTOR_MAX_THRESHOLD);
+ state = BEATDETECTOR_STATE_FOLLOWING_SLOPE;
+ }
+
+ // Tracking lost, resetting
+ if (t.read_ms() > BEATDETECTOR_INVALID_READOUT_DELAY) {
+ beatPeriod = 0;
+ lastMaxValue = 0;
+ }
+
+ decreaseThreshold();
+ break;
+
+ case BEATDETECTOR_STATE_FOLLOWING_SLOPE:
+ if (sample < threshold) {
+ state = BEATDETECTOR_STATE_MAYBE_DETECTED;
+ } else {
+ threshold = std::min((uint32_t)sample, (uint32_t)BEATDETECTOR_MAX_THRESHOLD);
+ }
+ break;
+
+ case BEATDETECTOR_STATE_MAYBE_DETECTED:
+ if (sample + BEATDETECTOR_STEP_RESILIENCY < threshold) {
+ // Found a beat
+ beatDetected = true;
+ lastMaxValue = sample;
+ state = BEATDETECTOR_STATE_MASKING;
+ float delta = t.read_ms();
+ if (delta) {
+ beatPeriod = BEATDETECTOR_BPFILTER_ALPHA * delta +
+ (1 - BEATDETECTOR_BPFILTER_ALPHA) * beatPeriod;
+ }
+
+ t.reset();
+ } else {
+ state = BEATDETECTOR_STATE_FOLLOWING_SLOPE;
+ }
+ break;
+
+ case BEATDETECTOR_STATE_MASKING:
+ if (t.read_ms() > BEATDETECTOR_MASKING_HOLDOFF) {
+ state = BEATDETECTOR_STATE_WAITING;
+ }
+ decreaseThreshold();
+ break;
+ }
+
+ return beatDetected;
+}
+
+void BeatDetector::decreaseThreshold()
+{
+ // When a valid beat rate readout is present, target the
+ if (lastMaxValue > 0 && beatPeriod > 0) {
+ threshold -= lastMaxValue * (1 - BEATDETECTOR_THRESHOLD_FALLOFF_TARGET) /
+ (beatPeriod / BEATDETECTOR_SAMPLES_PERIOD);
+ } else {
+ // Asymptotic decay
+ threshold *= BEATDETECTOR_THRESHOLD_DECAY_FACTOR;
+ }
+
+ if (threshold < BEATDETECTOR_MIN_THRESHOLD) {
+ threshold = BEATDETECTOR_MIN_THRESHOLD;
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100_BeatDetector.h Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,64 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MAX30100_BEATDETECTOR_H
+#define MAX30100_BEATDETECTOR_H
+
+#include "mbed.h"
+#include <stdint.h>
+#include <algorithm>
+
+#define BEATDETECTOR_INIT_HOLDOFF 2000 // in ms, how long to wait before counting
+#define BEATDETECTOR_MASKING_HOLDOFF 200 // in ms, non-retriggerable window after beat detection
+#define BEATDETECTOR_BPFILTER_ALPHA 0.6 // EMA factor for the beat period value
+#define BEATDETECTOR_MIN_THRESHOLD 20 // minimum threshold (filtered) value
+#define BEATDETECTOR_MAX_THRESHOLD 800 // maximum threshold (filtered) value
+#define BEATDETECTOR_STEP_RESILIENCY 30 // maximum negative jump that triggers the beat edge
+#define BEATDETECTOR_THRESHOLD_FALLOFF_TARGET 0.3 // thr chasing factor of the max value when beat
+#define BEATDETECTOR_THRESHOLD_DECAY_FACTOR 0.99 // thr chasing factor when no beat
+#define BEATDETECTOR_INVALID_READOUT_DELAY 2000 // in ms, no-beat time to cause a reset
+#define BEATDETECTOR_SAMPLES_PERIOD 10 // in ms, 1/Fs
+
+
+typedef enum BeatDetectorState {
+ BEATDETECTOR_STATE_INIT,
+ BEATDETECTOR_STATE_WAITING,
+ BEATDETECTOR_STATE_FOLLOWING_SLOPE,
+ BEATDETECTOR_STATE_MAYBE_DETECTED,
+ BEATDETECTOR_STATE_MASKING
+} BeatDetectorState;
+
+
+class BeatDetector
+{
+public:
+ BeatDetector();
+ bool addSample(float sample);
+ float getRate();
+ float getCurrentThreshold();
+
+private:
+ bool checkForBeat(float value);
+ void decreaseThreshold();
+
+ BeatDetectorState state;
+ float threshold;
+ float beatPeriod;
+ float lastMaxValue;
+ uint32_t tsLastBeat;
+ Timer t;
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100_Filters.h Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,71 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MAX30100_FILTERS_H
+#define MAX30100_FILTERS_H
+
+// http://www.schwietering.com/jayduino/filtuino/
+// Low pass butterworth filter order=1 alpha1=0.1
+// Fs=100Hz, Fc=6Hz
+class FilterBuLp1
+{
+ public:
+ FilterBuLp1()
+ {
+ v[0]=0.0;
+ }
+ private:
+ float v[2];
+ public:
+ float step(float x) //class II
+ {
+ v[0] = v[1];
+ v[1] = (2.452372752527856026e-1 * x)
+ + (0.50952544949442879485 * v[0]);
+ return
+ (v[0] + v[1]);
+ }
+};
+
+// http://sam-koblenski.blogspot.de/2015/11/everyday-dsp-for-programmers-dc-and.html
+class DCRemover
+{
+public:
+ DCRemover() : alpha(0), dcw(0)
+ {
+ }
+ DCRemover(float alpha_) : alpha(alpha_), dcw(0)
+ {
+ }
+
+ float step(float x)
+ {
+ float olddcw = dcw;
+ dcw = (float)x + alpha * dcw;
+
+ return dcw - olddcw;
+ }
+
+ float getDCW()
+ {
+ return dcw;
+ }
+
+private:
+ float alpha;
+ float dcw;
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100_PulseOximeter.cpp Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,154 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <mbed.h>
+#include "MAX30100_PulseOximeter.h"
+
+
+PulseOximeter::PulseOximeter() :
+ state(PULSEOXIMETER_STATE_INIT),
+// tsFirstBeatDetected(0),
+// tsLastBeatDetected(0),
+// tsLastSample(0),
+// tsLastBiasCheck(0),
+// tsLastCurrentAdjustment(0),
+ redLedPower((uint8_t)RED_LED_CURRENT_START),
+ onBeatDetected(NULL)
+{
+}
+
+bool PulseOximeter::begin(PulseOximeterDebuggingMode debuggingMode_)
+{
+ debuggingMode = debuggingMode_;
+
+ if(!hrm.begin())
+ return false;
+ if(!hrm.setMode(MAX30100_MODE_SPO2_HR))
+ return false;
+ if(!hrm.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT_START))
+ return false;
+
+ irDCRemover = DCRemover(DC_REMOVER_ALPHA);
+ redDCRemover = DCRemover(DC_REMOVER_ALPHA);
+
+ state = PULSEOXIMETER_STATE_IDLE;
+ return true;
+}
+
+
+void PulseOximeter::update()
+{
+ checkSample();
+ checkCurrentBias();
+}
+
+float PulseOximeter::getHeartRate()
+{
+ return beatDetector.getRate();
+}
+
+uint8_t PulseOximeter::getSpO2()
+{
+ return spO2calculator.getSpO2();
+}
+
+uint8_t PulseOximeter::getRedLedCurrentBias()
+{
+ return redLedPower;
+}
+
+void PulseOximeter::setOnBeatDetectedCallback(void (*cb)())
+{
+ onBeatDetected = cb;
+ t_Sample.start();
+ t_CurrentBias.start();
+}
+
+void PulseOximeter::checkSample()
+{
+ if (t_Sample.read_ms() > 1.0 / SAMPLING_FREQUENCY * 1000.0) {
+ t_Sample.reset();
+ if(hrm.update()){
+
+ float irACValue = irDCRemover.step(hrm.rawIRValue);
+ float redACValue = redDCRemover.step(hrm.rawRedValue);
+
+ // The signal fed to the beat detector is mirrored since the cleanest monotonic spike is below zero
+ float filteredPulseValue = lpf.step(-irACValue);
+ bool beatDetected = beatDetector.addSample(filteredPulseValue);
+
+ if (beatDetector.getRate() > 0) {
+ state = PULSEOXIMETER_STATE_DETECTING;
+ spO2calculator.update(irACValue, redACValue, beatDetected);
+ } else if (state == PULSEOXIMETER_STATE_DETECTING) {
+ state = PULSEOXIMETER_STATE_IDLE;
+ spO2calculator.reset();
+ }
+ /*
+ switch (debuggingMode) {
+ case PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES:
+ Serial.print("R:");
+ Serial.print(hrm.rawIRValue);
+ Serial.print(",");
+ Serial.println(hrm.rawRedValue);
+ break;
+
+ case PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES:
+ Serial.print("R:");
+ Serial.print(irACValue);
+ Serial.print(",");
+ Serial.println(redACValue);
+ break;
+
+ case PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT:
+ Serial.print("R:");
+ Serial.print(filteredPulseValue);
+ Serial.print(",");
+ Serial.println(beatDetector->getCurrentThreshold());
+ break;
+
+ default:
+ break;
+ }
+ */
+ if (beatDetected && onBeatDetected) {
+ onBeatDetected();
+ }
+ }
+ }
+}
+
+void PulseOximeter::checkCurrentBias()
+{
+ // Follower that adjusts the red led current in order to have comparable DC baselines between
+ // red and IR leds. The numbers are really magic: the less possible to avoid oscillations
+ if (t_CurrentBias.read_ms() > CURRENT_ADJUSTMENT_PERIOD_MS) {
+ bool changed = false;
+ if (irDCRemover.getDCW() - redDCRemover.getDCW() > 70000 && redLedPower < MAX30100_LED_CURR_50MA) {
+ ++redLedPower;
+ changed = true;
+ } else if (redDCRemover.getDCW() - irDCRemover.getDCW() > 70000 && redLedPower > 0) {
+ --redLedPower;
+ changed = true;
+ }
+
+ if (changed) {
+ hrm.setLedsCurrent(IR_LED_CURRENT, (LEDCurrent)redLedPower);
+ //tsLastCurrentAdjustment = millis();
+ }
+
+ t_CurrentBias.reset();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100_PulseOximeter.h Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,83 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MAX30100_PULSEOXIMETER_H
+#define MAX30100_PULSEOXIMETER_H
+
+#define SAMPLING_FREQUENCY 100
+#define CURRENT_ADJUSTMENT_PERIOD_MS 500
+#define IR_LED_CURRENT MAX30100_LED_CURR_50MA
+#define RED_LED_CURRENT_START MAX30100_LED_CURR_27_1MA
+#define DC_REMOVER_ALPHA 0.95
+
+#include <stdint.h>
+#include <vector>
+
+
+#include "MAX30100.h"
+#include "MAX30100_BeatDetector.h"
+#include "MAX30100_Filters.h"
+#include "MAX30100_SpO2Calculator.h"
+
+typedef enum PulseOximeterState {
+ PULSEOXIMETER_STATE_INIT,
+ PULSEOXIMETER_STATE_IDLE,
+ PULSEOXIMETER_STATE_DETECTING
+} PulseOximeterState;
+
+typedef enum PulseOximeterDebuggingMode {
+ PULSEOXIMETER_DEBUGGINGMODE_NONE,
+ PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES,
+ PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES,
+ PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT
+} PulseOximeterDebuggingMode;
+
+
+class PulseOximeter {
+public:
+ PulseOximeter();
+
+ bool begin(PulseOximeterDebuggingMode debuggingMode_=PULSEOXIMETER_DEBUGGINGMODE_NONE);
+ void update();
+ float getHeartRate();
+ uint8_t getSpO2();
+ uint8_t getRedLedCurrentBias();
+ void setOnBeatDetectedCallback(void (*cb)());
+
+private:
+ void checkSample();
+ void checkCurrentBias();
+
+ PulseOximeterState state;
+ PulseOximeterDebuggingMode debuggingMode;
+// uint32_t tsFirstBeatDetected;
+// uint32_t tsLastBeatDetected;
+// uint32_t tsLastSample;
+// uint32_t tsLastBiasCheck;
+// uint32_t tsLastCurrentAdjustment;
+ BeatDetector beatDetector;
+ DCRemover irDCRemover;
+ DCRemover redDCRemover;
+ FilterBuLp1 lpf;
+ uint8_t redLedPower;
+ SpO2Calculator spO2calculator;
+
+ MAX30100 hrm;
+
+ void (*onBeatDetected)();
+ Timer t_Sample;
+ Timer t_CurrentBias;
+};
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100_Registers.h Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,108 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MAX30100_REGISTERS_H
+#define MAX30100_REGISTERS_H
+
+//#define MAX30100_I2C_ADDRESS 0x57
+#define I2C_WRITE_ADDR 0xAE
+#define I2C_READ_ADDR 0xAF
+
+// Interrupt status register (RO)
+#define MAX30100_REG_INTERRUPT_STATUS 0x00
+#define MAX30100_IS_PWR_RDY (1 << 0)
+#define MAX30100_IS_SPO2_RDY (1 << 4)
+#define MAX30100_IS_HR_RDY (1 << 5)
+#define MAX30100_IS_TEMP_RDY (1 << 6)
+#define MAX30100_IS_A_FULL (1 << 7)
+
+// Interrupt enable register
+#define MAX30100_REG_INTERRUPT_ENABLE 0x01
+#define MAX30100_IE_ENB_SPO2_RDY (1 << 4)
+#define MAX30100_IE_ENB_HR_RDY (1 << 5)
+#define MAX30100_IE_ENB_TEMP_RDY (1 << 6)
+#define MAX30100_IE_ENB_A_FULL (1 << 7)
+
+// FIFO control and data registers
+#define MAX30100_REG_FIFO_WRITE_POINTER 0x02
+#define MAX30100_REG_FIFO_OVERFLOW_COUNTER 0x03
+#define MAX30100_REG_FIFO_READ_POINTER 0x04
+#define MAX30100_REG_FIFO_DATA 0x05 // Burst read does not autoincrement addr
+
+// Mode Configuration register
+#define MAX30100_REG_MODE_CONFIGURATION 0x06
+#define MAX30100_MC_TEMP_EN (1 << 3)
+#define MAX30100_MC_RESET (1 << 6)
+#define MAX30100_MC_SHDN (1 << 7)
+typedef enum Mode {
+ MAX30100_MODE_HRONLY = 0x02,
+ MAX30100_MODE_SPO2_HR = 0x03
+} Mode;
+
+// SpO2 Configuration register
+// Check tables 8 and 9, p19 of the MAX30100 datasheet to see the permissible
+// combinations of sampling rates and pulse widths
+#define MAX30100_REG_SPO2_CONFIGURATION 0x07
+#define MAX30100_SPC_SPO2_HI_RES_EN (1 << 6)
+typedef enum SamplingRate {
+ MAX30100_SAMPRATE_50HZ = 0x00,
+ MAX30100_SAMPRATE_100HZ = 0x01,
+ MAX30100_SAMPRATE_167HZ = 0x02,
+ MAX30100_SAMPRATE_200HZ = 0x03,
+ MAX30100_SAMPRATE_400HZ = 0x04,
+ MAX30100_SAMPRATE_600HZ = 0x05,
+ MAX30100_SAMPRATE_800HZ = 0x06,
+ MAX30100_SAMPRATE_1000HZ = 0x07
+} SamplingRate;
+
+typedef enum LEDPulseWidth {
+ MAX30100_SPC_PW_200US_13BITS = 0x00,
+ MAX30100_SPC_PW_400US_14BITS = 0x01,
+ MAX30100_SPC_PW_800US_15BITS = 0x02,
+ MAX30100_SPC_PW_1600US_16BITS = 0x03
+} LEDPulseWidth;
+
+// LED Configuration register
+#define MAX30100_REG_LED_CONFIGURATION 0x09
+typedef enum LEDCurrent {
+ MAX30100_LED_CURR_0MA = 0x00,
+ MAX30100_LED_CURR_4_4MA = 0x01,
+ MAX30100_LED_CURR_7_6MA = 0x02,
+ MAX30100_LED_CURR_11MA = 0x03,
+ MAX30100_LED_CURR_14_2MA = 0x04,
+ MAX30100_LED_CURR_17_4MA = 0x05,
+ MAX30100_LED_CURR_20_8MA = 0x06,
+ MAX30100_LED_CURR_24MA = 0x07,
+ MAX30100_LED_CURR_27_1MA = 0x08,
+ MAX30100_LED_CURR_30_6MA = 0x09,
+ MAX30100_LED_CURR_33_8MA = 0x0a,
+ MAX30100_LED_CURR_37MA = 0x0b,
+ MAX30100_LED_CURR_40_2MA = 0x0c,
+ MAX30100_LED_CURR_43_6MA = 0x0d,
+ MAX30100_LED_CURR_46_8MA = 0x0e,
+ MAX30100_LED_CURR_50MA = 0x0f
+} LEDCurrent;
+
+// Temperature integer part register
+#define MAX30100_REG_TEMPERATURE_DATA_INT 0x16
+// Temperature fractional part register
+#define MAX30100_REG_TEMPERATURE_DATA_FRAC 0x17
+
+// Revision ID register (RO)
+#define MAX30100_REG_REVISION_ID 0xfe
+// Part ID register
+#define MAX30100_REG_PART_ID 0xff
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100_SpO2Calculator.cpp Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,71 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <math.h>
+
+#include "MAX30100_SpO2Calculator.h"
+
+// SaO2 Look-up Table
+// http://www.ti.com/lit/an/slaa274b/slaa274b.pdf
+const uint8_t SpO2Calculator::spO2LUT[43] = {100,100,100,100,99,99,99,99,99,99,98,98,98,98,
+ 98,97,97,97,97,97,97,96,96,96,96,96,96,95,95,
+ 95,95,95,95,94,94,94,94,94,93,93,93,93,93};
+
+SpO2Calculator::SpO2Calculator() :
+ irACValueSqSum(0),
+ redACValueSqSum(0),
+ beatsDetectedNum(0),
+ samplesRecorded(0),
+ spO2(0)
+{
+}
+
+void SpO2Calculator::update(float irACValue, float redACValue, bool beatDetected)
+{
+ irACValueSqSum += irACValue * irACValue;
+ redACValueSqSum += redACValue * redACValue;
+ ++samplesRecorded;
+
+ if (beatDetected) {
+ ++beatsDetectedNum;
+ if (beatsDetectedNum == CALCULATE_EVERY_N_BEATS) {
+ float acSqRatio = 100.0 * log(redACValueSqSum/samplesRecorded) / log(irACValueSqSum/samplesRecorded);
+ uint8_t index = 0;
+
+ if (acSqRatio > 66) {
+ index = (uint8_t)acSqRatio - 66;
+ } else if (acSqRatio > 50) {
+ index = (uint8_t)acSqRatio - 50;
+ }
+ reset();
+
+ spO2 = spO2LUT[index];
+ }
+ }
+}
+
+void SpO2Calculator::reset()
+{
+ samplesRecorded = 0;
+ redACValueSqSum = 0;
+ irACValueSqSum = 0;
+ beatsDetectedNum = 0;
+ spO2 = 0;
+}
+
+uint8_t SpO2Calculator::getSpO2()
+{
+ return spO2;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30100_SpO2Calculator.h Fri Nov 25 00:52:54 2016 +0000
@@ -0,0 +1,41 @@
+/*
+Arduino-MAX30100 oximetry / heart rate integrated sensor library
+Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MAX30100_SPO2CALCULATOR_H
+#define MAX30100_SPO2CALCULATOR_H
+
+#include <stdint.h>
+
+#define CALCULATE_EVERY_N_BEATS 3
+
+class SpO2Calculator {
+public:
+ SpO2Calculator();
+
+ void update(float irACValue, float redACValue, bool beatDetected);
+ void reset();
+ uint8_t getSpO2();
+
+private:
+ static const uint8_t spO2LUT[43];
+
+ float irACValueSqSum;
+ float redACValueSqSum;
+ uint8_t beatsDetectedNum;
+ uint32_t samplesRecorded;
+ uint8_t spO2;
+};
+
+#endif
\ No newline at end of file
