Skip to content

Commit

Permalink
Rev2.01: Made conditional all parts of code specific to M0 Adalogger
Browse files Browse the repository at this point in the history
Revision 2.00 of this code was written specifically for the Adafruit M0
Adalogger microcontroller. By popular demand, all lines of the code
specific to this chip are now wrapped in a conditional triggered by
USE_ADALOGGER define. Comment this define if you want to use another
MCU, but read the warning included in README before you do that!
  • Loading branch information
aromring committed Aug 23, 2018
1 parent 8c87c6b commit 60800c3
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 26 deletions.
113 changes: 87 additions & 26 deletions RD117_ARDUINO.ino
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Revision History:
*\n 1-18-2016 Rev 01.00 GL Initial release.
*\n 12-22-2017 Rev 02.00 Significantlly modified by Robert Fraczkiewicz
*\n 08-22-2018 Rev 02.01 Added conditional compilation of the code related to ADALOGGER SD card operations
*
* --------------------------------------------------------------------
*
Expand All @@ -31,28 +32,36 @@
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include "algorithm_by_RF.h"
#include "max30102.h"

//#define DEBUG // Uncomment for debug output to the Serial stream
#define USE_ADALOGGER // Comment out if you don't have ADALOGGER itself but your MCU still can handle this code
//#define TEST_MAXIM_ALGORITHM // Uncomment if you want to include results returned by the original MAXIM algorithm
//#define SAVE_RAW_DATA // Uncomment if you want raw data coming out of the sensor saved to SD card. Red signal first, IR second.

#ifdef USE_ADALOGGER
#include <SD.h>
#endif

#ifdef TEST_MAXIM_ALGORITHM
#include "algorithm.h"
#endif

File dataFile;
// Interrupt pin
const byte oxiInt = 10; // pin connected to MAX30102 INT

// ADALOGGER pins
const byte chipSelect = 4;
const byte cardDetect = 7;
const byte batteryPin = 9;
const byte ledPin = 13; // Red LED on ADALOGGER
const byte sdIndicatorPin = 8; // Green LED on ADALOGGER
const byte oxiInt = 10; // ADALOGGER pin connected to MAX30102 INT
#ifdef USE_ADALOGGER
File dataFile;
const byte chipSelect = 4;
const byte cardDetect = 7;
const byte batteryPin = 9;
const byte ledPin = 13; // Red LED on ADALOGGER
const byte sdIndicatorPin = 8; // Green LED on ADALOGGER
bool cardOK;
#endif

bool cardOK;
uint32_t elapsedTime,timeStart;

uint32_t aun_ir_buffer[BUFFER_SIZE]; //infrared LED sensor data
Expand All @@ -62,17 +71,20 @@ uint8_t uch_dummy,k;

