diff --git a/.github/issue_template.md b/.github/issue_template.md index 251d2e3..0e7010d 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -1,7 +1,7 @@ ### Troubleshooting checklist - [ ] I read the README (on master) thoroughly -- [ ] I ran the MAX30100_Tester and I'm going to paste the output down below +- [ ] I ran the MAX30102_Tester and I'm going to paste the output down below - [ ] I filled in all the details of my setup down below ### Description of the issue @@ -11,6 +11,6 @@ ### Details of my setup * Arduino hardware: -* MAX30100 breakout: +* MAX30102 breakout: * Arduino framework version: -* MAX30100 library version: +* MAX30102 library version: diff --git a/.travis.yml b/.travis.yml index dbeba73..b44139a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,8 @@ cache: - "~/.platformio" env: - - PLATFORMIO_CI_SRC=examples/MAX30100_Minimal - - PLATFORMIO_CI_SRC=examples/MAX30100_Debug + - PLATFORMIO_CI_SRC=examples/MAX30102_Minimal + - PLATFORMIO_CI_SRC=examples/MAX30102_Debug install: - pip install -U platformio diff --git a/README.md b/README.md index 35ea124..1bf9181 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,35 @@ -# Arduino-MAX30100 +# Arduino-MAX30102 -[![Build Status](https://travis-ci.org/oxullo/Arduino-MAX30100.svg?branch=master)](https://travis-ci.org/oxullo/Arduino-MAX30100) +Arduino library for the Maxim Integrated MAX30102 oximetry / heart rate sensor by Shivam Gupta -Arduino library for the Maxim Integrated MAX30100 oximetry / heart rate sensor. -![MAX30100](http://www.mouser.com/images/microsites/Maxim_MAX30100.jpg) +Based on a library written for the older MAX30100 sensor by OXullo Intersecans in 2016. +It has been ported to work with MAX30102 sensor breakouts, and new functions have been added to the library such as channel control, +so that all available functions of the device can be accessed with ease. + +All algorithms and example codes are written by the above author [OXullo Intersecans ], this is a fork building on that to extend support. +Original Library can be found here : https://github.com/oxullo/Arduino-MAX30100 + +vvvvvvvvvvvvvv +Carried over content, changed to fit the experiments I performed: +vvvvvvvvvvvvvv ## Disclaimer The library is offered only for educational purposes and it is not meant for medical uses. Use it at your sole risk. -## Notes - -Maxim integrated stopped the production of the MAX30100 in favor of MAX30101 and MAX30102. -Therefore this library won't be seeing any further improvement, besides fixes. - *IMPORTANT: when submitting issues, make sure to fill ALL the fields indicated in the template text of the issue. The issue will be marked as invalid and closed immediately otherwise.* ## Hardware -This library has been tested with the MikroElektronika Heart rate click daughterboard: +This library has been tested with two different breakout boards for MAX30102 + +https://www.amazon.in/xcluma-MAX30102-Upgraded-Ultra-Low-Compatible/dp/B07TZCNG2G/ref=sr_1_1?crid=3H93UW42TRQWY&dchild=1&keywords=xcluma+max30102&qid=1601127280&sprefix=xcluma+max%2Caps%2C299&sr=8-1 + +https://robokits.co.in/sensors/heart-beat-sensor/max30102-oximetry-sensor-module -http://www.mikroe.com/click/heart-rate/ +https://in.element14.com/webapp/wcs/stores/servlet/ProductDisplay?catalogId=15001&langId=91&productSeoURL=maxim-integrated-products&storeId=10186&partNumber=2627165&krypto=R4I%2BFWxL8JW4fRaTcbt%2BHuLRKF64g5pcACQC6j4AdeuGGnr%2F0z4QoAgzJYIFu516Z9ZklPwUROYW5qFA%2BXaDmA%3D%3D along with an Arduino UNO r3. Any Arduino supporting the Wire library should work. @@ -41,7 +48,7 @@ up by 4,7kOhm or less resistors. ## Architecture -The library offers a low-level driver class, MAX30100. +The library offers a low-level driver class, MAX30102. This component allows for low level communication with the device. A rather simple but working implementation of the heart rate and SpO2 calculation @@ -61,18 +68,18 @@ The PulseOximeter class is not optimised for battery-based projects. The included examples show how to use the PulseOximeter class: - * MAX30100_Minimal: a minimal example that dumps human-readable results via serial - * MAX30100_Debug: used in conjunction with the Processing pde "rolling_graph" (extras folder), to show the sampled data at various processing stages - * MAX30100_RawData: demonstrates how to access raw data from the sensor - * MAX30100_Tester: this sketch helps to find out potential issues with the sensor + * MAX30102_Minimal: a minimal example that dumps human-readable results via serial + * MAX30102_Debug: used in conjunction with the Processing pde "rolling_graph" (extras folder), to show the sampled data at various processing stages + * MAX30102_RawData: demonstrates how to access raw data from the sensor + * MAX30102_Tester: this sketch helps to find out potential issues with the sensor ## Troubleshooting -Run the MAX30100_Tester example to inspect the state of your rig. +Run the MAX30102_Tester example to inspect the state of your rig. When run with a properly connected sensor, it should print: ``` -Initializing MAX30100..Success +Initializing MAX30102..Success Enabling HR/SPO2 mode..done. Configuring LEDs biases to 50mA..done. Lowering the current to 7.6mA..done. @@ -95,7 +102,7 @@ Typical issues when attempting to run the examples: In particular when the tester fails with: ``` -Initializing MAX30100..FAILED: I2C error +Initializing MAX30102..FAILED: I2C error ``` This is likely to be caused by an improper pullup setup for the I2C lines. @@ -109,7 +116,7 @@ to 3.3V, you should ensure that its inputs are compatible with the 3.3V logic le An original Atmel ATMega328p considers anything above 3V as HIGH, so it might work well without level shifting hardware. -Since the MAX30100 I2C pins maximum ratings aren't bound to Vdd, a cheap option to avoid +Since the MAX30102 I2C pins maximum ratings aren't bound to Vdd, a cheap option to avoid level shifting is to simply pull SDA and SCL up to 5V instead of 3.3V. ### Sketchy beat frequency readouts @@ -119,31 +126,20 @@ by default at 50mA on all examples, excluding the Tester (which sets it to 7.6mA This value is somehow critical and it must be experimented with. The current can be adjusted using PulseOximeter::setIRLedCurrent(). -Check the _MAX30100_Minimal_ example. +Check the _MAX30102_Minimal_ example. ### Advanced debugging Two tools are available for further inspection and error reporting: * extras/recorder: a python script that records a session that can be then analysed with the provided collection of jupyter notebooks -* extras/rolling_graph: to be used in conjunction with _MAX30100_Debug_ example, it provides a visual feedback of the LED tracking and heartbeat detector +* extras/rolling_graph: to be used in conjunction with _MAX30102_Debug_ example, it provides a visual feedback of the LED tracking and heartbeat detector Both tools have additional information on the README.md in their respective directories. ## Tested devices -* Arduino UNO r3, Mikroelektronika Heart rate click (https://shop.mikroe.com/heart-rate-click) - -This combination works without level shifting devices at 400kHz I2C clock rate. - -* Arduino UNO r3, MAX30100 custom board with 4.7kOhm pullups to 5V to SDA, SCL, INT - -As above, working at 400kHz - -* Sparkfun Arduino Pro 328p 8MHz 3.3V, Mikroelektronika Heart rate click - -Even if this combination works (MAX30100 communication), the slower clock speed fails to deliver -the required performance deadlines for a 100Hz sampling. +#todo ## Troubled breakouts diff --git a/examples/MAX30100_Debug/MAX30100_Debug.ino b/examples/MAX30102_Debug/MAX30102_Debug.ino similarity index 84% rename from examples/MAX30100_Debug/MAX30100_Debug.ino rename to examples/MAX30102_Debug/MAX30102_Debug.ino index d08e6b7..2d58259 100644 --- a/examples/MAX30100_Debug/MAX30100_Debug.ino +++ b/examples/MAX30102_Debug/MAX30102_Debug.ino @@ -1,81 +1,84 @@ -/* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans - -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 . -*/ - -// This example must be used in conjunction with the Processing sketch located -// in extras/rolling_graph - -#include -#include "MAX30100_PulseOximeter.h" - -#define REPORTING_PERIOD_MS 1000 - -// PulseOximeter is the higher level interface to the sensor -// it offers: -// * beat detection reporting -// * heart rate calculation -// * SpO2 (oxidation level) calculation -PulseOximeter pox; - -uint32_t tsLastReport = 0; - -// Callback (registered below) fired when a pulse is detected -void onBeatDetected() -{ - Serial.println("B:1"); -} - -void setup() -{ - Serial.begin(115200); - - // Initialize the PulseOximeter instance and register a beat-detected callback - // The parameter passed to the begin() method changes the samples flow that - // the library spews to the serial. - // Options: - // * PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT : filtered samples and beat detection threshold - // * PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES : sampled values coming from the sensor, with no processing - // * PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES : sampled values after the DC removal filter - - // Initialize the PulseOximeter instance - // Failures are generally due to an improper I2C wiring, missing power supply - // or wrong target chip - if (!pox.begin(PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT)) { - Serial.println("ERROR: Failed to initialize pulse oximeter"); - for(;;); - } - - pox.setOnBeatDetectedCallback(onBeatDetected); -} - -void loop() -{ - // Make sure to call update as fast as possible - pox.update(); - - // Asynchronously dump heart rate and oxidation levels to the serial - // For both, a value of 0 means "invalid" - if (millis() - tsLastReport > REPORTING_PERIOD_MS) { - Serial.print("H:"); - Serial.println(pox.getHeartRate()); - - Serial.print("O:"); - Serial.println(pox.getSpO2()); - - tsLastReport = millis(); - } -} +/* +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. + +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 . +*/ + +// This example must be used in conjunction with the Processing sketch located +// in extras/rolling_graph + +#include +#include "MAX30102_PulseOximeter.h" + +#define REPORTING_PERIOD_MS 1000 + +// PulseOximeter is the higher level interface to the sensor +// it offers: +// * beat detection reporting +// * heart rate calculation +// * SpO2 (oxidation level) calculation +PulseOximeter pox; + +uint32_t tsLastReport = 0; + +// Callback (registered below) fired when a pulse is detected +void onBeatDetected() +{ + Serial.println("B:1"); +} + +void setup() +{ + Serial.begin(115200); + + // Initialize the PulseOximeter instance and register a beat-detected callback + // The parameter passed to the begin() method changes the samples flow that + // the library spews to the serial. + // Options: + // * PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT : filtered samples and beat detection threshold + // * PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES : sampled values coming from the sensor, with no processing + // * PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES : sampled values after the DC removal filter + + // Initialize the PulseOximeter instance + // Failures are generally due to an improper I2C wiring, missing power supply + // or wrong target chip + if (!pox.begin(PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT)) { + Serial.println("ERROR: Failed to initialize pulse oximeter"); + for(;;); + } + + pox.setOnBeatDetectedCallback(onBeatDetected); +} + +void loop() +{ + // Make sure to call update as fast as possible + pox.update(); + + // Asynchronously dump heart rate and oxidation levels to the serial + // For both, a value of 0 means "invalid" + if (millis() - tsLastReport > REPORTING_PERIOD_MS) { + Serial.print("H:"); + Serial.println(pox.getHeartRate()); + + Serial.print("O:"); + Serial.println(pox.getSpO2()); + + tsLastReport = millis(); + } +} diff --git a/examples/MAX30100_Minimal/MAX30100_Minimal.ino b/examples/MAX30102_Minimal/MAX30102_Minimal.ino similarity index 81% rename from examples/MAX30100_Minimal/MAX30100_Minimal.ino rename to examples/MAX30102_Minimal/MAX30102_Minimal.ino index 456feae..2c74a51 100644 --- a/examples/MAX30100_Minimal/MAX30100_Minimal.ino +++ b/examples/MAX30102_Minimal/MAX30102_Minimal.ino @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -17,7 +20,7 @@ along with this program. If not, see . */ #include -#include "MAX30100_PulseOximeter.h" +#include "MAX30102_PulseOximeter.h" #define REPORTING_PERIOD_MS 1000 @@ -53,9 +56,9 @@ void setup() } // The default current for the IR LED is 50mA and it could be changed - // by uncommenting the following line. Check MAX30100_Registers.h for all the + // by uncommenting the following line. Check MAX30102_Registers.h for all the // available options. - // pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA); + // pox.setIRLedCurrent(MAX30102_LED_CURR_7_6MA); // Register a callback for the beat detection pox.setOnBeatDetectedCallback(onBeatDetected); diff --git a/examples/MAX30100_RawData/MAX30100_RawData.ino b/examples/MAX30102_RawData/MAX30102_RawData.ino similarity index 66% rename from examples/MAX30100_RawData/MAX30100_RawData.ino rename to examples/MAX30102_RawData/MAX30102_RawData.ino index 5b186bc..c1a91de 100644 --- a/examples/MAX30100_RawData/MAX30100_RawData.ino +++ b/examples/MAX30102_RawData/MAX30102_RawData.ino @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -21,32 +24,32 @@ along with this program. If not, see . // Use the "Serial Plotter" app from arduino IDE 1.6.7+ to plot the output #include -#include "MAX30100.h" +#include "MAX30102.h" // Sampling is tightly related to the dynamic range of the ADC. // refer to the datasheet for further info -#define SAMPLING_RATE MAX30100_SAMPRATE_100HZ +#define SAMPLING_RATE MAX30102_SAMPRATE_100HZ // The LEDs currents must be set to a level that avoids clipping and maximises the // dynamic range -#define IR_LED_CURRENT MAX30100_LED_CURR_50MA -#define RED_LED_CURRENT MAX30100_LED_CURR_27_1MA +#define IR_LED_CURRENT 0xff +#define RED_LED_CURRENT 0x88 // The pulse width of the LEDs driving determines the resolution of // the ADC (which is a Sigma-Delta). -// set HIGHRES_MODE to true only when setting PULSE_WIDTH to MAX30100_SPC_PW_1600US_16BITS -#define PULSE_WIDTH MAX30100_SPC_PW_1600US_16BITS +// set HIGHRES_MODE to true only when setting PULSE_WIDTH to MAX30102_SPC_PW_1600US_16BITS +#define PULSE_WIDTH MAX30102_SPC_PW_411US_18BITS #define HIGHRES_MODE true -// Instantiate a MAX30100 sensor class -MAX30100 sensor; +// Instantiate a MAX30102 sensor class +MAX30102 sensor; void setup() { Serial.begin(115200); - Serial.print("Initializing MAX30100.."); + Serial.print("Initializing MAX30102.."); // Initialize the sensor // Failures are generally due to an improper I2C wiring, missing power supply @@ -59,11 +62,13 @@ void setup() } // Set up the wanted parameters - sensor.setMode(MAX30100_MODE_SPO2_HR); - sensor.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT); + sensor.setMode(MAX30102_MODE_SPO2_HR); + //sensor.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT); + sensor.setIRLedCurrent(IR_LED_CURRENT); + sensor.setRedLedCurrent(RED_LED_CURRENT); sensor.setLedsPulseWidth(PULSE_WIDTH); sensor.setSamplingRate(SAMPLING_RATE); - sensor.setHighresModeEnabled(HIGHRES_MODE); + sensor.setRangeADC(MAX30102_ADCRange_16384); } void loop() @@ -77,4 +82,4 @@ void loop() Serial.print('\t'); Serial.println(red); } -} +} \ No newline at end of file diff --git a/examples/MAX30100_Tester/MAX30100_Tester.ino b/examples/MAX30102_Tester/MAX30102_Tester.ino similarity index 80% rename from examples/MAX30100_Tester/MAX30100_Tester.ino rename to examples/MAX30102_Tester/MAX30102_Tester.ino index f24b436..29e8a69 100644 --- a/examples/MAX30100_Tester/MAX30100_Tester.ino +++ b/examples/MAX30102_Tester/MAX30102_Tester.ino @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2017 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -21,15 +24,15 @@ along with this program. If not, see . // any of the tests running fail #include -#include "MAX30100.h" +#include "MAX30102.h" -MAX30100 sensor; +MAX30102 sensor; void setup() { Serial.begin(115200); - Serial.print("Initializing MAX30100.."); + Serial.print("Initializing MAX30102.."); if (!sensor.begin()) { Serial.print("FAILED: "); @@ -50,17 +53,20 @@ void setup() } Serial.print("Enabling HR/SPO2 mode.."); - sensor.setMode(MAX30100_MODE_SPO2_HR); + sensor.setMode(MAX30102_MODE_SPO2_HR); Serial.println("done."); Serial.print("Configuring LEDs biases to 50mA.."); - sensor.setLedsCurrent(MAX30100_LED_CURR_50MA, MAX30100_LED_CURR_50MA); + sensor.setIRLedCurrent(0xff); + sensor.setRedLedCurrent(0xff); Serial.println("done."); delay(1000); Serial.print("Lowering the current to 7.6mA.."); - sensor.setLedsCurrent(MAX30100_LED_CURR_7_6MA, MAX30100_LED_CURR_7_6MA); + sensor.setIRLedCurrent(0x26); + sensor.setRedLedCurrent(0x26); + //sensor.setLedsCurrent(MAX30102_LED_CURR_7_6MA, MAX30102_LED_CURR_7_6MA); Serial.println("done."); delay(1000); @@ -117,4 +123,4 @@ void loop() Serial.print(" RED="); Serial.println(red); } -} +} \ No newline at end of file diff --git a/extras/recorder/README.md b/extras/recorder/README.md index 19f888c..0c5382c 100644 --- a/extras/recorder/README.md +++ b/extras/recorder/README.md @@ -7,10 +7,10 @@ This tool pipes a raw session from the sensor into a file for further analysis. The recorder and the analysis notebook require python and analysis libraries. Virtualenv is warmly suggested. -* Flash the example firmware MAX30100_RawData to the microcontroller board +* Flash the example firmware MAX30102_RawData to the microcontroller board * Install the required libraries - $ virtualenv max30100env - $ source max30100env/bin/activate + $ virtualenv max30102env + $ source max30102env/bin/activate $ pip install -Ur requirements.txt * Ensure the board is connected diff --git a/extras/recorder/recorder.py b/extras/recorder/recorder.py index 0f63b40..6ebc7ac 100755 --- a/extras/recorder/recorder.py +++ b/extras/recorder/recorder.py @@ -12,7 +12,7 @@ # # Data logger -# to be used in conjunction with the MAX30100_RawData example +# to be used in conjunction with the MAX30102_RawData example # diff --git a/extras/rolling_graph/README.md b/extras/rolling_graph/README.md index 3d5caf2..baab305 100644 --- a/extras/rolling_graph/README.md +++ b/extras/rolling_graph/README.md @@ -6,7 +6,7 @@ a visual inspection of the beat detection algorithm. ## Requirements * Processing 3+ (http://www.processing.org) -* Flash the example MAX30100_Debug to the target microcontroller +* Flash the example MAX30102_Debug to the target microcontroller ## Usage diff --git a/extras/rolling_graph/rolling_graph.pde b/extras/rolling_graph/rolling_graph.pde index 943af72..eeed840 100644 --- a/extras/rolling_graph/rolling_graph.pde +++ b/extras/rolling_graph/rolling_graph.pde @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor.Copyright (C) 2016 OXullo Intersecans 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 @@ -16,7 +19,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -// Grapher helper for the Arduino MAX30100 library +// Grapher helper for the Arduino MAX30102 library import processing.serial.*; @@ -24,7 +27,7 @@ import processing.serial.*; // set this to -1 to enable the auto range mode final int ABSMAX = 800; // Adjust to the serial port. Under OSX, UNO platforms and alike are auto-detected. -final String serialPort = "/dev/tty.usbmodemFD13131"; +final String serialPort = "COM3"; final int WIDTH = 1200; @@ -158,4 +161,4 @@ void serialEvent (Serial myPort) } else if (sLine.substring(0, 2).equals("I:")) { redLedCurrentIndex = int(float(sLine.substring(2))); } -} \ No newline at end of file +} diff --git a/library.json b/library.json index 959c0e8..db841b7 100644 --- a/library.json +++ b/library.json @@ -1,20 +1,20 @@ { - "name": "MAX30100lib", - "keywords": "pulse,oximetry,spo2,max30100,sensor,i2c", - "description": "Maxim-IC MAX30100 heart-rate sensor driver and pulse-oximetry components", + "name": "MAX30102lib", + "keywords": "pulse,oximetry,spo2,max30102,sensor,i2c", + "description": "Maxim-IC MAX30102 heart-rate sensor driver and pulse-oximetry components", "authors": { - "name": "OXullo Intersecans", - "email": "x@brainrapers.org", - "url": "https://github.com/oxullo/", + "name": "Shivam Gupta", + "email": "gupta.shivam1996@gmail.com", + "url": "https://github.com/thewiseguyshivam", "maintainer": true }, "repository": { "type": "git", - "url": "https://github.com/oxullo/Arduino-MAX30100" + "url": "https://github.com/thewiseguyshivam/Arduino-MAX30102" }, - "version": "1.2.1", + "version": "1.0", "frameworks": "arduino", "platforms": "atmelavr" } diff --git a/library.properties b/library.properties index 73a13f7..4bb84c3 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ -name=MAX30100lib -version=1.2.1 -author=OXullo Intersecans -maintainer=OXullo Intersecans -sentence=Maxim-IC MAX30100 heart-rate sensor driver and pulse-oximetry components -paragraph=This library exposes most of the features of the MAX30100 and offers a modular approach to calculate pulse rate and SpO2 +name=MAX30102lib +version=1.0 +author=Shivam Gupta +maintainer=Shivam Gupta +sentence=Maxim-IC MAX30102 heart-rate sensor driver and pulse-oximetry components +paragraph=This library exposes most of the features of the MAX30102 and offers a modular approach to calculate pulse rate and SpO2 category=Sensors -url=https://github.com/oxullo/Arduino-MAX30100 +url=https://github.com/thewiseguyshivam/Arduino-MAX30102 architectures=* diff --git a/src/MAX30100.cpp b/src/MAX30100.cpp deleted file mode 100644 index e0235c1..0000000 --- a/src/MAX30100.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans - -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 . -*/ - -#include - -#include "MAX30100.h" - -MAX30100::MAX30100() -{ -} - -bool MAX30100::begin() -{ - Wire.begin(); - Wire.setClock(I2C_BUS_SPEED); - - if (getPartId() != EXPECTED_PART_ID) { - return false; - } - - setMode(DEFAULT_MODE); - setLedsPulseWidth(DEFAULT_PULSE_WIDTH); - setSamplingRate(DEFAULT_SAMPLING_RATE); - setLedsCurrent(DEFAULT_IR_LED_CURRENT, DEFAULT_RED_LED_CURRENT); - setHighresModeEnabled(true); - - return true; -} - -void MAX30100::setMode(Mode mode) -{ - writeRegister(MAX30100_REG_MODE_CONFIGURATION, mode); -} - -void MAX30100::setLedsPulseWidth(LEDPulseWidth ledPulseWidth) -{ - uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION); - writeRegister(MAX30100_REG_SPO2_CONFIGURATION, (previous & 0xfc) | ledPulseWidth); -} - -void MAX30100::setSamplingRate(SamplingRate samplingRate) -{ - uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION); - writeRegister(MAX30100_REG_SPO2_CONFIGURATION, (previous & 0xe3) | (samplingRate << 2)); -} - -void MAX30100::setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent) -{ - writeRegister(MAX30100_REG_LED_CONFIGURATION, redLedCurrent << 4 | irLedCurrent); -} - -void MAX30100::setHighresModeEnabled(bool enabled) -{ - uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION); - if (enabled) { - writeRegister(MAX30100_REG_SPO2_CONFIGURATION, previous | MAX30100_SPC_SPO2_HI_RES_EN); - } else { - writeRegister(MAX30100_REG_SPO2_CONFIGURATION, previous & ~MAX30100_SPC_SPO2_HI_RES_EN); - } -} - -void MAX30100::update() -{ - readFifoData(); -} - -bool MAX30100::getRawValues(uint16_t *ir, uint16_t *red) -{ - if (!readoutsBuffer.isEmpty()) { - SensorReadout readout = readoutsBuffer.pop(); - - *ir = readout.ir; - *red = readout.red; - - return true; - } else { - return false; - } -} - -void MAX30100::resetFifo() -{ - writeRegister(MAX30100_REG_FIFO_WRITE_POINTER, 0); - writeRegister(MAX30100_REG_FIFO_READ_POINTER, 0); - writeRegister(MAX30100_REG_FIFO_OVERFLOW_COUNTER, 0); -} - -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(); -} - -void MAX30100::writeRegister(uint8_t address, uint8_t data) -{ - Wire.beginTransmission(MAX30100_I2C_ADDRESS); - Wire.write(address); - Wire.write(data); - Wire.endTransmission(); -} - -void MAX30100::burstRead(uint8_t baseAddress, uint8_t *buffer, uint8_t length) -{ - Wire.beginTransmission(MAX30100_I2C_ADDRESS); - Wire.write(baseAddress); - Wire.endTransmission(false); - Wire.requestFrom((uint8_t)MAX30100_I2C_ADDRESS, length); - - uint8_t idx = 0; - while (Wire.available()) { - buffer[idx++] = Wire.read(); - } -} - -void MAX30100::readFifoData() -{ - uint8_t buffer[MAX30100_FIFO_DEPTH*4]; - uint8_t toRead; - - toRead = (readRegister(MAX30100_REG_FIFO_WRITE_POINTER) - readRegister(MAX30100_REG_FIFO_READ_POINTER)) & (MAX30100_FIFO_DEPTH-1); - - if (toRead) { - burstRead(MAX30100_REG_FIFO_DATA, buffer, 4 * toRead); - - for (uint8_t i=0 ; i < toRead ; ++i) { - // Warning: the values are always left-aligned - readoutsBuffer.push({ - .ir=(uint16_t)((buffer[i*4] << 8) | buffer[i*4 + 1]), - .red=(uint16_t)((buffer[i*4 + 2] << 8) | buffer[i*4 + 3])}); - } - } -} - -void MAX30100::startTemperatureSampling() -{ - uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION); - modeConfig |= MAX30100_MC_TEMP_EN; - - writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig); -} - -bool MAX30100::isTemperatureReady() -{ - return !(readRegister(MAX30100_REG_MODE_CONFIGURATION) & MAX30100_MC_TEMP_EN); -} - -float MAX30100::retrieveTemperature() -{ - int8_t tempInteger = readRegister(MAX30100_REG_TEMPERATURE_DATA_INT); - float tempFrac = readRegister(MAX30100_REG_TEMPERATURE_DATA_FRAC); - - return tempFrac * 0.0625 + tempInteger; -} - -void MAX30100::shutdown() -{ - uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION); - modeConfig |= MAX30100_MC_SHDN; - - writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig); -} - -void MAX30100::resume() -{ - uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION); - modeConfig &= ~MAX30100_MC_SHDN; - - writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig); -} - -uint8_t MAX30100::getPartId() -{ - return readRegister(0xff); -} diff --git a/src/MAX30100_Registers.h b/src/MAX30100_Registers.h deleted file mode 100644 index df12be1..0000000 --- a/src/MAX30100_Registers.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans - -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 . -*/ - -#ifndef MAX30100_REGISTERS_H -#define MAX30100_REGISTERS_H - -#define MAX30100_I2C_ADDRESS 0x57 - -// 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 - -#define MAX30100_FIFO_DEPTH 0x10 - -#endif diff --git a/src/MAX30102.cpp b/src/MAX30102.cpp new file mode 100644 index 0000000..60a237a --- /dev/null +++ b/src/MAX30102.cpp @@ -0,0 +1,224 @@ +/* +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. + +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 . +*/ + +#include + +#include "MAX30102.h" + +MAX30102::MAX30102() +{ +} + +bool MAX30102::begin() +{ + Wire.begin(); + Wire.setClock(I2C_BUS_SPEED); + + if (getPartId() != EXPECTED_PART_ID) { + return false; + } + + setMode(DEFAULT_MODE); + setLedsPulseWidth(DEFAULT_PULSE_WIDTH); + setSamplingRate(DEFAULT_SAMPLING_RATE); + setRangeADC(DEFAULT_ADC_RANGE); + setRedLedCurrent(DEFAULT_RED_LED_CURRENT); + setIRLedCurrent(DEFAULT_IR_LED_CURRENT); + + return true; +} + +void MAX30102::setMode(Mode mode) +{ + uint8_t previous = readRegister(MAX30102_REG_MODE_CONFIGURATION); + writeRegister(MAX30102_REG_MODE_CONFIGURATION, (previous & 0xf8) | mode); +} + +void MAX30102::setLedsPulseWidth(LEDPulseWidth ledPulseWidth) +{ + uint8_t previous = readRegister(MAX30102_REG_SPO2_CONFIGURATION); + writeRegister(MAX30102_REG_SPO2_CONFIGURATION, (previous & 0xfc) | ledPulseWidth); +} + +void MAX30102::setSamplingRate(SamplingRate samplingRate) +{ + uint8_t previous = readRegister(MAX30102_REG_SPO2_CONFIGURATION); + writeRegister(MAX30102_REG_SPO2_CONFIGURATION, (previous & 0xe3) | (samplingRate << 2)); +} + +void MAX30102::setRedLedCurrent(uint8_t redLedCurrent) +{ + writeRegister(MAX30102_REG_LED_RED_PA, redLedCurrent); +} + +void MAX30102::setIRLedCurrent(uint8_t IRLedCurrent) +{ + writeRegister(MAX30102_REG_LED_IR_PA, IRLedCurrent); +} + +void MAX30102::setSlot1(SlotSetting slotsetting) +{ + uint8_t previous = readRegister(MAX30102_REG_MULTI_LED_CTRL_1AND2); + writeRegister(MAX30102_REG_MULTI_LED_CTRL_1AND2, (previous & 0xf8) | slotsetting); +} + +void MAX30102::setSlot2(SlotSetting slotsetting) +{ + uint8_t previous = readRegister(MAX30102_REG_MULTI_LED_CTRL_1AND2); + writeRegister(MAX30102_REG_MULTI_LED_CTRL_1AND2, (previous & 0x8f) | slotsetting); +} + +void MAX30102::setSlot3(SlotSetting slotsetting) +{ + uint8_t previous = readRegister(MAX30102_REG_MULTI_LED_CTRL_3AND4); + writeRegister(MAX30102_REG_MULTI_LED_CTRL_3AND4, (previous & 0xf8) | slotsetting); +} + +void MAX30102::setSlot4(SlotSetting slotsetting) +{ + uint8_t previous = readRegister(MAX30102_REG_MULTI_LED_CTRL_3AND4); + writeRegister(MAX30102_REG_MULTI_LED_CTRL_3AND4, (previous & 0x8f) | slotsetting); +} + +void MAX30102::setRangeADC(ADCRange adcRange) +{ + uint8_t previous = readRegister(MAX30102_REG_SPO2_CONFIGURATION); + writeRegister(MAX30102_REG_SPO2_CONFIGURATION, (previous & 0x9f) | (adcRange << 5)); +} + +void MAX30102::update() +{ + readFifoData(); +} + +bool MAX30102::getRawValues(uint16_t *ir, uint16_t *red) +{ + if (!readoutsBuffer.isEmpty()) { + SensorReadout readout = readoutsBuffer.pop(); + + *ir = readout.ir; + *red = readout.red; + + return true; + } else { + return false; + } +} + +void MAX30102::resetFifo() +{ + writeRegister(MAX30102_REG_FIFO_WRITE_POINTER, 0); + writeRegister(MAX30102_REG_FIFO_READ_POINTER, 0); + writeRegister(MAX30102_REG_FIFO_OVERFLOW_COUNTER, 0); +} + +uint8_t MAX30102::readRegister(uint8_t address) +{ + Wire.beginTransmission(MAX30102_I2C_ADDRESS); + Wire.write(address); + Wire.endTransmission(false); + Wire.requestFrom(MAX30102_I2C_ADDRESS, 1); + + return Wire.read(); +} + +void MAX30102::writeRegister(uint8_t address, uint8_t data) +{ + Wire.beginTransmission(MAX30102_I2C_ADDRESS); + Wire.write(address); + Wire.write(data); + Wire.endTransmission(); +} + +void MAX30102::burstRead(uint8_t baseAddress, uint8_t *buffer, uint8_t length) +{ + Wire.beginTransmission(MAX30102_I2C_ADDRESS); + Wire.write(baseAddress); + Wire.endTransmission(false); + Wire.requestFrom((uint8_t)MAX30102_I2C_ADDRESS, length); + + uint8_t idx = 0; + while (Wire.available()) { + buffer[idx++] = Wire.read(); + } +} + +void MAX30102::readFifoData() +{ + uint8_t buffer[MAX30102_FIFO_DEPTH*4]; + uint8_t toRead; + + toRead = (readRegister(MAX30102_REG_FIFO_WRITE_POINTER) - readRegister(MAX30102_REG_FIFO_READ_POINTER)) & (MAX30102_FIFO_DEPTH-1); + + if (toRead) { + burstRead(MAX30102_REG_FIFO_DATA, buffer, 4 * toRead); + + for (uint8_t i=0 ; i < toRead ; ++i) { + // Warning: the values are always left-aligned + readoutsBuffer.push({ + .ir=(uint16_t)((buffer[i*4] << 8) | buffer[i*4 + 1]), + .red=(uint16_t)((buffer[i*4 + 2] << 8) | buffer[i*4 + 3])}); + } + } +} + + +void MAX30102::startTemperatureSampling() +{ + uint8_t modeConfig = readRegister(MAX30102_REG_TEMP_CONFIG); + modeConfig |= MAX30102_TC_TEMP_EN; + + writeRegister(MAX30102_REG_TEMP_CONFIG, modeConfig); +} + +bool MAX30102::isTemperatureReady() +{ + return !(readRegister(MAX30102_REG_TEMP_CONFIG) & MAX30102_TC_TEMP_EN); +} + +float MAX30102::retrieveTemperature() +{ + int8_t tempInteger = readRegister(MAX30102_REG_TEMPERATURE_DATA_INT); + float tempFrac = readRegister(MAX30102_REG_TEMPERATURE_DATA_FRAC); + + return tempFrac * 0.0625 + tempInteger; +} + +void MAX30102::shutdown() +{ + uint8_t modeConfig = readRegister(MAX30102_REG_MODE_CONFIGURATION); + modeConfig |= MAX30102_MC_SHDN; + + writeRegister(MAX30102_REG_MODE_CONFIGURATION, modeConfig); +} + +void MAX30102::resume() +{ + uint8_t modeConfig = readRegister(MAX30102_REG_MODE_CONFIGURATION); + modeConfig &= ~MAX30102_MC_SHDN; + + writeRegister(MAX30102_REG_MODE_CONFIGURATION, modeConfig); +} + +uint8_t MAX30102::getPartId() +{ + return readRegister(0xff); +} diff --git a/src/MAX30100.h b/src/MAX30102.h similarity index 57% rename from src/MAX30100.h rename to src/MAX30102.h index f7fa179..ab4f2b0 100644 --- a/src/MAX30100.h +++ b/src/MAX30102.h @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -16,22 +19,25 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef MAX30100_H -#define MAX30100_H +#ifndef MAX30102_H +#define MAX30102_H #include #define CIRCULAR_BUFFER_XS #include "CircularBuffer.h" -#include "MAX30100_Registers.h" +#include "MAX30102_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 EXPECTED_PART_ID 0x11 -#define RINGBUFFER_SIZE 16 +#define DEFAULT_MODE MAX30102_MODE_HRONLY +#define DEFAULT_SAMPLING_RATE MAX30102_SAMPRATE_100HZ +#define DEFAULT_PULSE_WIDTH MAX30102_SPC_PW_118US_16BITS +#define DEFAULT_RED_LED_CURRENT 0xff +#define DEFAULT_IR_LED_CURRENT 0xff +#define DEFAULT_ADC_RANGE MAX30102_ADCRange_8192 +//Max30102 part ID is 0x15 +#define EXPECTED_PART_ID 0x15 +//Max30102 fifo size is 32 +#define RINGBUFFER_SIZE 32 #define I2C_BUS_SPEED 400000UL @@ -40,14 +46,20 @@ typedef struct { uint16_t red; } SensorReadout; -class MAX30100 { +class MAX30102 { public: - MAX30100(); + MAX30102(); bool begin(); void setMode(Mode mode); void setLedsPulseWidth(LEDPulseWidth ledPulseWidth); void setSamplingRate(SamplingRate samplingRate); - void setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent); + void setRangeADC(ADCRange adcRange); + void setRedLedCurrent(uint8_t redLedCurrent); + void setIRLedCurrent(uint8_t IRLedCurrent); + void setSlot1(SlotSetting slotsetting); + void setSlot2(SlotSetting slotsetting); + void setSlot3(SlotSetting slotsetting); + void setSlot4(SlotSetting slotsetting); void setHighresModeEnabled(bool enabled); void update(); bool getRawValues(uint16_t *ir, uint16_t *red); diff --git a/src/MAX30100_BeatDetector.cpp b/src/MAX30102_BeatDetector.cpp similarity index 90% rename from src/MAX30100_BeatDetector.cpp rename to src/MAX30102_BeatDetector.cpp index 0f3c797..12beb0b 100644 --- a/src/MAX30100_BeatDetector.cpp +++ b/src/MAX30102_BeatDetector.cpp @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -18,7 +21,7 @@ along with this program. If not, see . #include -#include "MAX30100_BeatDetector.h" +#include "MAX30102_BeatDetector.h" #ifndef min #define min(a,b) \ diff --git a/src/MAX30100_BeatDetector.h b/src/MAX30102_BeatDetector.h similarity index 84% rename from src/MAX30100_BeatDetector.h rename to src/MAX30102_BeatDetector.h index 2d11247..b8a2fb5 100644 --- a/src/MAX30100_BeatDetector.h +++ b/src/MAX30102_BeatDetector.h @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -16,8 +19,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef MAX30100_BEATDETECTOR_H -#define MAX30100_BEATDETECTOR_H +#ifndef MAX30102_BEATDETECTOR_H +#define MAX30102_BEATDETECTOR_H #include diff --git a/src/MAX30100_Filters.h b/src/MAX30102_Filters.h similarity index 78% rename from src/MAX30100_Filters.h rename to src/MAX30102_Filters.h index dd48a56..193ad85 100644 --- a/src/MAX30100_Filters.h +++ b/src/MAX30102_Filters.h @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -16,8 +19,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef MAX30100_FILTERS_H -#define MAX30100_FILTERS_H +#ifndef MAX30102_FILTERS_H +#define MAX30102_FILTERS_H // http://www.schwietering.com/jayduino/filtuino/ // Low pass butterworth filter order=1 alpha1=0.1 diff --git a/src/MAX30100_PulseOximeter.cpp b/src/MAX30102_PulseOximeter.cpp similarity index 85% rename from src/MAX30100_PulseOximeter.cpp rename to src/MAX30102_PulseOximeter.cpp index a7bfe61..4f487ef 100644 --- a/src/MAX30100_PulseOximeter.cpp +++ b/src/MAX30102_PulseOximeter.cpp @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -18,7 +21,7 @@ along with this program. If not, see . #include -#include "MAX30100_PulseOximeter.h" +#include "MAX30102_PulseOximeter.h" PulseOximeter::PulseOximeter() : @@ -46,8 +49,9 @@ bool PulseOximeter::begin(PulseOximeterDebuggingMode debuggingMode_) return false; } - hrm.setMode(MAX30100_MODE_SPO2_HR); - hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex); + hrm.setMode(MAX30102_MODE_SPO2_HR); + hrm.setIRLedCurrent(irLedCurrent); + hrm.setRedLedCurrent((uint8_t)redLedCurrentIndex); irDCRemover = DCRemover(DC_REMOVER_ALPHA); redDCRemover = DCRemover(DC_REMOVER_ALPHA); @@ -85,10 +89,11 @@ void PulseOximeter::setOnBeatDetectedCallback(void (*cb)()) onBeatDetected = cb; } -void PulseOximeter::setIRLedCurrent(LEDCurrent irLedNewCurrent) +void PulseOximeter::setIRLedCurrent(uint8_t irLedNewCurrent) { irLedCurrent = irLedNewCurrent; - hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex); + hrm.setIRLedCurrent(irLedCurrent); + hrm.setRedLedCurrent((uint8_t)redLedCurrentIndex); } void PulseOximeter::shutdown() @@ -160,7 +165,7 @@ void PulseOximeter::checkCurrentBias() // red and IR leds. The numbers are really magic: the less possible to avoid oscillations if (millis() - tsLastBiasCheck > CURRENT_ADJUSTMENT_PERIOD_MS) { bool changed = false; - if (irDCRemover.getDCW() - redDCRemover.getDCW() > 70000 && redLedCurrentIndex < MAX30100_LED_CURR_50MA) { + if (irDCRemover.getDCW() - redDCRemover.getDCW() > 70000 && redLedCurrentIndex < 0xff) { ++redLedCurrentIndex; changed = true; } else if (redDCRemover.getDCW() - irDCRemover.getDCW() > 70000 && redLedCurrentIndex > 0) { @@ -169,7 +174,8 @@ void PulseOximeter::checkCurrentBias() } if (changed) { - hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex); + hrm.setIRLedCurrent(irLedCurrent); + hrm.setRedLedCurrent((uint8_t)redLedCurrentIndex); tsLastCurrentAdjustment = millis(); if (debuggingMode != PULSEOXIMETER_DEBUGGINGMODE_NONE) { diff --git a/src/MAX30100_PulseOximeter.h b/src/MAX30102_PulseOximeter.h similarity index 73% rename from src/MAX30100_PulseOximeter.h rename to src/MAX30102_PulseOximeter.h index 7fa690a..1e9e56e 100644 --- a/src/MAX30100_PulseOximeter.h +++ b/src/MAX30102_PulseOximeter.h @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -16,21 +19,21 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef MAX30100_PULSEOXIMETER_H -#define MAX30100_PULSEOXIMETER_H +#ifndef MAX30102_PULSEOXIMETER_H +#define MAX30102_PULSEOXIMETER_H #define SAMPLING_FREQUENCY 100 #define CURRENT_ADJUSTMENT_PERIOD_MS 500 -#define DEFAULT_IR_LED_CURRENT MAX30100_LED_CURR_50MA -#define RED_LED_CURRENT_START MAX30100_LED_CURR_27_1MA +#define DEFAULT_IR_LED_CURRENT 0xFF //51mA +#define RED_LED_CURRENT_START 0x88 //27mA #define DC_REMOVER_ALPHA 0.95 #include -#include "MAX30100.h" -#include "MAX30100_BeatDetector.h" -#include "MAX30100_Filters.h" -#include "MAX30100_SpO2Calculator.h" +#include "MAX30102.h" +#include "MAX30102_BeatDetector.h" +#include "MAX30102_Filters.h" +#include "MAX30102_SpO2Calculator.h" typedef enum PulseOximeterState { PULSEOXIMETER_STATE_INIT, @@ -56,7 +59,7 @@ class PulseOximeter { uint8_t getSpO2(); uint8_t getRedLedCurrentBias(); void setOnBeatDetectedCallback(void (*cb)()); - void setIRLedCurrent(LEDCurrent irLedCurrent); + void setIRLedCurrent(uint8_t irLedCurrent); void shutdown(); void resume(); @@ -75,9 +78,9 @@ class PulseOximeter { DCRemover redDCRemover; FilterBuLp1 lpf; uint8_t redLedCurrentIndex; - LEDCurrent irLedCurrent; + uint8_t irLedCurrent; SpO2Calculator spO2calculator; - MAX30100 hrm; + MAX30102 hrm; void (*onBeatDetected)(); }; diff --git a/src/MAX30102_Registers.h b/src/MAX30102_Registers.h new file mode 100644 index 0000000..b981a28 --- /dev/null +++ b/src/MAX30102_Registers.h @@ -0,0 +1,158 @@ +/* +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. + +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 . +*/ + +#ifndef MAX30102_REGISTERS_H +#define MAX30102_REGISTERS_H + +#define MAX30102_I2C_ADDRESS 0x57 + +// Interrupt status register (RO) +#define MAX30102_REG_INTERRUPT_STATUS_A 0x00 +#define MAX30102_IS_PWR_RDY (1 << 0) +#define MAX30102_IS_ALC_OVF (1 << 5) +#define MAX30102_IS_PPG_RDY (1 << 6) +#define MAX30102_IS_A_FULL (1 << 7) + +// Interrupt status register (R1) +#define MAX30102_REG_INTERRUPT_STATUS_B 0x01 +#define MAX30102_IS_TEMP_RDY (1 << 1) + +// Interrupt enable register E1 +#define MAX30102_REG_INTERRUPT_ENABLE_A 0x02 +#define MAX30102_IE_ENB_ALC_OVF (1 << 5) +#define MAX30102_IE_ENB_PPG_RDY (1 << 6) +#define MAX30102_IE_ENB_A_FULL (1 << 7) + +// Interrupt enable register E2 +#define MAX30102_REG_INTERRUPT_ENABLE_B 0x03 +#define MAX30102_IE_ENB_TEMP_RDY (1 << 1) + +// FIFO control and data registers +#define MAX30102_REG_FIFO_WRITE_POINTER 0x04 +#define MAX30102_REG_FIFO_OVERFLOW_COUNTER 0x05 +#define MAX30102_REG_FIFO_READ_POINTER 0x06 +#define MAX30102_REG_FIFO_DATA 0x07 // Burst read does not autoincrement addr + +//FIFO config registers +#define MAX30102_REG_FIFO_CONFIG 0x08 +#define MAX30102_FC_FIFO_ROLLOVER_EN 1 << 4 +typedef enum FIFO_A_Full { + MAX30102_FC_FIFO_A_FULL_0 = 0x0, + MAX30102_FC_FIFO_A_FULL_1 = 0x1, + MAX30102_FC_FIFO_A_FULL_2 = 0x2, + MAX30102_FC_FIFO_A_FULL_3 = 0x3, + MAX30102_FC_FIFO_A_FULL_4 = 0x4, + MAX30102_FC_FIFO_A_FULL_5 = 0x5, + MAX30102_FC_FIFO_A_FULL_6 = 0x6, + MAX30102_FC_FIFO_A_FULL_7 = 0x7, + MAX30102_FC_FIFO_A_FULL_8 = 0x8, + MAX30102_FC_FIFO_A_FULL_9 = 0x9, + MAX30102_FC_FIFO_A_FULL_10 = 0xA, + MAX30102_FC_FIFO_A_FULL_11 = 0xB, + MAX30102_FC_FIFO_A_FULL_12 = 0xC, + MAX30102_FC_FIFO_A_FULL_15 = 0xF, + MAX30102_FC_FIFO_A_FULL_13 = 0xD, + MAX30102_FC_FIFO_A_FULL_14 = 0xE + +} FIFO_A_Full; + +typedef enum SampleAverage { + MAX30102_SMP_AVE_1 = 0x0, + MAX30102_SMP_AVE_2 = 0x1, + MAX30102_SMP_AVE_4 = 0x2, + MAX30102_SMP_AVE_8 = 0x3, + MAX30102_SMP_AVE_16 = 0x4, + MAX30102_SMP_AVE_32 = 0x5 +} SampleAverage; + + +// Mode Configuration register +#define MAX30102_REG_MODE_CONFIGURATION 0x09 +#define MAX30102_MC_RESET (1 << 6) +#define MAX30102_MC_SHDN (1 << 7) +typedef enum Mode { + MAX30102_MODE_HRONLY = 0x02, + MAX30102_MODE_SPO2_HR = 0x03, + MAX30102_MODE_MULTI = 0x07 +} Mode; + +// SpO2 Configuration register +// Check tables 8 and 9, p19 of the MAX30102 datasheet to see the permissible +// combinations of sampling rates and pulse widths +#define MAX30102_REG_SPO2_CONFIGURATION 0x0A + +typedef enum ADCRange { + MAX30102_ADCRange_2048 = 0x0, + MAX30102_ADCRange_4096 = 0x1, + MAX30102_ADCRange_8192 = 0x2, + MAX30102_ADCRange_16384 = 0x3, +} ADCRange; + +typedef enum SamplingRate { + MAX30102_SAMPRATE_50HZ = 0x00, + MAX30102_SAMPRATE_100HZ = 0x01, + MAX30102_SAMPRATE_167HZ = 0x02, + MAX30102_SAMPRATE_200HZ = 0x03, + MAX30102_SAMPRATE_400HZ = 0x04, + MAX30102_SAMPRATE_600HZ = 0x05, + MAX30102_SAMPRATE_800HZ = 0x06, + MAX30102_SAMPRATE_1000HZ = 0x07 +} SamplingRate; + +typedef enum LEDPulseWidth { + MAX30102_SPC_PW_69US_15BITS = 0x00, + MAX30102_SPC_PW_118US_16BITS = 0x01, + MAX30102_SPC_PW_215US_17BITS = 0x02, + MAX30102_SPC_PW_411US_18BITS = 0x03 +} LEDPulseWidth; + +// LED Configuration registers +#define MAX30102_REG_LED_RED_PA 0x0C +#define MAX30102_REG_LED_IR_PA 0x0D + +// Multi LED Mode Control registers, refer page 21 of datasheet +#define MAX30102_REG_MULTI_LED_CTRL_1AND2 0x11 +#define MAX30102_REG_MULTI_LED_CTRL_3AND4 0x12 + +typedef enum SlotSetting { + MAX30102_SLOT_SETTING_OFF = 0x0, + MAX30102_SLOT_SETTING_RED = 0x1, + MAX30102_SLOT_SETTING_IR = 0x1 +} SlotSetting; + + +// Temperature integer part register +#define MAX30102_REG_TEMPERATURE_DATA_INT 0x1F +// Temperature fractional part register +#define MAX30102_REG_TEMPERATURE_DATA_FRAC 0x20 + +//Temperature emable +#define MAX30102_REG_TEMP_CONFIG 0x21 +#define MAX30102_TC_TEMP_EN 1 << 0 + +// Revision ID register (RO) +#define MAX30102_REG_REVISION_ID 0xfe +// Part ID register +#define MAX30102_REG_PART_ID 0xff + +#define MAX30102_FIFO_DEPTH 0x20 + +#endif diff --git a/src/MAX30100_SpO2Calculator.cpp b/src/MAX30102_SpO2Calculator.cpp similarity index 84% rename from src/MAX30100_SpO2Calculator.cpp rename to src/MAX30102_SpO2Calculator.cpp index c15c572..4c4a072 100644 --- a/src/MAX30100_SpO2Calculator.cpp +++ b/src/MAX30102_SpO2Calculator.cpp @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -18,7 +21,7 @@ along with this program. If not, see . #include -#include "MAX30100_SpO2Calculator.h" +#include "MAX30102_SpO2Calculator.h" // SaO2 Look-up Table // http://www.ti.com/lit/an/slaa274b/slaa274b.pdf diff --git a/src/MAX30100_SpO2Calculator.h b/src/MAX30102_SpO2Calculator.h similarity index 72% rename from src/MAX30100_SpO2Calculator.h rename to src/MAX30102_SpO2Calculator.h index 9044888..c618076 100644 --- a/src/MAX30100_SpO2Calculator.h +++ b/src/MAX30102_SpO2Calculator.h @@ -1,6 +1,9 @@ /* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans +Arduino-MAX30102 oximetry / heart rate integrated sensor library by Shivam Gupta (gupta.shivam1996@gmail.com) + +Based on MAX30100 library, Copyright (C) 2016 OXullo Intersecans +All alogrithms and methods used are from the above author, +I have only modified this enough to make it work with the new MAX30102 sensor. 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 @@ -16,8 +19,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef MAX30100_SPO2CALCULATOR_H -#define MAX30100_SPO2CALCULATOR_H +#ifndef MAX30102_SPO2CALCULATOR_H +#define MAX30102_SPO2CALCULATOR_H #include