Maxim Integrated's IoT development kit.

Dependencies:   MAX30101 MAX30003 MAX113XX_Pixi MAX30205 max32630fthr USBDevice

Revision:
13:fba77a5d0fa0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/max30101_app.cpp	Thu Jun 28 15:47:24 2018 +0300
@@ -0,0 +1,270 @@
+/*
+ * max30101_app.cpp
+ *
+ *  Created on: Jun 20, 2018
+ *      Author: Mahir.Ozturk
+ */
+#include <mbed.h>
+#include "max30101_app.h"
+#include "MAX30101.h"
+#include "max30101_algo.h"
+
+#define MAX30101_IRQ_ASSERTED_ID	1
+
+#define MAX30101_BUFFER_LEN			500
+
+static Thread *thread = 0;
+
+//variable for the algorithm
+uint16_t sampleRate = 100;
+uint16_t compSpO2 = 1;
+int16_t ir_ac_comp = 0;
+int16_t red_ac_comp = 0;
+int16_t green_ac_comp = 0;
+int16_t ir_ac_mag = 0;
+int16_t red_ac_mag = 0;
+int16_t green_ac_mag = 0;
+uint16_t HRbpm2 = 0;
+uint16_t SpO2B = 0;
+uint16_t DRdy = 0;
+
+//declare large variables outside of main
+uint32_t redData[MAX30101_BUFFER_LEN];//set array to max fifo size
+uint32_t irData[MAX30101_BUFFER_LEN];//set array to max fifo size
+uint32_t greenData[MAX30101_BUFFER_LEN];//set array to max fifo size
+
+bool max30101_config(MAX30101 &op_sensor)
+{
+	//Reset Device
+	MAX30101::ModeConfiguration_u modeConfig;
+	modeConfig.all = 0;
+	modeConfig.bits.reset = 1;
+	modeConfig.bits.mode = MAX30101::MultiLedMode;     // Sets SPO2 Mode
+	int32_t rc = op_sensor.setModeConfiguration(modeConfig);
+
+	//enable MAX30101 interrupts
+	MAX30101::InterruptBitField_u ints;
+	if (rc == 0) {
+		ints.all = 0;
+		ints.bits.a_full = 1;       // Enable FIFO almost full interrupt
+		ints.bits.ppg_rdy =1;       //Enables an interrupt when a new sample is ready
+		rc = op_sensor.enableInterrupts(ints);
+	}
+
+	//configure FIFO
+	MAX30101::FIFO_Configuration_u fifoConfig;
+	if (rc == 0) {
+		fifoConfig.all = 0;
+		fifoConfig.bits.fifo_a_full = 10;                            // Max level of 17 samples
+		fifoConfig.bits.sample_average = MAX30101::AveragedSamples_0;// Average 0 samples
+		rc = op_sensor.setFIFOConfiguration(fifoConfig);
+	}
+
+	MAX30101::SpO2Configuration_u spo2Config;
+	if (rc == 0) {
+		spo2Config.all = 0;                                 // clears register
+		spo2Config.bits.spo2_adc_range = 1;                 //sets resolution to 4096 nAfs
+		spo2Config.bits.spo2_sr = MAX30101::SR_100_Hz;     // SpO2 SR = 100Hz
+		spo2Config.bits.led_pw = MAX30101::PW_3;            // 18-bit ADC resolution ~400us
+		rc = op_sensor.setSpO2Configuration(spo2Config);
+	}
+
+	//Set time slots for LEDS
+	MAX30101::ModeControlReg_u multiLED;
+	if (rc == 0) {
+		//sets timing for control register 1
+		multiLED.bits.lo_slot=1;
+		multiLED.bits.hi_slot=2;
+		rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg1, multiLED);
+		if (rc == 0) {
+			multiLED.bits.lo_slot=3;
+			multiLED.bits.hi_slot=0;
+			rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg2, multiLED);
+		}
+	}
+
+	//Set LED drive currents
+	if (rc == 0) {
+		// Heart Rate only, 1 LED channel, Pulse amp. = ~7mA
+		rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED1_PA, 0x24);
+		//To include SPO2, 2 LED channel, Pulse amp. ~7mA
+		if (rc == 0) {
+			rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED2_PA, 0x24);
+		}
+		if (rc == 0) {
+			rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED3_PA, 0x24);
+		}
+	}
+
+	//Set operating mode
+	modeConfig.all = 0;
+	if (rc == 0) {
+		modeConfig.bits.mode = MAX30101::MultiLedMode;     // Sets multiLED mode
+		rc = op_sensor.setModeConfiguration(modeConfig);
+	}
+
+	return rc;
+}
+
+void max30101wing_pmic_config(I2C & i2c_bus, DigitalOut & pmic_en)
+{
+	const uint8_t PMIC_ADRS = 0x54;
+	const uint8_t BBB_EXTRA_ADRS = 0x1C;
+	const uint8_t BOOST_VOLTAGE = 0x05;
+
+	char data_buff[] = {BBB_EXTRA_ADRS, 0x40};    //BBBExtra register address
+	//and data to enable passive
+	//pull down.
+	i2c_bus.write(PMIC_ADRS, data_buff,2);        //write to BBBExtra register
+
+	data_buff[0] = BOOST_VOLTAGE;
+	data_buff[1] = 0x08;                          //Boost voltage configuration
+	//register followed by data
+	//to set voltage to 4.5V 1f
+	pmic_en = 0;                                  //disables VLED 08
+	i2c_bus.write(PMIC_ADRS, data_buff,2);        //write to BBBExtra register
+	pmic_en = 1;                                  //enables VLED
+}
+
+/* Op Sensor FIFO nearly full callback */
+void max30101_intr_callback()
+{
+	if (thread != 0) {
+		thread->signal_set(MAX30101_IRQ_ASSERTED_ID);
+	}
+}
+
+void max30101_reader_task(struct max30101_reader_task_args *args)
+{
+	InterruptIn op_sensor_int(args->pinIntr);		// Config P3_2 as int. in for
+	op_sensor_int.fall(max30101_intr_callback);		// FIFO ready interrupt
+
+	DigitalOut VLED_EN(args->pinVLED,0);			//Enable for VLEDs
+	max30101wing_pmic_config(args->i2cBus, VLED_EN);
+
+	MAX30101 op_sensor(args->i2cBus);				// Create new MAX30101 on i2cBus
+	int rc = max30101_config(op_sensor);			// Config sensor, return 0 on success
+
+	MAX30101::InterruptBitField_u ints;				// Read interrupt status to clear
+	rc = op_sensor.getInterruptStatus(ints);		// power on interrupt
+
+	thread = args->self;
+
+	uint8_t fifoData[MAX30101::MAX_FIFO_BYTES];
+	uint16_t idx, readBytes;
+	uint16_t HRTemp;
+	uint16_t spo2Temp;
+
+	uint16_t lastValidHR = 0;
+	uint16_t lastValidSPO2 = 0;
+
+	int r=0; //counter for redData position
+	int ir=0; //counter for irData position
+	int g =0; //counter for greenData position
+	int c=0; //counter to print values
+
+	int consecCalcFailCnt = 0;
+
+	printf("Starting MAX30101 HeartRate / SPO2 Demo Application...\r\n");
+	printf("Please wait a few seconds while data is being collected.\r\n");
+
+	Timer bleNotifyTimer;
+
+	bleNotifyTimer.start();
+
+	while (1) {
+		if (rc == 0) {
+			/* Check if op_sensor interrupt asserted */
+			thread->signal_wait(MAX30101_IRQ_ASSERTED_ID);
+
+			/* Read interrupt status to clear interrupt */
+			rc = op_sensor.getInterruptStatus(ints);
+
+			/* Confirms proper read prior to executing */
+			if (rc == 0) {
+				// Read FIFO
+				rc = op_sensor.readFIFO(MAX30101::ThreeLedChannels, fifoData, readBytes);
+
+				if (rc == 0) {
+					/* Convert read bytes into samples */
+					for (idx = 0; idx < readBytes; idx+=9) {
+						if (r >= 500 || ir >= 500 || g >= 500) {
+							printf("Overflow! r=%d ir=%d g=%d\r\n", r, ir, g);
+							break;
+						}
+
+						if (readBytes >= (idx + 8)) {
+							redData[r++] = ((fifoData[idx] << 16) | (fifoData[idx + 1] << 8) | (fifoData[idx + 2])) & 0x03FFFF;
+							irData[ir++] = ((fifoData[idx + 3] << 16) | (fifoData[idx + 4] << 8) | (fifoData[idx + 5])) & 0x03FFFF;
+							greenData[g++] = ((fifoData[idx + 6] << 16) | (fifoData[idx + 7] << 8) | (fifoData[idx + 8])) & 0x03FFFF;
+						}
+					}
+
+					if ((r >= MAX30101_BUFFER_LEN) && (ir >= MAX30101_BUFFER_LEN) && (g >= MAX30101_BUFFER_LEN)) {/* checks to make sure there are 500 */
+						/* samples in data buffers */
+
+						/* runs the heart rate and SpO2 algorithm */
+						for (c = 0, HRTemp = 0; c < r; c++) {
+							HRSpO2Func(irData[c], redData[c],greenData[c], c,sampleRate, compSpO2,
+									   &ir_ac_comp,&red_ac_comp, &green_ac_comp, &ir_ac_mag,&red_ac_mag,
+									   &green_ac_mag, &HRbpm2,&SpO2B,&DRdy);
+							if (DRdy) {
+								HRTemp = HRbpm2;
+								spo2Temp = SpO2B;
+							}
+						}
+
+						/* If the above algorithm returns a valid heart rate on the last sample, it is printed */
+						if (DRdy == 1) {
+							printf("Heart Rate = %i\r\n",HRbpm2);
+							printf("SPO2 = %i\r\n",SpO2B);
+							lastValidHR = HRbpm2;
+							lastValidSPO2 = SpO2B;
+							consecCalcFailCnt = 0;
+						} else if (HRTemp != 0) { /* if a valid heart was calculated at all, it is printed */
+							printf("Heart Rate = %i\r\n",HRTemp);
+							printf("SPO2 = %i\r\n",spo2Temp);
+							lastValidHR = HRTemp;
+							lastValidSPO2 = spo2Temp;
+							consecCalcFailCnt = 0;
+						} else {
+							consecCalcFailCnt++;
+							if (consecCalcFailCnt >= 10) {
+								printf("Calculation failed...waiting for more samples...\r\n");
+								printf("Please keep your finger on the MAX30101 sensor with minimal movement.\r\n");
+								consecCalcFailCnt = 0;
+							}
+						}
+
+						/* dump the first hundred samples after calculation */
+						for (c = 100; c < 500; c++) {
+							redData[c - 100] = redData[c];
+							irData[c - 100] = irData[c];
+							greenData[c - 100] = greenData[c];
+						}
+
+						/* reset counters */
+						r = 400;
+						ir = 400;
+						g = 400;
+					}
+
+					if (bleNotifyTimer.read_ms() >= (args->notify_period_sec * 1000)) {
+						bleGattAttrWrite(args->gattHeartRate, (uint8_t *)&lastValidHR, sizeof(lastValidHR));
+						bleGattAttrWrite(args->gattSPO2, (uint8_t *)&lastValidSPO2, sizeof(lastValidSPO2));
+						bleNotifyTimer.reset();
+					}
+				}
+			}
+		} else { // If rc != 0, a communication error has occurred
+
+			printf("Something went wrong, "
+					  "check the I2C bus or power connections... \r\n");
+
+			return;
+		}
+
+	}
+}
+
+