Demo program for the MAX30101WING that calculates heart rate and SpO2 data.

Dependencies:   MAX30101 max32630fthr

Fork of MAX30101_HR_SPO2 by John Greene

Committer:
johnGreeneMaxim
Date:
Thu Mar 08 16:29:29 2018 +0000
Revision:
13:ef4a84158e4c
Parent:
12:ac85295f8713
revised parsing algorithm

Who changed what in which revision?

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