Greg Toth / Mbed OS MAX30101WING_HR_SPO2

Dependencies:   MAX30101 MAX32620FTHR

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?

UserRevisionLine numberNew contents of line
coreyharris 5:2f708191f1bd 1 /*******************************************************************************
coreyharris 5:2f708191f1bd 2 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
coreyharris 5:2f708191f1bd 3 *
coreyharris 5:2f708191f1bd 4 * Permission is hereby granted, free of charge, to any person obtaining a
coreyharris 5:2f708191f1bd 5 * copy of this software and associated documentation files (the "Software"),
coreyharris 5:2f708191f1bd 6 * to deal in the Software without restriction, including without limitation
coreyharris 5:2f708191f1bd 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
coreyharris 5:2f708191f1bd 8 * and/or sell copies of the Software, and to permit persons to whom the
coreyharris 5:2f708191f1bd 9 * Software is furnished to do so, subject to the following conditions:
coreyharris 5:2f708191f1bd 10 *
coreyharris 5:2f708191f1bd 11 * The above copyright notice and this permission notice shall be included
coreyharris 5:2f708191f1bd 12 * in all copies or substantial portions of the Software.
coreyharris 5:2f708191f1bd 13 *
coreyharris 5:2f708191f1bd 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
coreyharris 5:2f708191f1bd 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
coreyharris 5:2f708191f1bd 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
coreyharris 5:2f708191f1bd 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
coreyharris 5:2f708191f1bd 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
coreyharris 5:2f708191f1bd 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
coreyharris 5:2f708191f1bd 20 * OTHER DEALINGS IN THE SOFTWARE.
coreyharris 5:2f708191f1bd 21 *
coreyharris 5:2f708191f1bd 22 * Except as contained in this notice, the name of Maxim Integrated
coreyharris 5:2f708191f1bd 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
coreyharris 5:2f708191f1bd 24 * Products, Inc. Branding Policy.
coreyharris 5:2f708191f1bd 25 *
coreyharris 5:2f708191f1bd 26 * The mere transfer of this software does not imply any licenses
coreyharris 5:2f708191f1bd 27 * of trade secrets, proprietary technology, copyrights, patents,
coreyharris 5:2f708191f1bd 28 * trademarks, maskwork rights, or any other form of intellectual
coreyharris 5:2f708191f1bd 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
coreyharris 5:2f708191f1bd 30 * ownership rights.
coreyharris 5:2f708191f1bd 31 *******************************************************************************
coreyharris 5:2f708191f1bd 32 */
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 }