Demo program for the MAX30101WING that calculates heart rate and SpO2 data.
Dependencies: MAX30101 max32630fthr
Fork of MAX30101_HR_SPO2 by
main.cpp@13:ef4a84158e4c, 2018-03-08 (annotated)
- Committer:
- johnGreeneMaxim
- Date:
- Thu Mar 08 16:29:29 2018 +0000
- Revision:
- 13:ef4a84158e4c
- Parent:
- 12:ac85295f8713
revised parsing algorithm
Who changed what in which revision?
User | Revision | Line number | New 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 | */ |
johnGreeneMaxim | 11:976c80cc99d5 | 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 | 11:976c80cc99d5 | 38 | #include <stdio.h> |
johnGreeneMaxim | 11:976c80cc99d5 | 39 | #include <stdlib.h> |
johnGreeneMaxim | 11:976c80cc99d5 | 40 | #include <math.h> |
johnGreeneMaxim | 11:976c80cc99d5 | 41 | #include <string.h> |
johnGreeneMaxim | 9:affd4e6372a0 | 42 | |
johnGreeneMaxim | 11:976c80cc99d5 | 43 | //variable for the algorithm |
johnGreeneMaxim | 11:976c80cc99d5 | 44 | uint16_t sampleRate =100; |
johnGreeneMaxim | 11:976c80cc99d5 | 45 | uint16_t compSpO2=1; |
johnGreeneMaxim | 11:976c80cc99d5 | 46 | int16_t ir_ac_comp =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 47 | int16_t red_ac_comp=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 48 | int16_t green_ac_comp=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 49 | int16_t ir_ac_mag=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 50 | int16_t red_ac_mag=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 51 | int16_t green_ac_mag=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 52 | uint16_t HRbpm2=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 53 | uint16_t SpO2B=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 54 | uint16_t DRdy=0; |
johnGreeneMaxim | 10:fcfa9adc99a9 | 55 | |
johnGreeneMaxim | 11:976c80cc99d5 | 56 | //Heart rate and SpO2 algorithm |
johnGreeneMaxim | 11:976c80cc99d5 | 57 | void HRSpO2Func(uint32_t dinIR, uint32_t dinRed, uint32_t dinGreen, uint32_t ns,uint16_t SampRate,uint16_t compSpO2, |
johnGreeneMaxim | 11:976c80cc99d5 | 58 | int16_t *ir_ac_comp,int16_t *red_ac_comp, int16_t *green_ac_comp, int16_t *ir_ac_mag,int16_t *red_ac_mag, int16_t *green_ac_mag, uint16_t *HRbpm2,uint16_t *SpO2B,uint16_t *DRdy ); |
coreyharris | 0:0bd4103885bf | 59 | |
johnGreeneMaxim | 11:976c80cc99d5 | 60 | //helper functions for the heart rate and SpO2 function |
johnGreeneMaxim | 11:976c80cc99d5 | 61 | uint16_t avg_dc_est(int32_t *p, uint16_t x); |
johnGreeneMaxim | 11:976c80cc99d5 | 62 | |
johnGreeneMaxim | 11:976c80cc99d5 | 63 | void lp_dfir_flt(int16_t din0,int16_t din1,int16_t din2, int16_t *dout0,int16_t *dout1,int16_t *dout2) ; |
johnGreeneMaxim | 11:976c80cc99d5 | 64 | int32_t mul16(int16_t x, int16_t y); |
johnGreeneMaxim | 11:976c80cc99d5 | 65 | |
johnGreeneMaxim | 11:976c80cc99d5 | 66 | //set logic level to 3.3V |
coreyharris | 0:0bd4103885bf | 67 | MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3); |
coreyharris | 0:0bd4103885bf | 68 | |
johnGreeneMaxim | 11:976c80cc99d5 | 69 | //IC configuration functions |
coreyharris | 0:0bd4103885bf | 70 | bool op_sensor_config(MAX30101 &op_sensor); |
johnGreeneMaxim | 8:a1538e8a3fd9 | 71 | void pmic_config(I2C & i2c_bus, DigitalOut & pmic_en); |
coreyharris | 0:0bd4103885bf | 72 | |
coreyharris | 0:0bd4103885bf | 73 | /* Op Sensor FIFO nearly full callback */ |
johnGreeneMaxim | 11:976c80cc99d5 | 74 | volatile bool op_sensorIntFlag = 0; |
coreyharris | 0:0bd4103885bf | 75 | void op_sensor_callback() |
coreyharris | 0:0bd4103885bf | 76 | { |
coreyharris | 1:471e2b722d24 | 77 | op_sensorIntFlag = 1; |
coreyharris | 0:0bd4103885bf | 78 | } |
coreyharris | 0:0bd4103885bf | 79 | |
johnGreeneMaxim | 11:976c80cc99d5 | 80 | //declare large variables outside of main |
johnGreeneMaxim | 11:976c80cc99d5 | 81 | uint32_t redData[500];//set array to max fifo size |
johnGreeneMaxim | 11:976c80cc99d5 | 82 | uint32_t irData[500];//set array to max fifo size |
johnGreeneMaxim | 11:976c80cc99d5 | 83 | uint32_t greenData[500];//set array to max fifo size |
johnGreeneMaxim | 11:976c80cc99d5 | 84 | |
johnGreeneMaxim | 11:976c80cc99d5 | 85 | |
coreyharris | 0:0bd4103885bf | 86 | int main() |
coreyharris | 0:0bd4103885bf | 87 | { |
coreyharris | 1:471e2b722d24 | 88 | Serial pc(USBTX, USBRX); // Use USB debug probe for serial link |
coreyharris | 1:471e2b722d24 | 89 | pc.baud(115200); // Baud rate = 115200 |
johnGreeneMaxim | 11:976c80cc99d5 | 90 | |
johnGreeneMaxim | 11:976c80cc99d5 | 91 | DigitalOut rLed(LED1, LED_OFF); // Debug LED |
johnGreeneMaxim | 11:976c80cc99d5 | 92 | |
coreyharris | 1:471e2b722d24 | 93 | InterruptIn op_sensor_int(P3_2); // Config P3_2 as int. in for |
coreyharris | 1:471e2b722d24 | 94 | op_sensor_int.fall(&op_sensor_callback); // FIFO ready interrupt |
johnGreeneMaxim | 11:976c80cc99d5 | 95 | |
johnGreeneMaxim | 11:976c80cc99d5 | 96 | I2C i2cBus(I2C1_SDA, I2C1_SCL); // I2C bus, P3_4 = SDA, P3_5 = SCL |
coreyharris | 0:0bd4103885bf | 97 | |
johnGreeneMaxim | 8:a1538e8a3fd9 | 98 | DigitalOut VLED_EN(P3_3,0); //Enable for VLEDs |
johnGreeneMaxim | 8:a1538e8a3fd9 | 99 | pmic_config(i2cBus, VLED_EN); |
johnGreeneMaxim | 11:976c80cc99d5 | 100 | |
coreyharris | 4:14d1b87cd3c4 | 101 | MAX30101 op_sensor(i2cBus); // Create new MAX30101 on i2cBus |
coreyharris | 4:14d1b87cd3c4 | 102 | int rc = op_sensor_config(op_sensor); // Config sensor, return 0 on success |
johnGreeneMaxim | 11:976c80cc99d5 | 103 | |
coreyharris | 5:2f708191f1bd | 104 | MAX30101::InterruptBitField_u ints; // Read interrupt status to clear |
johnGreeneMaxim | 11:976c80cc99d5 | 105 | rc = op_sensor.getInterruptStatus(ints); // power on interrupt |
johnGreeneMaxim | 11:976c80cc99d5 | 106 | |
coreyharris | 0:0bd4103885bf | 107 | uint8_t fifoData[MAX30101::MAX_FIFO_BYTES]; |
coreyharris | 0:0bd4103885bf | 108 | uint16_t idx, readBytes; |
coreyharris | 7:6075af57668e | 109 | int32_t opSample; |
coreyharris | 2:54182d6a168f | 110 | uint32_t sample; |
johnGreeneMaxim | 11:976c80cc99d5 | 111 | uint16_t HRTemp; |
johnGreeneMaxim | 11:976c80cc99d5 | 112 | uint16_t spo2Temp; |
johnGreeneMaxim | 10:fcfa9adc99a9 | 113 | |
johnGreeneMaxim | 11:976c80cc99d5 | 114 | int r=0; //counter for redData position |
johnGreeneMaxim | 11:976c80cc99d5 | 115 | int ir=0; //counter for irData position |
johnGreeneMaxim | 11:976c80cc99d5 | 116 | int g =0; //counter for greenData position |
johnGreeneMaxim | 11:976c80cc99d5 | 117 | int c=0; //counter to print values |
johnGreeneMaxim | 11:976c80cc99d5 | 118 | |
johnGreeneMaxim | 10:fcfa9adc99a9 | 119 | pc.printf("Starting Program...Please wait a few seconds while data is being collected.\r\n"); |
johnGreeneMaxim | 11:976c80cc99d5 | 120 | while(1) { |
johnGreeneMaxim | 11:976c80cc99d5 | 121 | if( rc == 0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 122 | |
coreyharris | 4:14d1b87cd3c4 | 123 | // Check if op_sensor interrupt asserted |
johnGreeneMaxim | 11:976c80cc99d5 | 124 | if(op_sensorIntFlag) { |
johnGreeneMaxim | 10:fcfa9adc99a9 | 125 | //pc.printf("Entered op_sensorIntFlag check\r\n"); |
coreyharris | 1:471e2b722d24 | 126 | op_sensorIntFlag = 0; // Lower interrupt flag |
johnGreeneMaxim | 11:976c80cc99d5 | 127 | rc = op_sensor.getInterruptStatus(ints); // Read interrupt status |
johnGreeneMaxim | 11:976c80cc99d5 | 128 | //to clear interrupt |
johnGreeneMaxim | 11:976c80cc99d5 | 129 | |
johnGreeneMaxim | 11:976c80cc99d5 | 130 | // Confirms proper read prior to executing |
johnGreeneMaxim | 11:976c80cc99d5 | 131 | if((rc == 0)) { |
johnGreeneMaxim | 11:976c80cc99d5 | 132 | // Read FIFO |
johnGreeneMaxim | 11:976c80cc99d5 | 133 | rc = op_sensor.readFIFO(MAX30101::ThreeLedChannels, fifoData, readBytes); |
johnGreeneMaxim | 11:976c80cc99d5 | 134 | |
johnGreeneMaxim | 11:976c80cc99d5 | 135 | if(rc == 0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 136 | |
coreyharris | 4:14d1b87cd3c4 | 137 | // Convert read bytes into samples |
johnGreeneMaxim | 13:ef4a84158e4c | 138 | for (idx = 0; idx < readBytes; idx+=9) { |
johnGreeneMaxim | 13:ef4a84158e4c | 139 | if (r >= 500 || ir >= 500 || g >= 500) { |
johnGreeneMaxim | 13:ef4a84158e4c | 140 | pc.printf("Overflow!"); |
johnGreeneMaxim | 13:ef4a84158e4c | 141 | } |
johnGreeneMaxim | 13:ef4a84158e4c | 142 | redData[r++] = ((fifoData[idx] << 16) | (fifoData[idx + 1] << 8) | (fifoData[idx + 2])) & 0x03FFFF; |
johnGreeneMaxim | 11:976c80cc99d5 | 143 | |
johnGreeneMaxim | 13:ef4a84158e4c | 144 | irData[ir++] = ((fifoData[idx + 3] << 16) | (fifoData[idx + 4] << 8) | (fifoData[idx + 5])) & 0x03FFFF; |
johnGreeneMaxim | 11:976c80cc99d5 | 145 | |
johnGreeneMaxim | 13:ef4a84158e4c | 146 | greenData[g++] = ((fifoData[idx + 6] << 16) | (fifoData[idx + 7] << 8) | (fifoData[idx + 8])) & 0x03FFFF; |
johnGreeneMaxim | 13:ef4a84158e4c | 147 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 148 | |
johnGreeneMaxim | 11:976c80cc99d5 | 149 | |
johnGreeneMaxim | 11:976c80cc99d5 | 150 | |
johnGreeneMaxim | 12:ac85295f8713 | 151 | if(r>=500 && ir>=500 && g>500)//checks to make sure there are 500 |
johnGreeneMaxim | 11:976c80cc99d5 | 152 | //samples in data buffers |
johnGreeneMaxim | 11:976c80cc99d5 | 153 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 154 | |
johnGreeneMaxim | 11:976c80cc99d5 | 155 | //runs the heart rate and SpO2 algorithm |
johnGreeneMaxim | 11:976c80cc99d5 | 156 | for(c=0, HRTemp = 0; c<r; c++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 157 | |
johnGreeneMaxim | 11:976c80cc99d5 | 158 | HRSpO2Func(irData[c], redData[c],greenData[c], c,sampleRate, compSpO2, |
johnGreeneMaxim | 11:976c80cc99d5 | 159 | &ir_ac_comp,&red_ac_comp, &green_ac_comp, &ir_ac_mag,&red_ac_mag, |
johnGreeneMaxim | 11:976c80cc99d5 | 160 | &green_ac_mag, &HRbpm2,&SpO2B,&DRdy); |
johnGreeneMaxim | 11:976c80cc99d5 | 161 | if(DRdy) |
johnGreeneMaxim | 11:976c80cc99d5 | 162 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 163 | HRTemp = HRbpm2; |
johnGreeneMaxim | 11:976c80cc99d5 | 164 | spo2Temp = SpO2B; |
johnGreeneMaxim | 11:976c80cc99d5 | 165 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 166 | |
johnGreeneMaxim | 11:976c80cc99d5 | 167 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 168 | |
johnGreeneMaxim | 11:976c80cc99d5 | 169 | //If the above algorithm returns a valid heart rate on the last sample, it is printed |
johnGreeneMaxim | 11:976c80cc99d5 | 170 | if(DRdy==1) { |
johnGreeneMaxim | 11:976c80cc99d5 | 171 | pc.printf("Heart Rate = %i\r\n",HRbpm2); |
johnGreeneMaxim | 11:976c80cc99d5 | 172 | pc.printf("SPO2 = %i\r\n",SpO2B); |
johnGreeneMaxim | 11:976c80cc99d5 | 173 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 174 | else if (HRTemp!=0)//if a valid heart was calculated at all, it is printed |
johnGreeneMaxim | 9:affd4e6372a0 | 175 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 176 | pc.printf("Heart Rate = %i\r\n",HRTemp); |
johnGreeneMaxim | 11:976c80cc99d5 | 177 | pc.printf("SPO2 = %i\r\n",spo2Temp); |
johnGreeneMaxim | 9:affd4e6372a0 | 178 | } |
johnGreeneMaxim | 9:affd4e6372a0 | 179 | else |
johnGreeneMaxim | 9:affd4e6372a0 | 180 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 181 | pc.printf("Calculation failed...waiting for more samples...\r\n"); |
johnGreeneMaxim | 11:976c80cc99d5 | 182 | pc.printf("Please keep your finger on the MAX30101 sensor with minimal movement.\r\n"); |
johnGreeneMaxim | 9:affd4e6372a0 | 183 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 184 | |
johnGreeneMaxim | 11:976c80cc99d5 | 185 | //dump the first hundred samples after caluclaiton |
johnGreeneMaxim | 11:976c80cc99d5 | 186 | for(c=100; c<500; c++) |
johnGreeneMaxim | 11:976c80cc99d5 | 187 | |
johnGreeneMaxim | 9:affd4e6372a0 | 188 | { |
johnGreeneMaxim | 9:affd4e6372a0 | 189 | redData[c-100]=redData[c]; |
johnGreeneMaxim | 9:affd4e6372a0 | 190 | irData[c-100]=irData[c]; |
johnGreeneMaxim | 11:976c80cc99d5 | 191 | greenData[c-100] = greenData[c]; |
johnGreeneMaxim | 9:affd4e6372a0 | 192 | |
johnGreeneMaxim | 9:affd4e6372a0 | 193 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 194 | //reset counters |
johnGreeneMaxim | 11:976c80cc99d5 | 195 | r=400; |
johnGreeneMaxim | 11:976c80cc99d5 | 196 | ir=400; |
johnGreeneMaxim | 11:976c80cc99d5 | 197 | g=400; |
johnGreeneMaxim | 11:976c80cc99d5 | 198 | } |
coreyharris | 0:0bd4103885bf | 199 | } |
coreyharris | 0:0bd4103885bf | 200 | } |
coreyharris | 0:0bd4103885bf | 201 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 202 | |
johnGreeneMaxim | 11:976c80cc99d5 | 203 | // If rc != 0, a communication error has occurred |
johnGreeneMaxim | 11:976c80cc99d5 | 204 | } else { |
johnGreeneMaxim | 11:976c80cc99d5 | 205 | |
coreyharris | 4:14d1b87cd3c4 | 206 | pc.printf("Something went wrong, " |
coreyharris | 4:14d1b87cd3c4 | 207 | "check the I2C bus or power connections... \r\n"); |
johnGreeneMaxim | 11:976c80cc99d5 | 208 | //bLed = LED_OFF; |
johnGreeneMaxim | 11:976c80cc99d5 | 209 | //gLed = LED_OFF; |
johnGreeneMaxim | 11:976c80cc99d5 | 210 | |
johnGreeneMaxim | 11:976c80cc99d5 | 211 | while(1) { |
coreyharris | 0:0bd4103885bf | 212 | rLed = !rLed; |
johnGreeneMaxim | 11:976c80cc99d5 | 213 | wait(0.5); |
johnGreeneMaxim | 11:976c80cc99d5 | 214 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 215 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 216 | |
johnGreeneMaxim | 11:976c80cc99d5 | 217 | } |
coreyharris | 0:0bd4103885bf | 218 | } |
coreyharris | 0:0bd4103885bf | 219 | |
coreyharris | 0:0bd4103885bf | 220 | |
johnGreeneMaxim | 11:976c80cc99d5 | 221 | bool op_sensor_config(MAX30101 &op_sensor) |
johnGreeneMaxim | 11:976c80cc99d5 | 222 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 223 | |
coreyharris | 0:0bd4103885bf | 224 | //Reset Device |
coreyharris | 0:0bd4103885bf | 225 | MAX30101::ModeConfiguration_u modeConfig; |
coreyharris | 0:0bd4103885bf | 226 | modeConfig.all = 0; |
coreyharris | 0:0bd4103885bf | 227 | modeConfig.bits.reset = 1; |
johnGreeneMaxim | 11:976c80cc99d5 | 228 | modeConfig.bits.mode = MAX30101::MultiLedMode; // Sets SPO2 Mode |
coreyharris | 0:0bd4103885bf | 229 | int32_t rc = op_sensor.setModeConfiguration(modeConfig); |
johnGreeneMaxim | 11:976c80cc99d5 | 230 | |
johnGreeneMaxim | 11:976c80cc99d5 | 231 | |
coreyharris | 0:0bd4103885bf | 232 | //enable MAX30101 interrupts |
coreyharris | 0:0bd4103885bf | 233 | MAX30101::InterruptBitField_u ints; |
johnGreeneMaxim | 11:976c80cc99d5 | 234 | if(rc == 0) { |
coreyharris | 0:0bd4103885bf | 235 | ints.all = 0; |
johnGreeneMaxim | 9:affd4e6372a0 | 236 | ints.bits.a_full = 1; // Enable FIFO almost full interrupt |
johnGreeneMaxim | 11:976c80cc99d5 | 237 | ints.bits.ppg_rdy =1; //Enables an interrupt when a new sample is ready |
coreyharris | 0:0bd4103885bf | 238 | rc = op_sensor.enableInterrupts(ints); |
coreyharris | 0:0bd4103885bf | 239 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 240 | |
coreyharris | 0:0bd4103885bf | 241 | //configure FIFO |
coreyharris | 0:0bd4103885bf | 242 | MAX30101::FIFO_Configuration_u fifoConfig; |
johnGreeneMaxim | 11:976c80cc99d5 | 243 | if(rc == 0) { |
coreyharris | 0:0bd4103885bf | 244 | fifoConfig.all = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 245 | fifoConfig.bits.fifo_a_full = 10; // Max level of 17 samples |
johnGreeneMaxim | 11:976c80cc99d5 | 246 | fifoConfig.bits.sample_average = MAX30101::AveragedSamples_0;// Average 0 samples |
coreyharris | 0:0bd4103885bf | 247 | rc = op_sensor.setFIFOConfiguration(fifoConfig); |
coreyharris | 0:0bd4103885bf | 248 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 249 | |
coreyharris | 0:0bd4103885bf | 250 | MAX30101::SpO2Configuration_u spo2Config; |
johnGreeneMaxim | 11:976c80cc99d5 | 251 | if(rc == 0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 252 | spo2Config.all = 0; // clears register |
johnGreeneMaxim | 11:976c80cc99d5 | 253 | spo2Config.bits.spo2_adc_range = 1; //sets resolution to 4096 nAfs |
johnGreeneMaxim | 11:976c80cc99d5 | 254 | spo2Config.bits.spo2_sr = MAX30101::SR_100_Hz; // SpO2 SR = 100Hz |
johnGreeneMaxim | 11:976c80cc99d5 | 255 | spo2Config.bits.led_pw = MAX30101::PW_3; // 18-bit ADC resolution ~400us |
coreyharris | 0:0bd4103885bf | 256 | rc = op_sensor.setSpO2Configuration(spo2Config); |
coreyharris | 0:0bd4103885bf | 257 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 258 | |
johnGreeneMaxim | 11:976c80cc99d5 | 259 | //Set time slots for LEDS |
johnGreeneMaxim | 11:976c80cc99d5 | 260 | MAX30101::ModeControlReg_u multiLED; |
johnGreeneMaxim | 11:976c80cc99d5 | 261 | if(rc==0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 262 | //sets timing for control register 1 |
johnGreeneMaxim | 11:976c80cc99d5 | 263 | multiLED.bits.lo_slot=1; |
johnGreeneMaxim | 11:976c80cc99d5 | 264 | multiLED.bits.hi_slot=2; |
johnGreeneMaxim | 11:976c80cc99d5 | 265 | rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg1, multiLED); |
johnGreeneMaxim | 11:976c80cc99d5 | 266 | if(rc==0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 267 | multiLED.bits.lo_slot=3; |
johnGreeneMaxim | 11:976c80cc99d5 | 268 | multiLED.bits.hi_slot=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 269 | rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg2, multiLED); |
johnGreeneMaxim | 9:affd4e6372a0 | 270 | } |
coreyharris | 0:0bd4103885bf | 271 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 272 | |
johnGreeneMaxim | 11:976c80cc99d5 | 273 | //Set LED drive currents |
johnGreeneMaxim | 11:976c80cc99d5 | 274 | if(rc == 0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 275 | // Heart Rate only, 1 LED channel, Pulse amp. = ~7mA |
johnGreeneMaxim | 11:976c80cc99d5 | 276 | rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED1_PA, 0x24); |
johnGreeneMaxim | 11:976c80cc99d5 | 277 | //To include SPO2, 2 LED channel, Pulse amp. ~7mA |
johnGreeneMaxim | 11:976c80cc99d5 | 278 | if(rc==0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 279 | rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED2_PA, 0x24); |
johnGreeneMaxim | 11:976c80cc99d5 | 280 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 281 | if(rc==0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 282 | rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED3_PA, 0x24); |
johnGreeneMaxim | 11:976c80cc99d5 | 283 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 284 | |
johnGreeneMaxim | 11:976c80cc99d5 | 285 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 286 | |
coreyharris | 0:0bd4103885bf | 287 | //Set operating mode |
coreyharris | 0:0bd4103885bf | 288 | modeConfig.all = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 289 | if(rc == 0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 290 | modeConfig.bits.mode = MAX30101::MultiLedMode; // Sets multiLED mode |
coreyharris | 0:0bd4103885bf | 291 | rc = op_sensor.setModeConfiguration(modeConfig); |
johnGreeneMaxim | 11:976c80cc99d5 | 292 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 293 | |
johnGreeneMaxim | 11:976c80cc99d5 | 294 | |
coreyharris | 0:0bd4103885bf | 295 | return rc; |
coreyharris | 0:0bd4103885bf | 296 | } |
johnGreeneMaxim | 8:a1538e8a3fd9 | 297 | |
johnGreeneMaxim | 8:a1538e8a3fd9 | 298 | void pmic_config(I2C & i2c_bus, DigitalOut & pmic_en) |
johnGreeneMaxim | 8:a1538e8a3fd9 | 299 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 300 | |
johnGreeneMaxim | 8:a1538e8a3fd9 | 301 | const uint8_t PMIC_ADRS = 0x54; |
johnGreeneMaxim | 8:a1538e8a3fd9 | 302 | const uint8_t BBB_EXTRA_ADRS = 0x1C; |
johnGreeneMaxim | 8:a1538e8a3fd9 | 303 | const uint8_t BOOST_VOLTAGE = 0x05; |
johnGreeneMaxim | 11:976c80cc99d5 | 304 | |
johnGreeneMaxim | 11:976c80cc99d5 | 305 | char data_buff[] = {BBB_EXTRA_ADRS, 0x40}; //BBBExtra register address |
johnGreeneMaxim | 11:976c80cc99d5 | 306 | //and data to enable passive |
johnGreeneMaxim | 11:976c80cc99d5 | 307 | //pull down. |
johnGreeneMaxim | 8:a1538e8a3fd9 | 308 | i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register |
johnGreeneMaxim | 11:976c80cc99d5 | 309 | |
johnGreeneMaxim | 8:a1538e8a3fd9 | 310 | data_buff[0] = BOOST_VOLTAGE; |
johnGreeneMaxim | 11:976c80cc99d5 | 311 | data_buff[1] = 0x08; //Boost voltage configuration |
johnGreeneMaxim | 11:976c80cc99d5 | 312 | //register followed by data |
johnGreeneMaxim | 11:976c80cc99d5 | 313 | //to set voltage to 4.5V 1f |
johnGreeneMaxim | 11:976c80cc99d5 | 314 | pmic_en = 0; //disables VLED 08 |
johnGreeneMaxim | 8:a1538e8a3fd9 | 315 | i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register |
johnGreeneMaxim | 11:976c80cc99d5 | 316 | pmic_en = 1; //enables VLED |
johnGreeneMaxim | 11:976c80cc99d5 | 317 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 318 | |
johnGreeneMaxim | 11:976c80cc99d5 | 319 | |
johnGreeneMaxim | 11:976c80cc99d5 | 320 | |
johnGreeneMaxim | 11:976c80cc99d5 | 321 | // |
johnGreeneMaxim | 11:976c80cc99d5 | 322 | // Heart Rate/SpO2 Monitor function takes sample input 'dinIR' and dinRed. |
johnGreeneMaxim | 11:976c80cc99d5 | 323 | // Other inputs: |
johnGreeneMaxim | 11:976c80cc99d5 | 324 | // ns -> Sample Counter, increments with each sample input. |
johnGreeneMaxim | 11:976c80cc99d5 | 325 | // SampRate -> Input data real-time sample rate. |
johnGreeneMaxim | 11:976c80cc99d5 | 326 | // dinLShft -> Number of left shifts for data to be 16 bit wide. |
johnGreeneMaxim | 11:976c80cc99d5 | 327 | // compSpO2 -> If '1' compute SpO2 value,else compute HR only. |
johnGreeneMaxim | 11:976c80cc99d5 | 328 | |
johnGreeneMaxim | 11:976c80cc99d5 | 329 | // |
johnGreeneMaxim | 11:976c80cc99d5 | 330 | // Outputs: |
johnGreeneMaxim | 11:976c80cc99d5 | 331 | // ir_ac_comp -> AC component of the IR signal. |
johnGreeneMaxim | 11:976c80cc99d5 | 332 | // red_ac_comp -> AC component of the Red signal. |
johnGreeneMaxim | 11:976c80cc99d5 | 333 | // ir_ac_mag -> Peak to Peak magnitude of the IR signal. |
johnGreeneMaxim | 11:976c80cc99d5 | 334 | // red_ac_mag -> Peak to Peak magnitude of the Red signal. |
johnGreeneMaxim | 11:976c80cc99d5 | 335 | // HRbpm -> Heart Rate in beats per minute. |
johnGreeneMaxim | 11:976c80cc99d5 | 336 | // SpO2 -> SpO2 value as %saturation. |
johnGreeneMaxim | 11:976c80cc99d5 | 337 | // DRdy -> '1' when new data is available. |
johnGreeneMaxim | 11:976c80cc99d5 | 338 | // |
johnGreeneMaxim | 11:976c80cc99d5 | 339 | |
johnGreeneMaxim | 11:976c80cc99d5 | 340 | void HRSpO2Func(uint32_t dinIR, uint32_t dinRed, uint32_t dinGreen, uint32_t ns,uint16_t SampRate,uint16_t compSpO2, |
johnGreeneMaxim | 11:976c80cc99d5 | 341 | int16_t *ir_ac_comp,int16_t *red_ac_comp, int16_t *green_ac_comp, int16_t *ir_ac_mag,int16_t *red_ac_mag, |
johnGreeneMaxim | 11:976c80cc99d5 | 342 | int16_t *green_ac_mag, uint16_t *HRbpm2,uint16_t *SpO2B,uint16_t *DRdy ) |
johnGreeneMaxim | 11:976c80cc99d5 | 343 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 344 | static int32_t ir_avg_reg=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 345 | static int32_t red_avg_reg=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 346 | static int32_t green_avg_reg=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 347 | |
johnGreeneMaxim | 11:976c80cc99d5 | 348 | static int16_t ir_ac_sig_cur=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 349 | static int16_t ir_ac_sig_pre; |
johnGreeneMaxim | 11:976c80cc99d5 | 350 | static int16_t ir_ac_sig_min=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 351 | static int16_t ir_ac_sig_max=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 352 | static int16_t ir_avg_est; |
johnGreeneMaxim | 11:976c80cc99d5 | 353 | |
johnGreeneMaxim | 11:976c80cc99d5 | 354 | static int16_t ir_pedge=0, ir_nedge=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 355 | static int16_t ir_pzxic, ir_pzxip; |
johnGreeneMaxim | 11:976c80cc99d5 | 356 | static int16_t ir_nzxic; |
johnGreeneMaxim | 11:976c80cc99d5 | 357 | |
johnGreeneMaxim | 11:976c80cc99d5 | 358 | static int16_t red_ac_sig_cur=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 359 | static int16_t red_ac_sig_min=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 360 | static int16_t red_ac_sig_max=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 361 | static int16_t red_avg_est; |
johnGreeneMaxim | 11:976c80cc99d5 | 362 | |
johnGreeneMaxim | 11:976c80cc99d5 | 363 | static int16_t green_avg_est; |
johnGreeneMaxim | 11:976c80cc99d5 | 364 | static int16_t green_ac_sig_cur=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 365 | //static int16_t green_ac_sig_cur=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 366 | static int16_t green_ac_sig_pre; |
johnGreeneMaxim | 11:976c80cc99d5 | 367 | static int16_t green_ac_sig_max ; |
johnGreeneMaxim | 11:976c80cc99d5 | 368 | static int16_t green_ac_sig_min; |
johnGreeneMaxim | 11:976c80cc99d5 | 369 | static int16_t green_mac_FIFO[5]; |
johnGreeneMaxim | 11:976c80cc99d5 | 370 | int16_t meanGreenMagFIFO; |
johnGreeneMaxim | 11:976c80cc99d5 | 371 | int16_t minAmpForHeartBeat ; |
johnGreeneMaxim | 11:976c80cc99d5 | 372 | |
johnGreeneMaxim | 11:976c80cc99d5 | 373 | uint32_t IRData,RedData, greenData , rnum,rden,rdens; |
johnGreeneMaxim | 11:976c80cc99d5 | 374 | uint16_t zeros_in_HrQue =0 , posCount=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 375 | static uint32_t prevPeakLoc = 0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 376 | static int16_t IrFIFO[100]; |
johnGreeneMaxim | 11:976c80cc99d5 | 377 | static int16_t HrQue[10], lastKnownGoodHr[10]; |
johnGreeneMaxim | 11:976c80cc99d5 | 378 | static int16_t SPO2Que[5]; |
johnGreeneMaxim | 11:976c80cc99d5 | 379 | int16_t SPO2score[5]; |
johnGreeneMaxim | 11:976c80cc99d5 | 380 | static uint16_t HrQindex=0 ,lengthOfposCountExceeding =0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 381 | static uint16_t initHrQueCounter=0 , fingerOff =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 382 | |
johnGreeneMaxim | 11:976c80cc99d5 | 383 | static int16_t HrQueSmoothing[3]; |
johnGreeneMaxim | 11:976c80cc99d5 | 384 | static int16_t SPO2QueSmoothing[3]; |
johnGreeneMaxim | 11:976c80cc99d5 | 385 | |
johnGreeneMaxim | 11:976c80cc99d5 | 386 | int16_t k, j; |
johnGreeneMaxim | 11:976c80cc99d5 | 387 | uint32_t peakLoc ; |
johnGreeneMaxim | 11:976c80cc99d5 | 388 | int16_t bufferIdx1, bufferIdx2; |
johnGreeneMaxim | 11:976c80cc99d5 | 389 | int16_t maxFIFO ,IdxMaxFIFO ; |
johnGreeneMaxim | 11:976c80cc99d5 | 390 | int16_t HRperiod2, HRComp2 ,deltaHR; |
johnGreeneMaxim | 11:976c80cc99d5 | 391 | int16_t cSpO2, SpO2; |
johnGreeneMaxim | 11:976c80cc99d5 | 392 | |
johnGreeneMaxim | 11:976c80cc99d5 | 393 | int16_t HrCount =0, HrSum =0 ,meanGreenMagFIFOcounter =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 394 | int16_t SPO2D ,meanHrQ; |
johnGreeneMaxim | 11:976c80cc99d5 | 395 | int16_t dx[99] ,cumsumX[99]; |
johnGreeneMaxim | 11:976c80cc99d5 | 396 | static int16_t SPO2QueCounter =0 ;//, lastDisplayedHrValue; |
johnGreeneMaxim | 11:976c80cc99d5 | 397 | |
johnGreeneMaxim | 11:976c80cc99d5 | 398 | int16_t validSPO2Count =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 399 | int16_t validSPO2Sum =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 400 | int16_t SPO2scoreAverage= 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 401 | int16_t SPO2scoreSum =0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 402 | // int16_t deltaMeanLastKnownGoodHr=0,meanLastKnownGoodHr =0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 403 | // int16_t counterMeanLastKnownGoodHr =0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 404 | |
johnGreeneMaxim | 11:976c80cc99d5 | 405 | |
johnGreeneMaxim | 11:976c80cc99d5 | 406 | // clear some vars if fresh new start |
johnGreeneMaxim | 11:976c80cc99d5 | 407 | if ((ns ==0) || (fingerOff >300)) { |
johnGreeneMaxim | 11:976c80cc99d5 | 408 | ir_avg_reg=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 409 | red_avg_reg=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 410 | green_avg_reg=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 411 | |
johnGreeneMaxim | 11:976c80cc99d5 | 412 | ir_ac_sig_cur=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 413 | ir_ac_sig_pre=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 414 | ir_ac_sig_min=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 415 | ir_ac_sig_max=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 416 | |
johnGreeneMaxim | 11:976c80cc99d5 | 417 | ir_avg_est=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 418 | green_avg_est =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 419 | red_avg_est =0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 420 | |
johnGreeneMaxim | 11:976c80cc99d5 | 421 | ir_pedge=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 422 | ir_nedge=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 423 | ir_pzxic=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 424 | ir_pzxip =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 425 | ir_nzxic=0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 426 | //ir_nzxip =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 427 | red_ac_sig_cur=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 428 | red_ac_sig_min=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 429 | red_ac_sig_max=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 430 | |
johnGreeneMaxim | 11:976c80cc99d5 | 431 | prevPeakLoc = 0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 432 | bufferIdx1=0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 433 | bufferIdx2=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 434 | HrQindex =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 435 | initHrQueCounter=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 436 | lengthOfposCountExceeding =0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 437 | fingerOff =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 438 | HRComp2 =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 439 | |
johnGreeneMaxim | 11:976c80cc99d5 | 440 | for (k=0 ; k<100 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 441 | IrFIFO[k]= 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 442 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 443 | for (k=0 ; k<10 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 444 | HrQue[k]= 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 445 | lastKnownGoodHr[k]=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 446 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 447 | for (k=0 ; k<3 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 448 | HrQueSmoothing[k]= 70; |
johnGreeneMaxim | 11:976c80cc99d5 | 449 | SPO2QueSmoothing[k]=97; |
johnGreeneMaxim | 11:976c80cc99d5 | 450 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 451 | for (k=0 ; k<5 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 452 | SPO2Que[k] =97; |
johnGreeneMaxim | 11:976c80cc99d5 | 453 | SPO2score[k] =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 454 | green_mac_FIFO[k] =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 455 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 456 | SPO2QueCounter =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 457 | *SpO2B =97; |
johnGreeneMaxim | 11:976c80cc99d5 | 458 | *HRbpm2 = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 459 | *DRdy =0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 460 | |
johnGreeneMaxim | 11:976c80cc99d5 | 461 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 462 | |
johnGreeneMaxim | 11:976c80cc99d5 | 463 | |
johnGreeneMaxim | 11:976c80cc99d5 | 464 | // Save current state |
johnGreeneMaxim | 11:976c80cc99d5 | 465 | green_ac_sig_pre = green_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 466 | // |
johnGreeneMaxim | 11:976c80cc99d5 | 467 | // Process next data sample |
johnGreeneMaxim | 11:976c80cc99d5 | 468 | minAmpForHeartBeat =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 469 | IRData = dinIR; |
johnGreeneMaxim | 11:976c80cc99d5 | 470 | RedData = dinRed; |
johnGreeneMaxim | 11:976c80cc99d5 | 471 | greenData = dinGreen ; |
johnGreeneMaxim | 11:976c80cc99d5 | 472 | |
johnGreeneMaxim | 11:976c80cc99d5 | 473 | ir_avg_est = avg_dc_est(&ir_avg_reg,IRData); |
johnGreeneMaxim | 11:976c80cc99d5 | 474 | red_avg_est = avg_dc_est(&red_avg_reg,RedData); |
johnGreeneMaxim | 11:976c80cc99d5 | 475 | green_avg_est = avg_dc_est(&green_avg_reg,greenData); |
johnGreeneMaxim | 11:976c80cc99d5 | 476 | |
johnGreeneMaxim | 11:976c80cc99d5 | 477 | lp_dfir_flt((uint16_t)(IRData - ir_avg_est),(uint16_t)(RedData - red_avg_est), |
johnGreeneMaxim | 11:976c80cc99d5 | 478 | (uint16_t)(greenData - green_avg_est), &ir_ac_sig_cur,&red_ac_sig_cur,&green_ac_sig_cur); |
johnGreeneMaxim | 11:976c80cc99d5 | 479 | |
johnGreeneMaxim | 11:976c80cc99d5 | 480 | |
johnGreeneMaxim | 11:976c80cc99d5 | 481 | *ir_ac_comp = ir_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 482 | *red_ac_comp = red_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 483 | *green_ac_comp = green_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 484 | |
johnGreeneMaxim | 11:976c80cc99d5 | 485 | //save to FIFO |
johnGreeneMaxim | 11:976c80cc99d5 | 486 | for (k=1 ; k<100 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 487 | IrFIFO[100 -k]= IrFIFO[99-k]; |
johnGreeneMaxim | 11:976c80cc99d5 | 488 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 489 | IrFIFO[0] = green_ac_sig_cur ; // invert |
johnGreeneMaxim | 11:976c80cc99d5 | 490 | for (k=0 ; k<97 ; k++) |
johnGreeneMaxim | 11:976c80cc99d5 | 491 | dx[k]= IrFIFO[k+2]-IrFIFO[k] ; |
johnGreeneMaxim | 11:976c80cc99d5 | 492 | dx[97]= dx[96]; |
johnGreeneMaxim | 11:976c80cc99d5 | 493 | dx[98]=dx[96]; |
johnGreeneMaxim | 11:976c80cc99d5 | 494 | |
johnGreeneMaxim | 11:976c80cc99d5 | 495 | for (k=0 ; k<99 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 496 | if (dx[k] > 0 ) |
johnGreeneMaxim | 11:976c80cc99d5 | 497 | dx[k]=1; |
johnGreeneMaxim | 11:976c80cc99d5 | 498 | else |
johnGreeneMaxim | 11:976c80cc99d5 | 499 | dx[k] = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 500 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 501 | |
johnGreeneMaxim | 11:976c80cc99d5 | 502 | cumsumX[0] =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 503 | for (k=1; k<99 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 504 | if (dx[k]>0 ) |
johnGreeneMaxim | 11:976c80cc99d5 | 505 | cumsumX[k]= cumsumX[k-1] + dx[k] ; |
johnGreeneMaxim | 11:976c80cc99d5 | 506 | else |
johnGreeneMaxim | 11:976c80cc99d5 | 507 | cumsumX[k]= 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 508 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 509 | // determine noise |
johnGreeneMaxim | 11:976c80cc99d5 | 510 | // ignore less than 3 conseuctive non-zeros's |
johnGreeneMaxim | 11:976c80cc99d5 | 511 | // detect # of sign change |
johnGreeneMaxim | 11:976c80cc99d5 | 512 | posCount=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 513 | for (k=1; k<99 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 514 | if (cumsumX[k]>0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 515 | posCount ++ ; |
johnGreeneMaxim | 11:976c80cc99d5 | 516 | } else if (cumsumX[k]==0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 517 | if (posCount<4 && k>=4) { |
johnGreeneMaxim | 11:976c80cc99d5 | 518 | for ( j= k-1; j> k-posCount-1; j--) |
johnGreeneMaxim | 11:976c80cc99d5 | 519 | cumsumX[j]=0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 520 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 521 | posCount =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 522 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 523 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 524 | // ignore less than 3 conseuctive zeros's |
johnGreeneMaxim | 11:976c80cc99d5 | 525 | |
johnGreeneMaxim | 11:976c80cc99d5 | 526 | posCount=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 527 | for (k=1; k<99 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 528 | if (cumsumX[k]==0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 529 | posCount ++ ; |
johnGreeneMaxim | 11:976c80cc99d5 | 530 | } else if (cumsumX[k] > 0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 531 | if (posCount<4 && k>=4) { |
johnGreeneMaxim | 11:976c80cc99d5 | 532 | for ( j= k-1; j> k-posCount-1; j--) |
johnGreeneMaxim | 11:976c80cc99d5 | 533 | cumsumX[j]=100 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 534 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 535 | posCount =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 536 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 537 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 538 | |
johnGreeneMaxim | 11:976c80cc99d5 | 539 | //// detect # of sign change |
johnGreeneMaxim | 11:976c80cc99d5 | 540 | posCount=0; // sign change counter |
johnGreeneMaxim | 11:976c80cc99d5 | 541 | for (k=0; k<98 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 542 | if (cumsumX[k]==0 && cumsumX[k+1] > 0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 543 | posCount ++; |
johnGreeneMaxim | 11:976c80cc99d5 | 544 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 545 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 546 | if (posCount>=4) { |
johnGreeneMaxim | 11:976c80cc99d5 | 547 | lengthOfposCountExceeding ++ ; |
johnGreeneMaxim | 11:976c80cc99d5 | 548 | // printf("PosCount =%i \n", posCount ); |
johnGreeneMaxim | 11:976c80cc99d5 | 549 | } else |
johnGreeneMaxim | 11:976c80cc99d5 | 550 | lengthOfposCountExceeding = 0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 551 | // Detect IR channel positive zero crossing (rising edge) |
johnGreeneMaxim | 11:976c80cc99d5 | 552 | if ((green_ac_sig_pre < 0) && (green_ac_sig_cur >= 0) && fingerOff==0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 553 | |
johnGreeneMaxim | 11:976c80cc99d5 | 554 | *ir_ac_mag = ir_ac_sig_max - ir_ac_sig_min; |
johnGreeneMaxim | 11:976c80cc99d5 | 555 | *red_ac_mag = red_ac_sig_max - red_ac_sig_min; |
johnGreeneMaxim | 11:976c80cc99d5 | 556 | *green_ac_mag = green_ac_sig_max - green_ac_sig_min; |
johnGreeneMaxim | 11:976c80cc99d5 | 557 | if ( *green_ac_mag>0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 558 | for (k=0; k<4 ; k++) |
johnGreeneMaxim | 11:976c80cc99d5 | 559 | green_mac_FIFO[k]=green_mac_FIFO[k+1]; |
johnGreeneMaxim | 11:976c80cc99d5 | 560 | green_mac_FIFO[4] = *green_ac_mag ; |
johnGreeneMaxim | 11:976c80cc99d5 | 561 | if ( green_mac_FIFO[4] > 1000) |
johnGreeneMaxim | 11:976c80cc99d5 | 562 | green_mac_FIFO[4] =1000; |
johnGreeneMaxim | 11:976c80cc99d5 | 563 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 564 | meanGreenMagFIFO=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 565 | meanGreenMagFIFOcounter=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 566 | for (k=0; k<5 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 567 | if( green_mac_FIFO[k] >0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 568 | meanGreenMagFIFO= meanGreenMagFIFO +green_mac_FIFO[k] ; |
johnGreeneMaxim | 11:976c80cc99d5 | 569 | meanGreenMagFIFOcounter++; |
johnGreeneMaxim | 11:976c80cc99d5 | 570 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 571 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 572 | if (meanGreenMagFIFOcounter>=2 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 573 | meanGreenMagFIFO =meanGreenMagFIFO/ meanGreenMagFIFOcounter ; |
johnGreeneMaxim | 11:976c80cc99d5 | 574 | minAmpForHeartBeat= meanGreenMagFIFO /4 ; //25% of mean of past heart beat |
johnGreeneMaxim | 11:976c80cc99d5 | 575 | } else |
johnGreeneMaxim | 11:976c80cc99d5 | 576 | minAmpForHeartBeat = 75; |
johnGreeneMaxim | 11:976c80cc99d5 | 577 | if (minAmpForHeartBeat <75) |
johnGreeneMaxim | 11:976c80cc99d5 | 578 | minAmpForHeartBeat =75; |
johnGreeneMaxim | 11:976c80cc99d5 | 579 | if (minAmpForHeartBeat >400) |
johnGreeneMaxim | 11:976c80cc99d5 | 580 | minAmpForHeartBeat =400; |
johnGreeneMaxim | 11:976c80cc99d5 | 581 | |
johnGreeneMaxim | 11:976c80cc99d5 | 582 | ir_pedge = 1; |
johnGreeneMaxim | 11:976c80cc99d5 | 583 | ir_nedge = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 584 | ir_ac_sig_max = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 585 | ir_pzxip = ir_pzxic; |
johnGreeneMaxim | 11:976c80cc99d5 | 586 | ir_pzxic = ns; |
johnGreeneMaxim | 11:976c80cc99d5 | 587 | bufferIdx1= ir_pzxic- ir_nzxic; |
johnGreeneMaxim | 11:976c80cc99d5 | 588 | bufferIdx2 = ir_pzxic -ir_pzxip; |
johnGreeneMaxim | 11:976c80cc99d5 | 589 | |
johnGreeneMaxim | 11:976c80cc99d5 | 590 | |
johnGreeneMaxim | 11:976c80cc99d5 | 591 | if ((*green_ac_mag)> minAmpForHeartBeat && (*green_ac_mag)< 20000 && bufferIdx1>=0 |
johnGreeneMaxim | 11:976c80cc99d5 | 592 | && bufferIdx1 <100 && bufferIdx2>=0 && bufferIdx2 <100 && bufferIdx1< bufferIdx2 ) { // was <5000 |
johnGreeneMaxim | 11:976c80cc99d5 | 593 | maxFIFO = -32766; |
johnGreeneMaxim | 11:976c80cc99d5 | 594 | |
johnGreeneMaxim | 11:976c80cc99d5 | 595 | IdxMaxFIFO = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 596 | for ( j=bufferIdx1; j<= bufferIdx2; j++) { // find max peak |
johnGreeneMaxim | 11:976c80cc99d5 | 597 | if (IrFIFO[j] > maxFIFO ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 598 | maxFIFO =IrFIFO[j]; |
johnGreeneMaxim | 11:976c80cc99d5 | 599 | IdxMaxFIFO =j; |
johnGreeneMaxim | 11:976c80cc99d5 | 600 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 601 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 602 | peakLoc= ir_pzxic -IdxMaxFIFO+1 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 603 | |
johnGreeneMaxim | 11:976c80cc99d5 | 604 | if (prevPeakLoc !=0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 605 | HRperiod2 =( uint16_t) (peakLoc - prevPeakLoc); |
johnGreeneMaxim | 11:976c80cc99d5 | 606 | if (HRperiod2>33 && HRperiod2 < 134) { |
johnGreeneMaxim | 11:976c80cc99d5 | 607 | HRComp2= (6000/HRperiod2); |
johnGreeneMaxim | 11:976c80cc99d5 | 608 | fingerOff =0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 609 | } else |
johnGreeneMaxim | 11:976c80cc99d5 | 610 | HRComp2=0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 611 | } else |
johnGreeneMaxim | 11:976c80cc99d5 | 612 | HRComp2 = 0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 613 | |
johnGreeneMaxim | 11:976c80cc99d5 | 614 | if ( initHrQueCounter<10 && HRComp2 >0 ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 615 | HrQue[HrQindex] =HRComp2; |
johnGreeneMaxim | 11:976c80cc99d5 | 616 | HrQindex++; |
johnGreeneMaxim | 11:976c80cc99d5 | 617 | initHrQueCounter ++; |
johnGreeneMaxim | 11:976c80cc99d5 | 618 | if (HrQindex== 10) |
johnGreeneMaxim | 11:976c80cc99d5 | 619 | HrQindex =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 620 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 621 | |
johnGreeneMaxim | 11:976c80cc99d5 | 622 | if (initHrQueCounter > 7 && lengthOfposCountExceeding<=3) { |
johnGreeneMaxim | 11:976c80cc99d5 | 623 | if ( HRComp2 > 0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 624 | |
johnGreeneMaxim | 11:976c80cc99d5 | 625 | HrCount =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 626 | HrSum =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 627 | zeros_in_HrQue=0; |
johnGreeneMaxim | 11:976c80cc99d5 | 628 | for (k=1 ; k<initHrQueCounter ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 629 | if (HrQue[k] >0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 630 | HrSum +=HrQue[k]; |
johnGreeneMaxim | 11:976c80cc99d5 | 631 | HrCount ++; |
johnGreeneMaxim | 11:976c80cc99d5 | 632 | } else |
johnGreeneMaxim | 11:976c80cc99d5 | 633 | zeros_in_HrQue ++; |
johnGreeneMaxim | 11:976c80cc99d5 | 634 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 635 | meanHrQ = HrSum/HrCount ; |
johnGreeneMaxim | 11:976c80cc99d5 | 636 | deltaHR= lastKnownGoodHr[0]/10; |
johnGreeneMaxim | 11:976c80cc99d5 | 637 | |
johnGreeneMaxim | 11:976c80cc99d5 | 638 | if ( HRComp2 > lastKnownGoodHr[0] -deltaHR && HRComp2 <lastKnownGoodHr[0] +deltaHR ) { |
johnGreeneMaxim | 11:976c80cc99d5 | 639 | for (k=1 ; k<10 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 640 | HrQue[10 -k]= HrQue[9-k]; |
johnGreeneMaxim | 11:976c80cc99d5 | 641 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 642 | HrQue[0] =HRComp2; |
johnGreeneMaxim | 11:976c80cc99d5 | 643 | } // HR smmothing using FIFO queue - |
johnGreeneMaxim | 11:976c80cc99d5 | 644 | |
johnGreeneMaxim | 11:976c80cc99d5 | 645 | if (zeros_in_HrQue<=2) { |
johnGreeneMaxim | 11:976c80cc99d5 | 646 | for (k=1 ; k<3 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 647 | HrQueSmoothing[3 -k]= HrQueSmoothing[2-k]; |
johnGreeneMaxim | 11:976c80cc99d5 | 648 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 649 | HrQueSmoothing[0] = meanHrQ ; |
johnGreeneMaxim | 11:976c80cc99d5 | 650 | HRComp2 = ( (HrQueSmoothing[0]<<2) + (HrQueSmoothing[1]<<1) + (HrQueSmoothing[2] <<1) ) >>3; |
johnGreeneMaxim | 11:976c80cc99d5 | 651 | *HRbpm2 =HRComp2 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 652 | |
johnGreeneMaxim | 11:976c80cc99d5 | 653 | for (k=1 ; k<10 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 654 | lastKnownGoodHr[10 -k]= lastKnownGoodHr[9-k]; |
johnGreeneMaxim | 11:976c80cc99d5 | 655 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 656 | lastKnownGoodHr[0] =HRComp2; |
johnGreeneMaxim | 11:976c80cc99d5 | 657 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 658 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 659 | |
johnGreeneMaxim | 11:976c80cc99d5 | 660 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 661 | ///// if (initHrQueCounter > 7 && lengthOfposCountExceeding<5) |
johnGreeneMaxim | 11:976c80cc99d5 | 662 | else if (initHrQueCounter < 7) { // before que is filled up, display whatever it got. |
johnGreeneMaxim | 11:976c80cc99d5 | 663 | *HRbpm2 = HRComp2; |
johnGreeneMaxim | 11:976c80cc99d5 | 664 | |
johnGreeneMaxim | 11:976c80cc99d5 | 665 | } else { |
johnGreeneMaxim | 11:976c80cc99d5 | 666 | // *HRbpm2 = 0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 667 | HrCount =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 668 | HrSum =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 669 | for (k=0 ; k<10 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 670 | if (lastKnownGoodHr[k] >0) { |
johnGreeneMaxim | 11:976c80cc99d5 | 671 | HrSum =HrSum + lastKnownGoodHr[k]; |
johnGreeneMaxim | 11:976c80cc99d5 | 672 | HrCount++; |
johnGreeneMaxim | 11:976c80cc99d5 | 673 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 674 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 675 | if (HrCount>0) |
johnGreeneMaxim | 11:976c80cc99d5 | 676 | *HRbpm2 = HrSum/HrCount; |
johnGreeneMaxim | 11:976c80cc99d5 | 677 | else |
johnGreeneMaxim | 11:976c80cc99d5 | 678 | *HRbpm2 = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 679 | |
johnGreeneMaxim | 11:976c80cc99d5 | 680 | |
johnGreeneMaxim | 11:976c80cc99d5 | 681 | |
johnGreeneMaxim | 11:976c80cc99d5 | 682 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 683 | prevPeakLoc = peakLoc ; // save peakLoc into Static var |
johnGreeneMaxim | 11:976c80cc99d5 | 684 | |
johnGreeneMaxim | 11:976c80cc99d5 | 685 | |
johnGreeneMaxim | 11:976c80cc99d5 | 686 | if (compSpO2) { |
johnGreeneMaxim | 11:976c80cc99d5 | 687 | rnum = (ir_avg_reg >> 20)*(*red_ac_mag); |
johnGreeneMaxim | 11:976c80cc99d5 | 688 | rden = (red_avg_reg >> 20)*(*ir_ac_mag); |
johnGreeneMaxim | 11:976c80cc99d5 | 689 | rdens = (rden>>15); |
johnGreeneMaxim | 11:976c80cc99d5 | 690 | if (rdens>0) cSpO2 = 110- (((25*rnum)/(rdens))>>15); |
johnGreeneMaxim | 11:976c80cc99d5 | 691 | |
johnGreeneMaxim | 11:976c80cc99d5 | 692 | if (cSpO2 >=100) SpO2 = 100; |
johnGreeneMaxim | 11:976c80cc99d5 | 693 | else if (cSpO2 <= 70) SpO2 = 70; |
johnGreeneMaxim | 11:976c80cc99d5 | 694 | else SpO2 = cSpO2; |
johnGreeneMaxim | 11:976c80cc99d5 | 695 | |
johnGreeneMaxim | 11:976c80cc99d5 | 696 | SPO2Que[SPO2QueCounter ] = SpO2; |
johnGreeneMaxim | 11:976c80cc99d5 | 697 | |
johnGreeneMaxim | 11:976c80cc99d5 | 698 | for (k=0 ; k<5 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 699 | SPO2score[k] =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 700 | for (j=0 ; j< 5 ; j++) |
johnGreeneMaxim | 11:976c80cc99d5 | 701 | if( abs( SPO2Que[k] - SPO2Que[j] )>5) |
johnGreeneMaxim | 11:976c80cc99d5 | 702 | SPO2score[k] ++; |
johnGreeneMaxim | 11:976c80cc99d5 | 703 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 704 | |
johnGreeneMaxim | 11:976c80cc99d5 | 705 | |
johnGreeneMaxim | 11:976c80cc99d5 | 706 | SPO2scoreSum= 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 707 | for (k=0 ; k<5 ; k++) |
johnGreeneMaxim | 11:976c80cc99d5 | 708 | SPO2scoreSum += SPO2score[k] ; |
johnGreeneMaxim | 11:976c80cc99d5 | 709 | SPO2scoreAverage= SPO2scoreSum / 5; |
johnGreeneMaxim | 11:976c80cc99d5 | 710 | for (k=1 ; k<5 ; k++) |
johnGreeneMaxim | 11:976c80cc99d5 | 711 | SPO2score[k] = SPO2score[k] -SPO2scoreAverage; |
johnGreeneMaxim | 11:976c80cc99d5 | 712 | |
johnGreeneMaxim | 11:976c80cc99d5 | 713 | validSPO2Count =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 714 | validSPO2Sum =0; |
johnGreeneMaxim | 11:976c80cc99d5 | 715 | for (k=1 ; k<5 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 716 | if (SPO2score[k]<=0 ) { // add for HR to report |
johnGreeneMaxim | 11:976c80cc99d5 | 717 | validSPO2Sum +=SPO2Que[k]; |
johnGreeneMaxim | 11:976c80cc99d5 | 718 | validSPO2Count ++; |
johnGreeneMaxim | 11:976c80cc99d5 | 719 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 720 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 721 | if ( validSPO2Count>0) |
johnGreeneMaxim | 11:976c80cc99d5 | 722 | SPO2D = (validSPO2Sum /validSPO2Count)-1; |
johnGreeneMaxim | 11:976c80cc99d5 | 723 | if ( SPO2D >100) |
johnGreeneMaxim | 11:976c80cc99d5 | 724 | SPO2D = 100; |
johnGreeneMaxim | 11:976c80cc99d5 | 725 | |
johnGreeneMaxim | 11:976c80cc99d5 | 726 | SPO2QueCounter ++; |
johnGreeneMaxim | 11:976c80cc99d5 | 727 | if (SPO2QueCounter ==5) SPO2QueCounter = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 728 | |
johnGreeneMaxim | 11:976c80cc99d5 | 729 | for (k=1 ; k<3 ; k++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 730 | SPO2QueSmoothing[3 -k]= SPO2QueSmoothing[2-k]; |
johnGreeneMaxim | 11:976c80cc99d5 | 731 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 732 | SPO2QueSmoothing[0] = SPO2D; |
johnGreeneMaxim | 11:976c80cc99d5 | 733 | *SpO2B = ( (SPO2QueSmoothing[0]<<2) + (SPO2QueSmoothing[1]<<1) + (SPO2QueSmoothing[2] <<1) ) >>3; |
johnGreeneMaxim | 11:976c80cc99d5 | 734 | |
johnGreeneMaxim | 11:976c80cc99d5 | 735 | if (*SpO2B> 100) *SpO2B = 100 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 736 | |
johnGreeneMaxim | 11:976c80cc99d5 | 737 | } else { |
johnGreeneMaxim | 11:976c80cc99d5 | 738 | SpO2 = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 739 | *SpO2B = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 740 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 741 | *DRdy = 1; |
johnGreeneMaxim | 11:976c80cc99d5 | 742 | |
johnGreeneMaxim | 11:976c80cc99d5 | 743 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 744 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 745 | // Detect IR channel negative zero crossing (falling edge) |
johnGreeneMaxim | 11:976c80cc99d5 | 746 | if ((green_ac_sig_pre > 0) && (green_ac_sig_cur <= 0)) { |
johnGreeneMaxim | 11:976c80cc99d5 | 747 | ir_pedge = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 748 | ir_nedge = 1; |
johnGreeneMaxim | 11:976c80cc99d5 | 749 | ir_ac_sig_min = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 750 | ir_nzxic = ns; |
johnGreeneMaxim | 11:976c80cc99d5 | 751 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 752 | // Find Maximum IR & Red values in positive cycle |
johnGreeneMaxim | 11:976c80cc99d5 | 753 | if (ir_pedge && (green_ac_sig_cur > green_ac_sig_pre)) { |
johnGreeneMaxim | 11:976c80cc99d5 | 754 | ir_ac_sig_max = ir_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 755 | red_ac_sig_max = red_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 756 | green_ac_sig_max = green_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 757 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 758 | |
johnGreeneMaxim | 11:976c80cc99d5 | 759 | // Find minimum IR & Red values in negative cycle |
johnGreeneMaxim | 11:976c80cc99d5 | 760 | if (ir_nedge && (green_ac_sig_cur < green_ac_sig_pre)) { |
johnGreeneMaxim | 11:976c80cc99d5 | 761 | ir_ac_sig_min = ir_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 762 | red_ac_sig_min = red_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 763 | green_ac_sig_min = green_ac_sig_cur; |
johnGreeneMaxim | 11:976c80cc99d5 | 764 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 765 | if (IRData <50000 ) |
johnGreeneMaxim | 11:976c80cc99d5 | 766 | // finger-off |
johnGreeneMaxim | 11:976c80cc99d5 | 767 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 768 | fingerOff++; |
johnGreeneMaxim | 11:976c80cc99d5 | 769 | *DRdy = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 770 | } else |
johnGreeneMaxim | 11:976c80cc99d5 | 771 | fingerOff = 0 ; |
johnGreeneMaxim | 11:976c80cc99d5 | 772 | /*if (IRData <50000 && fingerOff>10 ) |
johnGreeneMaxim | 11:976c80cc99d5 | 773 | fingerOff = 0; */ |
johnGreeneMaxim | 11:976c80cc99d5 | 774 | if ( *SpO2B == 0 || *HRbpm2 ==0) |
johnGreeneMaxim | 11:976c80cc99d5 | 775 | *DRdy = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 776 | |
johnGreeneMaxim | 11:976c80cc99d5 | 777 | /*if (ns > 2000 ) |
johnGreeneMaxim | 11:976c80cc99d5 | 778 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 779 | if (abs(lastDisplayedHrValue - *HRbpm2)>5) |
johnGreeneMaxim | 11:976c80cc99d5 | 780 | *HRbpm2 =lastDisplayedHrValue ; |
johnGreeneMaxim | 11:976c80cc99d5 | 781 | else |
johnGreeneMaxim | 11:976c80cc99d5 | 782 | lastDisplayedHrValue = *HRbpm2; |
johnGreeneMaxim | 11:976c80cc99d5 | 783 | }*/ |
johnGreeneMaxim | 11:976c80cc99d5 | 784 | // *DRdy = minAmpForHeartBeat; |
johnGreeneMaxim | 11:976c80cc99d5 | 785 | |
johnGreeneMaxim | 11:976c80cc99d5 | 786 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 787 | |
johnGreeneMaxim | 11:976c80cc99d5 | 788 | // Average DC Estimator |
johnGreeneMaxim | 11:976c80cc99d5 | 789 | uint16_t avg_dc_est(int32_t *p, uint16_t x) |
johnGreeneMaxim | 11:976c80cc99d5 | 790 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 791 | *p += ((((int32_t) x << 15) - *p)>>4); |
johnGreeneMaxim | 11:976c80cc99d5 | 792 | return (*p >> 15); |
johnGreeneMaxim | 11:976c80cc99d5 | 793 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 794 | |
johnGreeneMaxim | 11:976c80cc99d5 | 795 | // Symmetric Dual Low Pass FIR Filter |
johnGreeneMaxim | 11:976c80cc99d5 | 796 | void lp_dfir_flt(int16_t din0,int16_t din1,int16_t din2, int16_t *dout0,int16_t *dout1,int16_t *dout2) |
johnGreeneMaxim | 11:976c80cc99d5 | 797 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 798 | static const uint16_t FIRCoeffs[12] = {688,1283,2316,3709,5439,7431, |
johnGreeneMaxim | 11:976c80cc99d5 | 799 | 9561,11666,13563,15074,16047,16384 |
johnGreeneMaxim | 11:976c80cc99d5 | 800 | }; |
johnGreeneMaxim | 11:976c80cc99d5 | 801 | |
johnGreeneMaxim | 11:976c80cc99d5 | 802 | static int16_t cbuf0[32],cbuf1[32] , cbuf2[32]; |
johnGreeneMaxim | 11:976c80cc99d5 | 803 | static int16_t offset = 0; |
johnGreeneMaxim | 11:976c80cc99d5 | 804 | int32_t y0,y1, y2; |
johnGreeneMaxim | 11:976c80cc99d5 | 805 | int16_t i; |
johnGreeneMaxim | 11:976c80cc99d5 | 806 | |
johnGreeneMaxim | 11:976c80cc99d5 | 807 | cbuf0[offset] = din0; |
johnGreeneMaxim | 11:976c80cc99d5 | 808 | cbuf1[offset] = din1; |
johnGreeneMaxim | 11:976c80cc99d5 | 809 | cbuf2[offset] = din2; |
johnGreeneMaxim | 11:976c80cc99d5 | 810 | |
johnGreeneMaxim | 11:976c80cc99d5 | 811 | y0 = mul16(FIRCoeffs[11], cbuf0[(offset - 11)&0x1F]); |
johnGreeneMaxim | 11:976c80cc99d5 | 812 | y1 = mul16(FIRCoeffs[11], cbuf1[(offset - 11)&0x1F]); |
johnGreeneMaxim | 11:976c80cc99d5 | 813 | y2 = mul16(FIRCoeffs[11], cbuf2[(offset - 11)&0x1F]); |
johnGreeneMaxim | 11:976c80cc99d5 | 814 | |
johnGreeneMaxim | 11:976c80cc99d5 | 815 | |
johnGreeneMaxim | 11:976c80cc99d5 | 816 | for (i=0; i<11; i++) { |
johnGreeneMaxim | 11:976c80cc99d5 | 817 | y0 += mul16(FIRCoeffs[i], cbuf0[(offset-i)&0x1F] + cbuf0[(offset-22+i)&0x1F]); |
johnGreeneMaxim | 11:976c80cc99d5 | 818 | y1 += mul16(FIRCoeffs[i], cbuf1[(offset-i)&0x1F] + cbuf1[(offset-22+i)&0x1F]); |
johnGreeneMaxim | 11:976c80cc99d5 | 819 | y2 += mul16(FIRCoeffs[i], cbuf2[(offset-i)&0x1F] + cbuf2[(offset-22+i)&0x1F]); |
johnGreeneMaxim | 11:976c80cc99d5 | 820 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 821 | offset = (offset + 1)&0x1F; |
johnGreeneMaxim | 11:976c80cc99d5 | 822 | |
johnGreeneMaxim | 11:976c80cc99d5 | 823 | *dout0 = (y0>>15); |
johnGreeneMaxim | 11:976c80cc99d5 | 824 | *dout1 = (y1>>15); |
johnGreeneMaxim | 11:976c80cc99d5 | 825 | *dout2 = (y2>>15); |
johnGreeneMaxim | 11:976c80cc99d5 | 826 | } |
johnGreeneMaxim | 11:976c80cc99d5 | 827 | |
johnGreeneMaxim | 11:976c80cc99d5 | 828 | // Integer multiplier |
johnGreeneMaxim | 11:976c80cc99d5 | 829 | int32_t mul16(int16_t x, int16_t y) |
johnGreeneMaxim | 11:976c80cc99d5 | 830 | { |
johnGreeneMaxim | 11:976c80cc99d5 | 831 | return (int32_t)(x* y); |
johnGreeneMaxim | 8:a1538e8a3fd9 | 832 | } |