void setup() {

pinMode(oxiInt, INPUT); //pin D10 connects to the interrupt output pin of the MAX30102

#ifdef USE_ADALOGGER
pinMode(cardDetect,INPUT_PULLUP);
pinMode(batteryPin,INPUT);
pinMode(oxiInt, INPUT); //pin D10 connects to the interrupt output pin of the MAX30102
pinMode(ledPin,OUTPUT);
digitalWrite(ledPin,LOW);
pinMode(sdIndicatorPin,OUTPUT);
digitalWrite(sdIndicatorPin,LOW);
#endif

Wire.begin();

#ifdef DEBUG
#if defined(DEBUG) || !defined(USE_ADALOGGER)
// initialize serial communication at 115200 bits per second:
Serial.begin(115200);
#endif
Expand All @@ -81,7 +93,10 @@ void setup() {
delay(1000);

maxim_max30102_read_reg(REG_INTR_STATUS_1,&uch_dummy); //Reads/clears the interrupt status register
maxim_max30102_init(); //initialize the MAX30102
old_n_spo2=0.0;

#ifdef USE_ADALOGGER
// Measure battery voltage
float measuredvbat = analogRead(batteryPin);
measuredvbat *= 2; // we divided by 2, so multiply back
Expand Down Expand Up @@ -129,18 +144,16 @@ void setup() {
#endif

blinkLED(ledPin,cardOK);
old_n_spo2=0.0;
maxim_max30102_init(); //initialize the MAX30102

k=0;
dataFile.println(F("Vbatt=\t"));
dataFile.println(measuredvbat);
dataFile.println(my_status);
#ifdef TEST_MAXIM_ALGORITHM
dataFile.print(F("Time[s]\tSpO2\tHR\tSpO2_MX\tHR_MX\tClock\tRatio\tCorr"));
#else
#else // TEST_MAXIM_ALGORITHM
dataFile.print(F("Time[s]\tSpO2\tHR\tClock\tRatio\tCorr"));
#endif
#endif // TEST_MAXIM_ALGORITHM
#ifdef SAVE_RAW_DATA
int32_t i;
// These are headers for the red signal
Expand All @@ -153,8 +166,20 @@ void setup() {
dataFile.print("\t");
dataFile.print(i);
}
#endif
#endif // SAVE_RAW_DATA
dataFile.println("");

#else // USE_ADALOGGER

while(Serial.available()==0) //wait until user presses a key
{
Serial.println(F("Press any key to start conversion"));
delay(1000);
}
uch_dummy=Serial.read();

#endif // USE_ADALOGGER

timeStart=millis();
}

Expand All @@ -180,7 +205,7 @@ void loop() {
Serial.print(F("\t"));
Serial.print(aun_ir_buffer[i], DEC);
Serial.println("");
#endif
#endif // DEBUG
}

//calculate heart rate and SpO2 after BUFFER_SIZE samples (ST seconds of samples) using Robert's method
Expand All @@ -199,7 +224,7 @@ void loop() {
Serial.print("\t");
Serial.println(hr_str);
Serial.println("------");
#endif
#endif // DEBUG

#ifdef TEST_MAXIM_ALGORITHM
//calculate heart rate and SpO2 after BUFFER_SIZE samples (ST seconds of samples) using MAXIM's method
Expand All @@ -218,15 +243,16 @@ void loop() {
Serial.print("\t");
Serial.println(hr_str);
Serial.println("------");
#endif
#endif
#endif // DEBUG
#endif // TEST_MAXIM_ALGORITHM

//save samples and calculation result to SD card
#ifdef TEST_MAXIM_ALGORITHM
if(ch_hr_valid && ch_spo2_valid || ch_hr_valid_maxim && ch_spo2_valid_maxim) {
#else
#else // TEST_MAXIM_ALGORITHM
if(ch_hr_valid && ch_spo2_valid) {
#endif
#endif // TEST_MAXIM_ALGORITHM
#ifdef USE_ADALOGGER
++k;
dataFile.print(elapsedTime);
dataFile.print("\t");
Expand All @@ -239,7 +265,7 @@ void loop() {
dataFile.print("\t");
dataFile.print(n_heart_rate_maxim, DEC);
dataFile.print("\t");
#endif
#endif // TEST_MAXIM_ALGORITHM
dataFile.print(hr_str);
dataFile.print("\t");
dataFile.print(ratio);
Expand All @@ -257,10 +283,9 @@ void loop() {
dataFile.print(F("\t"));
dataFile.print(aun_ir_buffer[i], DEC);
}
#endif
#endif // SAVE_RAW_DATA
dataFile.println("");
old_n_spo2=n_spo2;
// Blink green LED to indicate save event
// Blink green LED to indicate save event
digitalWrite(sdIndicatorPin,HIGH);
delay(10);
digitalWrite(sdIndicatorPin,LOW);
Expand All @@ -269,6 +294,40 @@ void loop() {
dataFile.flush();
k=0;
}
#else // USE_ADALOGGER
Serial.print(elapsedTime);
Serial.print("\t");
Serial.print(n_spo2);
Serial.print("\t");
Serial.print(n_heart_rate, DEC);
Serial.print("\t");
#ifdef TEST_MAXIM_ALGORITHM
Serial.print(n_spo2_maxim);
Serial.print("\t");
Serial.print(n_heart_rate_maxim, DEC);
Serial.print("\t");
#endif //TEST_MAXIM_ALGORITHM
Serial.print(hr_str);
Serial.print("\t");
Serial.print(ratio);
Serial.print("\t");
Serial.print(correl);
#ifdef SAVE_RAW_DATA
// Save raw data for unusual O2 levels
for(i=0;i<BUFFER_SIZE;++i)
{
Serial.print(F("\t"));
Serial.print(aun_red_buffer[i], DEC);
}
for(i=0;i<BUFFER_SIZE;++i)
{
Serial.print(F("\t"));
Serial.print(aun_ir_buffer[i], DEC);
}
#endif // SAVE_RAW_DATA
Serial.println("");
#endif // USE_ADALOGGER
old_n_spo2=n_spo2;
}
}

Expand All @@ -290,6 +349,7 @@ void millis_to_hours(uint32_t ms, char* hr_str)
strcat(hr_str,istr);
}

#ifdef USE_ADALOGGER
// blink three times if isOK is true, otherwise blink continuously
void blinkLED(const byte led, bool isOK)
{
Expand All @@ -313,4 +373,5 @@ void blinkLED(const byte led, bool isOK)
}
}
}
#endif

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ const float min_autocorrelation_ratio;
const float min_pearson_correlation;

Values of these constants determine the severity of quality filter applied to raw signals emitted by MAX30102. Generally, the higher their values, the more strict the filter will be. Details can be found in this project's Instructable.

The RD117_ARDUINO.ino contains several defines that will enable/disable debug printing, testing of the original MAXIM algorithm, saving raw data, and most importantly whether or not you use Adafruit Feather M0 Adalogger as your MCU. Disable the latter option if you want to use an alternative microcontroller. But I have to give you a fair warning: Feather M0's features an ATSAMD21G18 ARM Cortex M0 processor, clocked at 48 MHz and with a whopping 256K of FLASH (8x more than the Atmega328 or 32u4) and 32K of RAM (16x as much). As such, it can handle this code without a drop of sweat. Lesser MCUs may have serious problems with it, especially in terms of sufficient memory.

0 comments on commit 60800c3

Please sign in to comment.