Maxim Integrated's IoT development kit
Dependencies: MAX30101 MAX30003 MAX113XX_Pixi MAX30205 max32630fthr USBDevice
max30101_app.cpp
00001 /* 00002 * max30101_app.cpp 00003 * 00004 * Created on: Jun 20, 2018 00005 * Author: Mahir.Ozturk 00006 */ 00007 #include <mbed.h> 00008 #include "max30101_app.h" 00009 #include "MAX30101.h" 00010 #include "max30101_algo.h" 00011 00012 #define MAX30101_IRQ_ASSERTED_ID 1 00013 00014 #define MAX30101_BUFFER_LEN 500 00015 00016 static Thread *thread = 0; 00017 00018 //variable for the algorithm 00019 uint16_t sampleRate = 100; 00020 uint16_t compSpO2 = 1; 00021 int16_t ir_ac_comp = 0; 00022 int16_t red_ac_comp = 0; 00023 int16_t green_ac_comp = 0; 00024 int16_t ir_ac_mag = 0; 00025 int16_t red_ac_mag = 0; 00026 int16_t green_ac_mag = 0; 00027 uint16_t HRbpm2 = 0; 00028 uint16_t SpO2B = 0; 00029 uint16_t DRdy = 0; 00030 00031 //declare large variables outside of main 00032 uint32_t redData[MAX30101_BUFFER_LEN];//set array to max fifo size 00033 uint32_t irData[MAX30101_BUFFER_LEN];//set array to max fifo size 00034 uint32_t greenData[MAX30101_BUFFER_LEN];//set array to max fifo size 00035 00036 bool max30101_config(MAX30101 &op_sensor) 00037 { 00038 //Reset Device 00039 MAX30101::ModeConfiguration_u modeConfig; 00040 modeConfig.all = 0; 00041 modeConfig.bits.reset = 1; 00042 modeConfig.bits.mode = MAX30101::MultiLedMode; // Sets SPO2 Mode 00043 int32_t rc = op_sensor.setModeConfiguration(modeConfig); 00044 00045 //enable MAX30101 interrupts 00046 MAX30101::InterruptBitField_u ints; 00047 if (rc == 0) { 00048 ints.all = 0; 00049 ints.bits.a_full = 1; // Enable FIFO almost full interrupt 00050 ints.bits.ppg_rdy =1; //Enables an interrupt when a new sample is ready 00051 rc = op_sensor.enableInterrupts(ints); 00052 } 00053 00054 //configure FIFO 00055 MAX30101::FIFO_Configuration_u fifoConfig; 00056 if (rc == 0) { 00057 fifoConfig.all = 0; 00058 fifoConfig.bits.fifo_a_full = 10; // Max level of 17 samples 00059 fifoConfig.bits.sample_average = MAX30101::AveragedSamples_0;// Average 0 samples 00060 rc = op_sensor.setFIFOConfiguration(fifoConfig); 00061 } 00062 00063 MAX30101::SpO2Configuration_u spo2Config; 00064 if (rc == 0) { 00065 spo2Config.all = 0; // clears register 00066 spo2Config.bits.spo2_adc_range = 1; //sets resolution to 4096 nAfs 00067 spo2Config.bits.spo2_sr = MAX30101::SR_100_Hz; // SpO2 SR = 100Hz 00068 spo2Config.bits.led_pw = MAX30101::PW_3; // 18-bit ADC resolution ~400us 00069 rc = op_sensor.setSpO2Configuration(spo2Config); 00070 } 00071 00072 //Set time slots for LEDS 00073 MAX30101::ModeControlReg_u multiLED; 00074 if (rc == 0) { 00075 //sets timing for control register 1 00076 multiLED.bits.lo_slot=1; 00077 multiLED.bits.hi_slot=2; 00078 rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg1, multiLED); 00079 if (rc == 0) { 00080 multiLED.bits.lo_slot=3; 00081 multiLED.bits.hi_slot=0; 00082 rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg2, multiLED); 00083 } 00084 } 00085 00086 //Set LED drive currents 00087 if (rc == 0) { 00088 // Heart Rate only, 1 LED channel, Pulse amp. = ~7mA 00089 rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED1_PA, 0x24); 00090 //To include SPO2, 2 LED channel, Pulse amp. ~7mA 00091 if (rc == 0) { 00092 rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED2_PA, 0x24); 00093 } 00094 if (rc == 0) { 00095 rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED3_PA, 0x24); 00096 } 00097 } 00098 00099 //Set operating mode 00100 modeConfig.all = 0; 00101 if (rc == 0) { 00102 modeConfig.bits.mode = MAX30101::MultiLedMode; // Sets multiLED mode 00103 rc = op_sensor.setModeConfiguration(modeConfig); 00104 } 00105 00106 return rc; 00107 } 00108 00109 void max30101wing_pmic_config(I2C & i2c_bus, DigitalOut & pmic_en) 00110 { 00111 const uint8_t PMIC_ADRS = 0x54; 00112 const uint8_t BBB_EXTRA_ADRS = 0x1C; 00113 const uint8_t BOOST_VOLTAGE = 0x05; 00114 00115 char data_buff[] = {BBB_EXTRA_ADRS, 0x40}; //BBBExtra register address 00116 //and data to enable passive 00117 //pull down. 00118 i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register 00119 00120 data_buff[0] = BOOST_VOLTAGE; 00121 data_buff[1] = 0x08; //Boost voltage configuration 00122 //register followed by data 00123 //to set voltage to 4.5V 1f 00124 pmic_en = 0; //disables VLED 08 00125 i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register 00126 pmic_en = 1; //enables VLED 00127 } 00128 00129 /* Op Sensor FIFO nearly full callback */ 00130 void max30101_intr_callback() 00131 { 00132 if (thread != 0) { 00133 thread->signal_set(MAX30101_IRQ_ASSERTED_ID); 00134 } 00135 } 00136 00137 void max30101_reader_task(struct max30101_reader_task_args *args) 00138 { 00139 InterruptIn op_sensor_int(args->pinIntr); // Config P3_2 as int. in for 00140 op_sensor_int.fall(max30101_intr_callback); // FIFO ready interrupt 00141 00142 DigitalOut VLED_EN(args->pinVLED,0); //Enable for VLEDs 00143 max30101wing_pmic_config(args->i2cBus, VLED_EN); 00144 00145 MAX30101 op_sensor(args->i2cBus); // Create new MAX30101 on i2cBus 00146 int rc = max30101_config(op_sensor); // Config sensor, return 0 on success 00147 00148 MAX30101::InterruptBitField_u ints; // Read interrupt status to clear 00149 rc = op_sensor.getInterruptStatus(ints); // power on interrupt 00150 00151 thread = args->self; 00152 00153 uint8_t fifoData[MAX30101::MAX_FIFO_BYTES]; 00154 uint16_t idx, readBytes; 00155 uint16_t HRTemp; 00156 uint16_t spo2Temp; 00157 00158 uint16_t lastValidHR = 0; 00159 uint16_t lastValidSPO2 = 0; 00160 00161 int r=0; //counter for redData position 00162 int ir=0; //counter for irData position 00163 int g =0; //counter for greenData position 00164 int c=0; //counter to print values 00165 00166 int consecCalcFailCnt = 0; 00167 00168 printf("Starting MAX30101 HeartRate / SPO2 Demo Application...\r\n"); 00169 printf("Please wait a few seconds while data is being collected.\r\n"); 00170 00171 Timer bleNotifyTimer; 00172 00173 bleNotifyTimer.start(); 00174 00175 while (1) { 00176 if (rc == 0) { 00177 /* Check if op_sensor interrupt asserted */ 00178 thread->signal_wait(MAX30101_IRQ_ASSERTED_ID); 00179 00180 /* Read interrupt status to clear interrupt */ 00181 rc = op_sensor.getInterruptStatus(ints); 00182 00183 /* Confirms proper read prior to executing */ 00184 if (rc == 0) { 00185 // Read FIFO 00186 rc = op_sensor.readFIFO(MAX30101::ThreeLedChannels, fifoData, readBytes); 00187 00188 if (rc == 0) { 00189 /* Convert read bytes into samples */ 00190 for (idx = 0; idx < readBytes; idx+=9) { 00191 if (r >= 500 || ir >= 500 || g >= 500) { 00192 printf("Overflow! r=%d ir=%d g=%d\r\n", r, ir, g); 00193 break; 00194 } 00195 00196 if (readBytes >= (idx + 8)) { 00197 redData[r++] = ((fifoData[idx] << 16) | (fifoData[idx + 1] << 8) | (fifoData[idx + 2])) & 0x03FFFF; 00198 irData[ir++] = ((fifoData[idx + 3] << 16) | (fifoData[idx + 4] << 8) | (fifoData[idx + 5])) & 0x03FFFF; 00199 greenData[g++] = ((fifoData[idx + 6] << 16) | (fifoData[idx + 7] << 8) | (fifoData[idx + 8])) & 0x03FFFF; 00200 } 00201 } 00202 00203 if ((r >= MAX30101_BUFFER_LEN) && (ir >= MAX30101_BUFFER_LEN) && (g >= MAX30101_BUFFER_LEN)) {/* checks to make sure there are 500 */ 00204 /* samples in data buffers */ 00205 00206 /* runs the heart rate and SpO2 algorithm */ 00207 for (c = 0, HRTemp = 0; c < r; c++) { 00208 HRSpO2Func(irData[c], redData[c],greenData[c], c,sampleRate, compSpO2, 00209 &ir_ac_comp,&red_ac_comp, &green_ac_comp, &ir_ac_mag,&red_ac_mag, 00210 &green_ac_mag, &HRbpm2,&SpO2B,&DRdy); 00211 if (DRdy) { 00212 HRTemp = HRbpm2; 00213 spo2Temp = SpO2B; 00214 } 00215 } 00216 00217 /* If the above algorithm returns a valid heart rate on the last sample, it is printed */ 00218 if (DRdy == 1) { 00219 printf("Heart Rate = %i\r\n",HRbpm2); 00220 printf("SPO2 = %i\r\n",SpO2B); 00221 lastValidHR = HRbpm2; 00222 lastValidSPO2 = SpO2B; 00223 consecCalcFailCnt = 0; 00224 } else if (HRTemp != 0) { /* if a valid heart was calculated at all, it is printed */ 00225 printf("Heart Rate = %i\r\n",HRTemp); 00226 printf("SPO2 = %i\r\n",spo2Temp); 00227 lastValidHR = HRTemp; 00228 lastValidSPO2 = spo2Temp; 00229 consecCalcFailCnt = 0; 00230 } else { 00231 consecCalcFailCnt++; 00232 if (consecCalcFailCnt >= 10) { 00233 printf("Calculation failed...waiting for more samples...\r\n"); 00234 printf("Please keep your finger on the MAX30101 sensor with minimal movement.\r\n"); 00235 consecCalcFailCnt = 0; 00236 } 00237 } 00238 00239 /* dump the first hundred samples after calculation */ 00240 for (c = 100; c < 500; c++) { 00241 redData[c - 100] = redData[c]; 00242 irData[c - 100] = irData[c]; 00243 greenData[c - 100] = greenData[c]; 00244 } 00245 00246 /* reset counters */ 00247 r = 400; 00248 ir = 400; 00249 g = 400; 00250 } 00251 00252 if (bleNotifyTimer.read_ms() >= (args->notify_period_sec * 1000)) { 00253 bleGattAttrWrite(args->gattHeartRate, (uint8_t *)&lastValidHR, sizeof(lastValidHR)); 00254 bleGattAttrWrite(args->gattSPO2, (uint8_t *)&lastValidSPO2, sizeof(lastValidSPO2)); 00255 bleNotifyTimer.reset(); 00256 } 00257 } 00258 } 00259 } else { // If rc != 0, a communication error has occurred 00260 00261 printf("Something went wrong, " 00262 "check the I2C bus or power connections... \r\n"); 00263 00264 return; 00265 } 00266 00267 } 00268 } 00269 00270
Generated on Wed Jul 13 2022 21:08:45 by
1.7.2