Maxim Integrated / Mbed OS MAX30101WING_HR_SPO2

Dependencies:   MAX30101 max32630fthr

Fork of MAX30101_HR_SPO2 by John Greene

Committer:
johnGreeneMaxim
Date:
Mon Nov 20 16:36:55 2017 +0000
Revision:
10:fcfa9adc99a9
Parent:
9:affd4e6372a0
Child:
11:976c80cc99d5
SPO2 and HR calculations

Who changed what in which revision?

UserRevisionLine numberNew contents of line
coreyharris 5:2f708191f1bd 1 /*******************************************************************************
coreyharris 5:2f708191f1bd 2 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
coreyharris 5:2f708191f1bd 3 *
coreyharris 5:2f708191f1bd 4 * Permission is hereby granted, free of charge, to any person obtaining a
coreyharris 5:2f708191f1bd 5 * copy of this software and associated documentation files (the "Software"),
coreyharris 5:2f708191f1bd 6 * to deal in the Software without restriction, including without limitation
coreyharris 5:2f708191f1bd 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
coreyharris 5:2f708191f1bd 8 * and/or sell copies of the Software, and to permit persons to whom the
coreyharris 5:2f708191f1bd 9 * Software is furnished to do so, subject to the following conditions:
coreyharris 5:2f708191f1bd 10 *
coreyharris 5:2f708191f1bd 11 * The above copyright notice and this permission notice shall be included
coreyharris 5:2f708191f1bd 12 * in all copies or substantial portions of the Software.
coreyharris 5:2f708191f1bd 13 *
coreyharris 5:2f708191f1bd 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
coreyharris 5:2f708191f1bd 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
coreyharris 5:2f708191f1bd 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
coreyharris 5:2f708191f1bd 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
coreyharris 5:2f708191f1bd 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
coreyharris 5:2f708191f1bd 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
coreyharris 5:2f708191f1bd 20 * OTHER DEALINGS IN THE SOFTWARE.
coreyharris 5:2f708191f1bd 21 *
coreyharris 5:2f708191f1bd 22 * Except as contained in this notice, the name of Maxim Integrated
coreyharris 5:2f708191f1bd 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
coreyharris 5:2f708191f1bd 24 * Products, Inc. Branding Policy.
coreyharris 5:2f708191f1bd 25 *
coreyharris 5:2f708191f1bd 26 * The mere transfer of this software does not imply any licenses
coreyharris 5:2f708191f1bd 27 * of trade secrets, proprietary technology, copyrights, patents,
coreyharris 5:2f708191f1bd 28 * trademarks, maskwork rights, or any other form of intellectual
coreyharris 5:2f708191f1bd 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
coreyharris 5:2f708191f1bd 30 * ownership rights.
coreyharris 5:2f708191f1bd 31 *******************************************************************************
coreyharris 5:2f708191f1bd 32 */
coreyharris 5:2f708191f1bd 33
coreyharris 5:2f708191f1bd 34
coreyharris 0:0bd4103885bf 35 #include "mbed.h"
coreyharris 0:0bd4103885bf 36 #include "max32630fthr.h"
coreyharris 0:0bd4103885bf 37 #include "MAX30101.h"
johnGreeneMaxim 9:affd4e6372a0 38 #include "algorithm.h"
johnGreeneMaxim 9:affd4e6372a0 39
johnGreeneMaxim 10:fcfa9adc99a9 40
coreyharris 0:0bd4103885bf 41
coreyharris 0:0bd4103885bf 42 MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
coreyharris 0:0bd4103885bf 43
coreyharris 0:0bd4103885bf 44 bool op_sensor_config(MAX30101 &op_sensor);
johnGreeneMaxim 8:a1538e8a3fd9 45 void pmic_config(I2C & i2c_bus, DigitalOut & pmic_en);
coreyharris 0:0bd4103885bf 46
coreyharris 0:0bd4103885bf 47 /* Op Sensor FIFO nearly full callback */
coreyharris 1:471e2b722d24 48 volatile bool op_sensorIntFlag = 0;
coreyharris 0:0bd4103885bf 49 void op_sensor_callback()
coreyharris 0:0bd4103885bf 50 {
coreyharris 1:471e2b722d24 51 op_sensorIntFlag = 1;
coreyharris 0:0bd4103885bf 52 }
coreyharris 0:0bd4103885bf 53
johnGreeneMaxim 10:fcfa9adc99a9 54 //declare large variables outside of main
johnGreeneMaxim 10:fcfa9adc99a9 55 uint32_t redData[500];//set array to max fifo size
johnGreeneMaxim 10:fcfa9adc99a9 56 uint32_t irData[500];//set array to max fifo size
johnGreeneMaxim 10:fcfa9adc99a9 57
johnGreeneMaxim 10:fcfa9adc99a9 58
coreyharris 0:0bd4103885bf 59 int main()
coreyharris 0:0bd4103885bf 60 {
coreyharris 1:471e2b722d24 61 Serial pc(USBTX, USBRX); // Use USB debug probe for serial link
coreyharris 1:471e2b722d24 62 pc.baud(115200); // Baud rate = 115200
coreyharris 0:0bd4103885bf 63
coreyharris 1:471e2b722d24 64 DigitalOut rLed(LED1, LED_OFF); // Debug LEDs
coreyharris 0:0bd4103885bf 65 DigitalOut gLed(LED2, LED_OFF);
coreyharris 0:0bd4103885bf 66 DigitalOut bLed(LED3, LED_OFF);
coreyharris 0:0bd4103885bf 67
coreyharris 1:471e2b722d24 68 InterruptIn op_sensor_int(P3_2); // Config P3_2 as int. in for
coreyharris 1:471e2b722d24 69 op_sensor_int.fall(&op_sensor_callback); // FIFO ready interrupt
coreyharris 0:0bd4103885bf 70
coreyharris 4:14d1b87cd3c4 71 I2C i2cBus(I2C1_SDA, I2C1_SCL); // I2C bus, P3_4 = SDA, P3_5 = SCL
coreyharris 0:0bd4103885bf 72
johnGreeneMaxim 8:a1538e8a3fd9 73 DigitalOut VLED_EN(P3_3,0); //Enable for VLEDs
johnGreeneMaxim 8:a1538e8a3fd9 74 pmic_config(i2cBus, VLED_EN);
johnGreeneMaxim 8:a1538e8a3fd9 75
coreyharris 4:14d1b87cd3c4 76 MAX30101 op_sensor(i2cBus); // Create new MAX30101 on i2cBus
coreyharris 4:14d1b87cd3c4 77 int rc = op_sensor_config(op_sensor); // Config sensor, return 0 on success
coreyharris 0:0bd4103885bf 78
coreyharris 5:2f708191f1bd 79 MAX30101::InterruptBitField_u ints; // Read interrupt status to clear
coreyharris 5:2f708191f1bd 80 rc = op_sensor.getInterruptStatus(ints); // power on interrupt
coreyharris 5:2f708191f1bd 81
coreyharris 0:0bd4103885bf 82 uint8_t fifoData[MAX30101::MAX_FIFO_BYTES];
coreyharris 0:0bd4103885bf 83 uint16_t idx, readBytes;
coreyharris 7:6075af57668e 84 int32_t opSample;
coreyharris 2:54182d6a168f 85 uint32_t sample;
johnGreeneMaxim 10:fcfa9adc99a9 86
johnGreeneMaxim 9:affd4e6372a0 87 int r=0; //counter for redData position
johnGreeneMaxim 9:affd4e6372a0 88 int ir=0; //counter for irData position
johnGreeneMaxim 9:affd4e6372a0 89 int c=0; //counter to print values
johnGreeneMaxim 9:affd4e6372a0 90 int32_t spo2 =0;
johnGreeneMaxim 9:affd4e6372a0 91 int8_t spo2Valid = 0;
johnGreeneMaxim 9:affd4e6372a0 92 int32_t heartRate = 0;
johnGreeneMaxim 9:affd4e6372a0 93 int8_t heartRateValid = 0;
johnGreeneMaxim 10:fcfa9adc99a9 94
johnGreeneMaxim 9:affd4e6372a0 95
johnGreeneMaxim 10:fcfa9adc99a9 96 pc.printf("Starting Program...Please wait a few seconds while data is being collected.\r\n");
johnGreeneMaxim 9:affd4e6372a0 97 while(1)
johnGreeneMaxim 10:fcfa9adc99a9 98 {
johnGreeneMaxim 9:affd4e6372a0 99 if( rc == 0 )
johnGreeneMaxim 9:affd4e6372a0 100 {
coreyharris 4:14d1b87cd3c4 101
coreyharris 4:14d1b87cd3c4 102 // Check if op_sensor interrupt asserted
johnGreeneMaxim 9:affd4e6372a0 103 if(op_sensorIntFlag)
johnGreeneMaxim 9:affd4e6372a0 104 {
johnGreeneMaxim 10:fcfa9adc99a9 105 //pc.printf("Entered op_sensorIntFlag check\r\n");
coreyharris 1:471e2b722d24 106 op_sensorIntFlag = 0; // Lower interrupt flag
coreyharris 4:14d1b87cd3c4 107 rc = op_sensor.getInterruptStatus(ints); // Read interrupt status
coreyharris 0:0bd4103885bf 108
coreyharris 4:14d1b87cd3c4 109 // Check if FIFO almost full interrupt asserted
johnGreeneMaxim 9:affd4e6372a0 110 if((rc == 0) && (ints.bits.a_full))
johnGreeneMaxim 9:affd4e6372a0 111 {
coreyharris 4:14d1b87cd3c4 112 // Read FIFO
johnGreeneMaxim 9:affd4e6372a0 113 rc = op_sensor.readFIFO(MAX30101::TwoLedChannels, fifoData, readBytes);
johnGreeneMaxim 10:fcfa9adc99a9 114
johnGreeneMaxim 9:affd4e6372a0 115 if(rc == 0)
johnGreeneMaxim 9:affd4e6372a0 116 {
coreyharris 4:14d1b87cd3c4 117
coreyharris 4:14d1b87cd3c4 118 // Convert read bytes into samples
johnGreeneMaxim 10:fcfa9adc99a9 119 for(idx = 0, c=0; idx < readBytes; idx+=3)
johnGreeneMaxim 9:affd4e6372a0 120 {
johnGreeneMaxim 10:fcfa9adc99a9 121
coreyharris 2:54182d6a168f 122 sample = (fifoData[idx]<<16) | (fifoData[idx+1]<<8) | (fifoData[idx+2]);
johnGreeneMaxim 10:fcfa9adc99a9 123 opSample = sample;
johnGreeneMaxim 10:fcfa9adc99a9 124 opSample&=0x03FFFF; //Mask MSB [23:18]
johnGreeneMaxim 10:fcfa9adc99a9 125
johnGreeneMaxim 9:affd4e6372a0 126 if(idx%2==0)
johnGreeneMaxim 9:affd4e6372a0 127 {
johnGreeneMaxim 9:affd4e6372a0 128 redData[r] = opSample;//saves to buff for calculations
johnGreeneMaxim 9:affd4e6372a0 129 r++;
johnGreeneMaxim 9:affd4e6372a0 130
johnGreeneMaxim 9:affd4e6372a0 131 }
johnGreeneMaxim 9:affd4e6372a0 132 else
johnGreeneMaxim 9:affd4e6372a0 133 {
johnGreeneMaxim 10:fcfa9adc99a9 134
johnGreeneMaxim 9:affd4e6372a0 135 irData[ir] = opSample; //saves to buff for calculations
johnGreeneMaxim 9:affd4e6372a0 136 ir++;
johnGreeneMaxim 9:affd4e6372a0 137
johnGreeneMaxim 9:affd4e6372a0 138 }
johnGreeneMaxim 9:affd4e6372a0 139
coreyharris 0:0bd4103885bf 140 }
coreyharris 4:14d1b87cd3c4 141
johnGreeneMaxim 10:fcfa9adc99a9 142 if(r>=450 & ir>=450)//checks to make sure there are 450
johnGreeneMaxim 10:fcfa9adc99a9 143 //samples in data buffers
johnGreeneMaxim 9:affd4e6372a0 144 {
johnGreeneMaxim 10:fcfa9adc99a9 145
johnGreeneMaxim 9:affd4e6372a0 146 //calculate heart rate and spo2
johnGreeneMaxim 10:fcfa9adc99a9 147 maxim_heart_rate_and_oxygen_saturation( irData, ir,
johnGreeneMaxim 9:affd4e6372a0 148 redData, &spo2, &spo2Valid, &heartRate, &heartRateValid);
johnGreeneMaxim 10:fcfa9adc99a9 149 pc.printf("SPO2 = %i\r\n",spo2);
johnGreeneMaxim 10:fcfa9adc99a9 150 //heart rate is typically twice what it should be, thus divide by 2
johnGreeneMaxim 10:fcfa9adc99a9 151 pc.printf("Heart Rate = %i\r\n",heartRate/2);
johnGreeneMaxim 9:affd4e6372a0 152
johnGreeneMaxim 10:fcfa9adc99a9 153 for(c=100;c<450;c++)//dump first hundred samples
johnGreeneMaxim 10:fcfa9adc99a9 154 //after calculations
johnGreeneMaxim 9:affd4e6372a0 155 {
johnGreeneMaxim 9:affd4e6372a0 156 redData[c-100]=redData[c];
johnGreeneMaxim 9:affd4e6372a0 157 irData[c-100]=irData[c];
johnGreeneMaxim 9:affd4e6372a0 158
johnGreeneMaxim 9:affd4e6372a0 159 }
johnGreeneMaxim 10:fcfa9adc99a9 160 r=350;
johnGreeneMaxim 10:fcfa9adc99a9 161 ir=350;
johnGreeneMaxim 10:fcfa9adc99a9 162 }
coreyharris 0:0bd4103885bf 163 }
coreyharris 0:0bd4103885bf 164 }
coreyharris 0:0bd4103885bf 165 }
coreyharris 3:a580414c44ce 166
coreyharris 5:2f708191f1bd 167 // If rc != 0, a communication error has occurred
coreyharris 3:a580414c44ce 168 } else {
coreyharris 0:0bd4103885bf 169
coreyharris 4:14d1b87cd3c4 170 pc.printf("Something went wrong, "
coreyharris 4:14d1b87cd3c4 171 "check the I2C bus or power connections... \r\n");
coreyharris 0:0bd4103885bf 172 bLed = LED_OFF;
coreyharris 0:0bd4103885bf 173 gLed = LED_OFF;
coreyharris 0:0bd4103885bf 174
coreyharris 0:0bd4103885bf 175 while(1)
coreyharris 0:0bd4103885bf 176 {
coreyharris 0:0bd4103885bf 177 rLed = !rLed;
coreyharris 0:0bd4103885bf 178 wait(0.5);
coreyharris 3:a580414c44ce 179 }
coreyharris 3:a580414c44ce 180 }
coreyharris 0:0bd4103885bf 181
coreyharris 3:a580414c44ce 182 }
coreyharris 0:0bd4103885bf 183 }
coreyharris 0:0bd4103885bf 184
coreyharris 0:0bd4103885bf 185
coreyharris 0:0bd4103885bf 186 bool op_sensor_config(MAX30101 &op_sensor) {
coreyharris 0:0bd4103885bf 187
coreyharris 0:0bd4103885bf 188 //Reset Device
coreyharris 0:0bd4103885bf 189 MAX30101::ModeConfiguration_u modeConfig;
coreyharris 0:0bd4103885bf 190 modeConfig.all = 0;
coreyharris 0:0bd4103885bf 191 modeConfig.bits.reset = 1;
coreyharris 0:0bd4103885bf 192 int32_t rc = op_sensor.setModeConfiguration(modeConfig);
coreyharris 0:0bd4103885bf 193
coreyharris 0:0bd4103885bf 194
coreyharris 0:0bd4103885bf 195 //enable MAX30101 interrupts
coreyharris 0:0bd4103885bf 196 MAX30101::InterruptBitField_u ints;
coreyharris 0:0bd4103885bf 197 if(rc == 0)
coreyharris 0:0bd4103885bf 198 {
coreyharris 0:0bd4103885bf 199 ints.all = 0;
johnGreeneMaxim 9:affd4e6372a0 200 ints.bits.die_temp = 1; // Enable internal die temp. interrupt
johnGreeneMaxim 9:affd4e6372a0 201 ints.bits.a_full = 1; // Enable FIFO almost full interrupt
coreyharris 0:0bd4103885bf 202 rc = op_sensor.enableInterrupts(ints);
coreyharris 0:0bd4103885bf 203 }
coreyharris 0:0bd4103885bf 204
coreyharris 0:0bd4103885bf 205 //configure FIFO
coreyharris 0:0bd4103885bf 206 MAX30101::FIFO_Configuration_u fifoConfig;
coreyharris 0:0bd4103885bf 207 if(rc == 0)
coreyharris 0:0bd4103885bf 208 {
coreyharris 0:0bd4103885bf 209 fifoConfig.all = 0;
johnGreeneMaxim 10:fcfa9adc99a9 210 fifoConfig.bits.fifo_a_full = 15; // Max level of 15 samples
johnGreeneMaxim 10:fcfa9adc99a9 211 fifoConfig.bits.sample_average = MAX30101::AveragedSamples_8;// Average 8 samples
coreyharris 0:0bd4103885bf 212 rc = op_sensor.setFIFOConfiguration(fifoConfig);
coreyharris 0:0bd4103885bf 213 }
coreyharris 0:0bd4103885bf 214
coreyharris 0:0bd4103885bf 215 MAX30101::SpO2Configuration_u spo2Config;
coreyharris 0:0bd4103885bf 216 if(rc == 0)
coreyharris 0:0bd4103885bf 217 {
johnGreeneMaxim 9:affd4e6372a0 218 spo2Config.all = 0; // sets smallest LSB size
johnGreeneMaxim 9:affd4e6372a0 219 spo2Config.bits.spo2_sr = MAX30101::SR_3200_Hz; // SpO2 SR = 3200Hz
coreyharris 7:6075af57668e 220 spo2Config.bits.led_pw = MAX30101::PW_3; // 18-bit ADC resolution
coreyharris 0:0bd4103885bf 221 rc = op_sensor.setSpO2Configuration(spo2Config);
coreyharris 0:0bd4103885bf 222 }
coreyharris 0:0bd4103885bf 223
johnGreeneMaxim 9:affd4e6372a0 224 //Set LED drive currents
coreyharris 0:0bd4103885bf 225 if(rc == 0)
coreyharris 0:0bd4103885bf 226 {
coreyharris 5:2f708191f1bd 227 // Heart Rate only, 1 LED channel, Pulse amp. = 0x1F
coreyharris 2:54182d6a168f 228 rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED1_PA, 0x1F);
johnGreeneMaxim 9:affd4e6372a0 229 //To include SPO2, 2 LED channel, Pulse amp. 0x1F
johnGreeneMaxim 9:affd4e6372a0 230 if(rc==0)
johnGreeneMaxim 9:affd4e6372a0 231 {
johnGreeneMaxim 9:affd4e6372a0 232 rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED2_PA, 0x1F);
johnGreeneMaxim 9:affd4e6372a0 233 }
coreyharris 0:0bd4103885bf 234 }
coreyharris 0:0bd4103885bf 235
coreyharris 0:0bd4103885bf 236 //Set operating mode
coreyharris 0:0bd4103885bf 237 modeConfig.all = 0;
coreyharris 0:0bd4103885bf 238 if(rc == 0)
coreyharris 0:0bd4103885bf 239 {
johnGreeneMaxim 9:affd4e6372a0 240 modeConfig.bits.mode = MAX30101::SpO2Mode; // Sets SPO2 Mode
coreyharris 0:0bd4103885bf 241 rc = op_sensor.setModeConfiguration(modeConfig);
coreyharris 0:0bd4103885bf 242 }
coreyharris 0:0bd4103885bf 243
coreyharris 0:0bd4103885bf 244
coreyharris 0:0bd4103885bf 245 return rc;
coreyharris 0:0bd4103885bf 246 }
johnGreeneMaxim 8:a1538e8a3fd9 247
johnGreeneMaxim 8:a1538e8a3fd9 248 void pmic_config(I2C & i2c_bus, DigitalOut & pmic_en)
johnGreeneMaxim 8:a1538e8a3fd9 249 {
johnGreeneMaxim 8:a1538e8a3fd9 250
johnGreeneMaxim 8:a1538e8a3fd9 251 const uint8_t PMIC_ADRS = 0x54;
johnGreeneMaxim 8:a1538e8a3fd9 252 const uint8_t BBB_EXTRA_ADRS = 0x1C;
johnGreeneMaxim 8:a1538e8a3fd9 253 const uint8_t BOOST_VOLTAGE = 0x05;
johnGreeneMaxim 8:a1538e8a3fd9 254
johnGreeneMaxim 8:a1538e8a3fd9 255 char data_buff[] = {BBB_EXTRA_ADRS, 0x40}; //BBBExtra register address
johnGreeneMaxim 8:a1538e8a3fd9 256 //and data to enable passive
johnGreeneMaxim 8:a1538e8a3fd9 257 //pull down.
johnGreeneMaxim 8:a1538e8a3fd9 258 i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register
johnGreeneMaxim 8:a1538e8a3fd9 259
johnGreeneMaxim 8:a1538e8a3fd9 260 data_buff[0] = BOOST_VOLTAGE;
johnGreeneMaxim 8:a1538e8a3fd9 261 data_buff[1] = 0x14; //Boost voltage configuration
johnGreeneMaxim 8:a1538e8a3fd9 262 //register followed by data
johnGreeneMaxim 8:a1538e8a3fd9 263 //to set voltage to 4.5V
johnGreeneMaxim 8:a1538e8a3fd9 264 pmic_en = 0; //disables VLED
johnGreeneMaxim 8:a1538e8a3fd9 265 i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register
johnGreeneMaxim 8:a1538e8a3fd9 266 pmic_en = 1; //enables VLED
johnGreeneMaxim 8:a1538e8a3fd9 267 }