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