MAX86150 code

Dependencies:   mbed

Fork of MAX86150_ECG_PPG by Bidet Remote

Committer:
laserdad
Date:
Wed Jan 04 17:00:04 2017 +0000
Revision:
0:74fff521858e
Child:
1:f62247cbeac6
Working version (all features--I think). I moved interrupt pin to d12 (which works). I sped up I2C to 1MHz (not recommended by mfg, but seems to be fine) for data taking, but left it at 400kHz for setting registers.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
laserdad 0:74fff521858e 1
laserdad 0:74fff521858e 2 //********************************************** Arduino code
laserdad 0:74fff521858e 3 /* This program configures and reads data from the MAX86150 ECG/PPG (BioZ to come) ASIC from Maxim Integrated.
laserdad 0:74fff521858e 4 * Originally writter for Arduino. The MAX86150r4 or MAX86150r8 boards work well (others are noisy).
laserdad 0:74fff521858e 5 * Keep ECG electrodes as short as possible. Due to the nature of this chip low frequency RC filters cannot be used.
laserdad 0:74fff521858e 6 * Note the ECG input oscillates when not loaded with human body impedance.
laserdad 0:74fff521858e 7 * ECG inputs have internal ESD protection.
laserdad 0:74fff521858e 8 * Configuration is done by the initMAX86150() subroutine. Register settings are per recommendations from JY Kim at Maxim.
laserdad 0:74fff521858e 9 * In the global declarations are several options for enabling 4 kinds of measurements: PPG (IR and R), ECG, and ETI.
laserdad 0:74fff521858e 10 * The flex FIFO will be configured to order the selected measurements exactly in that order: first PPG, then ECG, then ETI.
laserdad 0:74fff521858e 11 * If PPG is not enabled (ppgOn=0), then the first data point will be ECG. If ecg is not enabled then the only data input will be ETI.
laserdad 0:74fff521858e 12 * This program uses by default the A-full interrupt which alerts when the FIFO is almost full. It does not attempt to read the entire FIFO,
laserdad 0:74fff521858e 13 * but rather reads a fixed number of samples. This operation is important because the ASIC can't update the FIFO while we are in the middle
laserdad 0:74fff521858e 14 * of an I2C transaction, so we have to keep I2C transactions short.
laserdad 0:74fff521858e 15 * Note the program limits the number of samples which can be read according to a specified I2C buffer size which will depend on the HW and
laserdad 0:74fff521858e 16 * library you use. For Arduino the default is 32 bytes.
laserdad 0:74fff521858e 17 * ECG data and PPG data are different. PPG data is unipolar 18 bits and has garbage in the MSBs that has to be masked.
laserdad 0:74fff521858e 18 * ECG data is bipolar (2's complement), 17 bits and has to have the MSBs masked with FFF.. if the signal is negative.
laserdad 0:74fff521858e 19 * ECG data is displayed with a short IIR noise filter and longer IIR baseline removal filter. The filter length is specified in bits
laserdad 0:74fff521858e 20 * so the math can be done with integers using register shifting, rather than floats.
laserdad 0:74fff521858e 21 * This chip practically requires at least 400kHZ i2c speed for ECG readout. (I have a query in to Maxim to see if it unofficially supports 1MHz.)
laserdad 0:74fff521858e 22 * ETI is electrical tissue impedance, a few kHz sampling of impedance to check for presence of user's fingers. This is not a datasheet feature.
laserdad 0:74fff521858e 23 * ETI settings were delivered by Maxim.
laserdad 0:74fff521858e 24 * ECG comes too fast to read every EOC interrupt. Either read every few interrupts or use AFULL int.
laserdad 0:74fff521858e 25 * PPG data is measured at a much lower rate than ECG, but data is buffered through in the FIFO, showing the most recent sample.
laserdad 0:74fff521858e 26 * To reduce data rate it would be possible to only send PPG data when it changes. Otherwise ECG can be filtered down to the PPG data rate and
laserdad 0:74fff521858e 27 * filtered data sent at a the reduced bandwidth (what Maxim does on their BLE EV kit).
laserdad 0:74fff521858e 28 *
laserdad 0:74fff521858e 29 * IMPORTANT: Maxim recommends to read the FIFO pointer after getting data to make sure it changed. I have not implemented that yet.
laserdad 0:74fff521858e 30 * Basically, if you try to read the FIFO during the few clock cycles while it is being updated (a rare but eventual event),
laserdad 0:74fff521858e 31 * then the FIFO data will be garbage. You have to reread the FIFO.
laserdad 0:74fff521858e 32 *
laserdad 0:74fff521858e 33 * BTW I am not convinced it is possible to mix PPG and ETI in the same row of the flex FIFO. Eg. FD2= ECG, FD1 = PPG
laserdad 0:74fff521858e 34 *
laserdad 0:74fff521858e 35 * Note: IR and R LED power should be closed loop controlled to an optimal region above 90% of full scale for best resolution.
laserdad 0:74fff521858e 36 * (Not yet implemented).
laserdad 0:74fff521858e 37 *
laserdad 0:74fff521858e 38 * Note: PPG system uses sophisticated background subtraction to cancel ambient light flicker and large ambient light signals (sunlight).
laserdad 0:74fff521858e 39 * This is important for finger measurements, but less important for measurements indoors under the thigh, for example, where a generic
laserdad 0:74fff521858e 40 * light source and LED can be used in DC operation.
laserdad 0:74fff521858e 41 *
laserdad 0:74fff521858e 42 * Note the PPG ADC uses feedback cancellation from the current source to reduce noise. No LED current will result in noisy ADC readings.
laserdad 0:74fff521858e 43 * In other words you can't measure ADC noise without LED current. There are test registers not available to us which can disconnect the photodiode and
laserdad 0:74fff521858e 44 * measure with noise with test currents on the chip.
laserdad 0:74fff521858e 45 *
laserdad 0:74fff521858e 46 * Note ASIC has configurable on-chip PPG averaging if-desired (prior to being written to FIFO).
laserdad 0:74fff521858e 47 */
laserdad 0:74fff521858e 48 #include "mbed.h"
laserdad 0:74fff521858e 49 #include "math.h"
laserdad 0:74fff521858e 50 //Register definitions
laserdad 0:74fff521858e 51 #define MAX86150_Addr 0xBC //updated per I2Cscanner, 8 bit version of 7 bit code 0x5E
laserdad 0:74fff521858e 52 #define InterruptStatusReg1 0x00 //Interrupt status byte 0 (read both bytes 0x00 and 0x01 when checking int status)
laserdad 0:74fff521858e 53 #define InterruptStatusReg2 0x01
laserdad 0:74fff521858e 54 #define InterruptEnableReg1 0x02 //Interrupt enable byte 0
laserdad 0:74fff521858e 55 #define InterruptEnableReg2 0x03
laserdad 0:74fff521858e 56 #define FIFOWritePointerReg 0x04
laserdad 0:74fff521858e 57 #define OverflowCounterReg 0x05
laserdad 0:74fff521858e 58 #define FIFOReadPointerReg 0x06
laserdad 0:74fff521858e 59 #define FIFODataReg 0x07
laserdad 0:74fff521858e 60 #define FIFOConfigReg 0x08
laserdad 0:74fff521858e 61 #define FIFODataControlReg1 0x09
laserdad 0:74fff521858e 62 #define FIFODataControlReg2 0x0A
laserdad 0:74fff521858e 63 #define SystemControlReg 0x0D
laserdad 0:74fff521858e 64 #define ppgConfigReg0 0x0E
laserdad 0:74fff521858e 65 #define ppgConfigReg1 0x0F
laserdad 0:74fff521858e 66 #define ProxIntThreshReg 0x10
laserdad 0:74fff521858e 67 #define LED1PulseAmpReg 0x11
laserdad 0:74fff521858e 68 #define LED2PulseAmpReg 0x12
laserdad 0:74fff521858e 69 #define LEDRangeReg 0x14
laserdad 0:74fff521858e 70 #define LEDPilotPAReg 0x15
laserdad 0:74fff521858e 71 #define EcgConfigReg1 0x3C
laserdad 0:74fff521858e 72 #define EcgConfigReg2 0x3D
laserdad 0:74fff521858e 73 #define EcgConfigReg3 0x3E
laserdad 0:74fff521858e 74 #define EcgConfigReg4 0x3F
laserdad 0:74fff521858e 75 #define PartIDReg 0xFF
laserdad 0:74fff521858e 76 #define maxi2cFreq 1000000
laserdad 0:74fff521858e 77 #define recommendedi2cFreq 400000
laserdad 0:74fff521858e 78 #define maxECGrate 0
laserdad 0:74fff521858e 79 #define normECGrate 1
laserdad 0:74fff521858e 80 const int16_t i2cBufferSize=32;
laserdad 0:74fff521858e 81
laserdad 0:74fff521858e 82 //global variables
laserdad 0:74fff521858e 83
laserdad 0:74fff521858e 84 //USER SELECTABLE****************************
laserdad 0:74fff521858e 85 const uint8_t ppgOn = 1; //turn on PPG (IR and Red both)
laserdad 0:74fff521858e 86 const uint8_t ecgOn = 1; //turn on ECG measurement
laserdad 0:74fff521858e 87 const uint8_t etiOn = 1; //turn on ETI (lead check) electrical tissue impedance. Checks if your fingers are on or not.
laserdad 0:74fff521858e 88 const uint8_t ecgRate = maxECGrate; //use normECGrate 800Hz or maxECGrate 1600Hz
laserdad 0:74fff521858e 89 const int16_t printEvery = 5 *(2-ecgRate); //print data only every X samples to reduce serial data BW (print fewer for faster sampling)
laserdad 0:74fff521858e 90 const int16_t ppgBits2Avg = 0; //log(2) of IIR filter divisor, data = data + (new_data-data)>>bits2Avg for PPG IR and R, use 0 for no averaging
laserdad 0:74fff521858e 91 const int16_t ecgBits2Avg = 3 + (1-ecgRate);; //(Recommend 3) log(2) of IIR filter divisor, data = data + (new_data-data)>>bits2Avg for ECG, use 0 for no averaging, or 4 with fast rate
laserdad 0:74fff521858e 92 const int16_t etiBits2Avg = 0; //log(2) of IIR filter divisor, data = data + (new_data-data)>>bits2Avg for ETI, use 0 for no averaging
laserdad 0:74fff521858e 93 const int16_t ppgBaselineBits = 9; //log(2) of baseline IIR filter divisor for PPG IR and PPG R, use 0 for no baseline removal
laserdad 0:74fff521858e 94 const int16_t ecgBaselineBits = 9; //(Recommend 9-10)log(2) of baseline IIR filter divisor for ecg, use 0 for no baseline removal
laserdad 0:74fff521858e 95 const int16_t etiBaselineBits = 0; //log(2) of baseline IIR filter divisor for eti, use 0 for no baseline removal
laserdad 0:74fff521858e 96 const uint8_t rCurrent = 0x50; //PPG LED current (when enabled), max=0xFF (255)
laserdad 0:74fff521858e 97 const uint8_t irCurrent = 0x50; //PPG LED current (when enabled), max=0xFF (255) in increments of 0.2mA or 0.4mA if hi pwr is enabled.
laserdad 0:74fff521858e 98 const uint8_t redHiPWR = 0; //0 = use normal pwr level (recommended for PPG). Note hi pwr is useful for proximity detection.
laserdad 0:74fff521858e 99 const uint8_t irHiPWR = 0; //0 = use normal pwr level (recommended for PPG). Note hi pwr is useful for proximity detection.
laserdad 0:74fff521858e 100
laserdad 0:74fff521858e 101 bool runSetup =1; //tells program to reprogram ASIC (used on startup)
laserdad 0:74fff521858e 102 //***************************************
laserdad 0:74fff521858e 103
laserdad 0:74fff521858e 104 //USER SELECTABLE (though not recommended)
laserdad 0:74fff521858e 105 const uint8_t ppgRdyIntEn = 0; //not using ppgRdyInt (too slow)
laserdad 0:74fff521858e 106 const uint8_t ecgRdyIntEn = 0; //not using ECG_RDY interrrupt. It will interrupt frequently if this is enabled (too fast)
laserdad 0:74fff521858e 107 //**************************************
laserdad 0:74fff521858e 108
laserdad 0:74fff521858e 109 //NOT USER CONFIGURABLE******************
laserdad 0:74fff521858e 110
laserdad 0:74fff521858e 111 #define interrupt_pin D12 //INTB pin --see InterruptIn declaration
laserdad 0:74fff521858e 112 const int16_t irChannel = ppgOn-1; //-1 or 0
laserdad 0:74fff521858e 113 const int16_t rChannel = ppgOn*(2)-1; //-1 or 1
laserdad 0:74fff521858e 114 const int16_t ecgChannel = ecgOn*(1+2*ppgOn)-1; //-1, 0, or 2
laserdad 0:74fff521858e 115 const int16_t etiChannel = etiOn*(1+ecgOn+2*ppgOn)-1; //-1, 0,1 or 3
laserdad 0:74fff521858e 116 const uint8_t numMeasEnabled = 2*ppgOn + ecgOn + etiOn; //Index # of how many measurements will be in each block of the FIFO
laserdad 0:74fff521858e 117 const uint8_t bytesPerSample = 3*numMeasEnabled; //each measurement is 3bytes
laserdad 0:74fff521858e 118 const int16_t samples2Read = i2cBufferSize / bytesPerSample ; //assuming 32 byte I2C buffer default
laserdad 0:74fff521858e 119 const uint8_t almostFullIntEn = 1; //priority to AFULL vs. PPG in code
laserdad 0:74fff521858e 120 const char bytes2Read = bytesPerSample*samples2Read;
laserdad 0:74fff521858e 121 char i2cWriteBuffer[10];
laserdad 0:74fff521858e 122 char i2cReadBuffer[i2cBufferSize]; //32 bytes in i2c buffer size in Arduino by default.
laserdad 0:74fff521858e 123 unsigned long tim = 0; //for counting milliseconds
laserdad 0:74fff521858e 124 volatile bool intFlagged = 0; //ISR variable
laserdad 0:74fff521858e 125 long data[4][5]; //data from the first measurement type
laserdad 0:74fff521858e 126 long dataAvg[4]; //currently using data1 for ECG. This variable stores the IIR filtered avg.
laserdad 0:74fff521858e 127 long dataBaseline[4]; //this variable stores the few second baseline for substraction (IIR filter)
laserdad 0:74fff521858e 128 int ind = 0; //index to keep track of whether to print data or not (not printing every sample to serial monitor b/c it is too slow)
laserdad 0:74fff521858e 129 int bits2Avg[4]; //array stores the selected averaging time constants set below for filtering (loaded in setup)
laserdad 0:74fff521858e 130 int bits2AvgBaseline[4]; //stores below filter time constants (loaded in setup)
laserdad 0:74fff521858e 131 char FIFOData[bytes2Read];
laserdad 0:74fff521858e 132
laserdad 0:74fff521858e 133
laserdad 0:74fff521858e 134
laserdad 0:74fff521858e 135 //setup I2C, serial connection and timer
laserdad 0:74fff521858e 136 InterruptIn intPin(interrupt_pin); //config p5 as interrupt
laserdad 0:74fff521858e 137 I2C i2c(I2C_SDA,I2C_SCL);
laserdad 0:74fff521858e 138 Serial pc(USBTX,USBRX,NULL,230400); //open serial port (optionally add device name and baud rate after specifying TX and RX pins)
laserdad 0:74fff521858e 139
laserdad 0:74fff521858e 140
laserdad 0:74fff521858e 141 //declare subroutines
laserdad 0:74fff521858e 142 void writeRegister(uint8_t addr, uint8_t reg, uint8_t val) {
laserdad 0:74fff521858e 143 /*writes 1 byte to a single register*/
laserdad 0:74fff521858e 144 char writeData[2];
laserdad 0:74fff521858e 145 writeData[0] = reg ;
laserdad 0:74fff521858e 146 writeData[1] = val;
laserdad 0:74fff521858e 147 i2c.write(addr,writeData, 2);
laserdad 0:74fff521858e 148 }
laserdad 0:74fff521858e 149
laserdad 0:74fff521858e 150 void writeBlock(uint8_t addr, uint8_t startReg, uint8_t *data, uint8_t numBytes) {
laserdad 0:74fff521858e 151 /*writes data from an array beginning at the startReg*/
laserdad 0:74fff521858e 152 char writeData[numBytes+1];
laserdad 0:74fff521858e 153 writeData[0]=startReg;
laserdad 0:74fff521858e 154 for(int n=1;n<numBytes;n++) {
laserdad 0:74fff521858e 155 writeData[n]=data[n-1];
laserdad 0:74fff521858e 156 }
laserdad 0:74fff521858e 157 i2c.write(addr,writeData,numBytes+1);
laserdad 0:74fff521858e 158 }
laserdad 0:74fff521858e 159
laserdad 0:74fff521858e 160 void readRegisters(uint8_t addr, uint8_t startReg, char *regData, int numBytes) {
laserdad 0:74fff521858e 161 char writeData = startReg;
laserdad 0:74fff521858e 162 i2c.write(addr,&writeData,1,true); //true is for repeated start
laserdad 0:74fff521858e 163 i2c.read(addr,regData,numBytes);
laserdad 0:74fff521858e 164 }
laserdad 0:74fff521858e 165
laserdad 0:74fff521858e 166 //clears interrupts
laserdad 0:74fff521858e 167 void clearInterrupts(char *data) {
laserdad 0:74fff521858e 168 readRegisters(MAX86150_Addr,InterruptStatusReg1,data,1);
laserdad 0:74fff521858e 169 }
laserdad 0:74fff521858e 170
laserdad 0:74fff521858e 171 void regDump(uint8_t Addr, uint8_t startByte, uint8_t endByte) {
laserdad 0:74fff521858e 172 /*print the values of up to 20 registers*/
laserdad 0:74fff521858e 173 char regData[20];
laserdad 0:74fff521858e 174 int numBytes;
laserdad 0:74fff521858e 175 if (endByte>=startByte) {
laserdad 0:74fff521858e 176 numBytes = (endByte-startByte+1) < 20 ? (endByte-startByte+1) : 20;
laserdad 0:74fff521858e 177 }
laserdad 0:74fff521858e 178 else {
laserdad 0:74fff521858e 179 numBytes=1;
laserdad 0:74fff521858e 180 }
laserdad 0:74fff521858e 181
laserdad 0:74fff521858e 182 regData[0] = startByte;
laserdad 0:74fff521858e 183 i2c.write(Addr,regData,1,true);
laserdad 0:74fff521858e 184 i2c.read(Addr, regData, numBytes);
laserdad 0:74fff521858e 185 for(int n=0;n<numBytes;n++) {
laserdad 0:74fff521858e 186 pc.printf("%X, %X \r\n", startByte+n, regData[n]);
laserdad 0:74fff521858e 187 }
laserdad 0:74fff521858e 188 }
laserdad 0:74fff521858e 189
laserdad 0:74fff521858e 190 bool bitRead(long data, uint8_t bitNum) {
laserdad 0:74fff521858e 191 long mask = 1<<bitNum;
laserdad 0:74fff521858e 192 long masked_bit = data & mask;
laserdad 0:74fff521858e 193 return masked_bit >> bitNum;
laserdad 0:74fff521858e 194 }
laserdad 0:74fff521858e 195
laserdad 0:74fff521858e 196 void intEvent(void) {
laserdad 0:74fff521858e 197 intFlagged = 1;
laserdad 0:74fff521858e 198 }
laserdad 0:74fff521858e 199
laserdad 0:74fff521858e 200 void initMAX86150(void) {
laserdad 0:74fff521858e 201 pc.printf("Initializing MAX86150\r\n");
laserdad 0:74fff521858e 202
laserdad 0:74fff521858e 203 //print configurations
laserdad 0:74fff521858e 204 pc.printf( (ppgOn ? "PPG on" : "PPG off") );
laserdad 0:74fff521858e 205 pc.printf( (ecgOn ? ", ECG On" : ", ECG off") );
laserdad 0:74fff521858e 206 pc.printf( (etiOn ? ", ETI On\r\n" : ", ETI off\r\n") );
laserdad 0:74fff521858e 207 pc.printf( (ppgRdyIntEn ? "PPG Int On" : "PPG Int off") );
laserdad 0:74fff521858e 208 pc.printf( (ecgRdyIntEn ? ", ECG Int On" : ", ECG Int off") );
laserdad 0:74fff521858e 209 pc.printf( (almostFullIntEn ? ", Afull Int On\r\n" : ", Afull Int off\r\n") );
laserdad 0:74fff521858e 210 //write register configurations
laserdad 0:74fff521858e 211 writeRegister(MAX86150_Addr,SystemControlReg,0x01); //chip reset
laserdad 0:74fff521858e 212 wait_ms(2); //wait for chip to come back on line
laserdad 0:74fff521858e 213 //if PPG or ETI are not enabled, then FIFO is setup for ECG
laserdad 0:74fff521858e 214 writeRegister(MAX86150_Addr,FIFOConfigReg,0x1F); // [4] FIFO_ROLLS_ON_FULL, clears with status read or FIFO_data read
laserdad 0:74fff521858e 215 uint16_t FIFOCode;
laserdad 0:74fff521858e 216 FIFOCode = etiOn ? 0x000A : 0x0000 ; //ETI is last in FIFO
laserdad 0:74fff521858e 217 FIFOCode = ecgOn ? (FIFOCode<<4 | 0x0009) : FIFOCode; //insert ECG front of ETI in FIFO
laserdad 0:74fff521858e 218 FIFOCode = ppgOn ? (FIFOCode<<8 | 0x0021) : FIFOCode; //insert Red(2) and IR (1) in front of ECG in FIFO
laserdad 0:74fff521858e 219 writeRegister(MAX86150_Addr,FIFODataControlReg1, (char)(FIFOCode & 0x00FF) );
laserdad 0:74fff521858e 220 writeRegister(MAX86150_Addr,FIFODataControlReg2, (char)(FIFOCode >>8) );
laserdad 0:74fff521858e 221 writeRegister(MAX86150_Addr, ppgConfigReg0,0b11010111); //D3 for 100Hz, PPG_ADC_RGE: 32768nA, PPG_SR: 100SpS, PPG_LED_PW: 400uS
laserdad 0:74fff521858e 222 writeRegister(MAX86150_Addr,LED1PulseAmpReg, ppgOn ? rCurrent : 0x00 );
laserdad 0:74fff521858e 223 writeRegister(MAX86150_Addr,LED2PulseAmpReg, ppgOn ? irCurrent : 0x00);
laserdad 0:74fff521858e 224 writeRegister(MAX86150_Addr,LEDRangeReg, irHiPWR * 2 + redHiPWR ); // PPG_ADC_RGE: 32768nA
laserdad 0:74fff521858e 225 //ecg configuration
laserdad 0:74fff521858e 226 if (ecgOn) {
laserdad 0:74fff521858e 227 //****************************************
laserdad 0:74fff521858e 228 //ECG data rate is user configurable in theory, but you have to adjust your filter time constants and serial printEvery variables accordingly
laserdad 0:74fff521858e 229 writeRegister(MAX86150_Addr,EcgConfigReg1,ecgRate); //ECG sample rate 0x00 =1600, 0x01=800Hz etc down to 200Hz. add 4 to double frequency (double ADC clock)
laserdad 0:74fff521858e 230 writeRegister(MAX86150_Addr,EcgConfigReg2,0x11); //hidden register at ECG config 2, per JY's settings
laserdad 0:74fff521858e 231 writeRegister(MAX86150_Addr,EcgConfigReg3,0x3D); //ECG config 3
laserdad 0:74fff521858e 232 writeRegister(MAX86150_Addr,EcgConfigReg4,0x02); //ECG config 4 per JY's settings
laserdad 0:74fff521858e 233 //enter test mode
laserdad 0:74fff521858e 234 writeRegister(MAX86150_Addr,0xFF,0x54); //write 0x54 to register 0xFF
laserdad 0:74fff521858e 235 writeRegister(MAX86150_Addr,0xFF,0x4D); //write 0x4D to register 0xFF
laserdad 0:74fff521858e 236 writeRegister(MAX86150_Addr,0xCE,0x01);
laserdad 0:74fff521858e 237 writeRegister(MAX86150_Addr,0xCF,0x18); //adjust hidden registers at CE and CF per JY's settings in EV kit
laserdad 0:74fff521858e 238 writeRegister(MAX86150_Addr,0xD0,0x01); //adjust hidden registers D0 (probably ETI)
laserdad 0:74fff521858e 239 writeRegister(MAX86150_Addr,0xFF,0x00); //exit test mode
laserdad 0:74fff521858e 240 }
laserdad 0:74fff521858e 241 //setup interrupts last
laserdad 0:74fff521858e 242 writeRegister(MAX86150_Addr,InterruptEnableReg1,( almostFullIntEn ? 0x80 : (ppgRdyIntEn ? 0x40 : 0x00) ) );
laserdad 0:74fff521858e 243 writeRegister(MAX86150_Addr,InterruptEnableReg2, (ecgRdyIntEn ? 0x04 : 0x00) );
laserdad 0:74fff521858e 244 writeRegister(MAX86150_Addr,SystemControlReg,0x04);//start FIFO
laserdad 0:74fff521858e 245
laserdad 0:74fff521858e 246 pc.printf("done configuring MAX86150\r\n");
laserdad 0:74fff521858e 247 } //end initMAX86150
laserdad 0:74fff521858e 248
laserdad 0:74fff521858e 249
laserdad 0:74fff521858e 250 bool readFIFO(int numSamples, char *fifodata) {
laserdad 0:74fff521858e 251 char stat[1];
laserdad 0:74fff521858e 252 bool dataValid = 0;
laserdad 0:74fff521858e 253 uint8_t tries = 0;
laserdad 0:74fff521858e 254 char newReadPointer;
laserdad 0:74fff521858e 255 clearInterrupts(stat);
laserdad 0:74fff521858e 256 //get FIFO position
laserdad 0:74fff521858e 257 readRegisters(MAX86150_Addr, FIFOReadPointerReg, i2cReadBuffer, 1); //you can do more sophisticated stuff looking for missed samples, but I'm keeping this lean and simple
laserdad 0:74fff521858e 258 char readPointer = i2cReadBuffer[0];
laserdad 0:74fff521858e 259 while(!dataValid) {
laserdad 0:74fff521858e 260 tries++;
laserdad 0:74fff521858e 261 //try reading FIFO
laserdad 0:74fff521858e 262 readRegisters(MAX86150_Addr, FIFODataReg, fifodata, bytes2Read); //get data
laserdad 0:74fff521858e 263 //see if it worked if you are not servicing interrupts faster than the sample rate
laserdad 0:74fff521858e 264 //if you are servicing interrupts much faster than the sample rate, then you can get rid of the extra pointer register check.
laserdad 0:74fff521858e 265 dataValid=1;
laserdad 0:74fff521858e 266 //readRegisters(MAX86150_Addr, FIFOReadPointerReg, i2cReadBuffer, 1); //check that the read pointer has moved (otherwise FIFO was being written to)
laserdad 0:74fff521858e 267 // newReadPointer = i2cReadBuffer[0];
laserdad 0:74fff521858e 268 // if( (newReadPointer - readPointer == numSamples) || (newReadPointer+32 -readPointer ==numSamples ) ){ //check that we got the right number of samples (including FIFO pointer wrap around possiblity)
laserdad 0:74fff521858e 269 // dataValid=1;
laserdad 0:74fff521858e 270 // return 1;
laserdad 0:74fff521858e 271 // }
laserdad 0:74fff521858e 272 // else if (tries > 1) { //if it failed twice, you've got a different problem perhaps, exiting with error code (0) so you can void the data
laserdad 0:74fff521858e 273 // break;
laserdad 0:74fff521858e 274 // }
laserdad 0:74fff521858e 275 // else {
laserdad 0:74fff521858e 276 // wait_us(100); //try again a moment later
laserdad 0:74fff521858e 277 // }
laserdad 0:74fff521858e 278 }
laserdad 0:74fff521858e 279 return dataValid;
laserdad 0:74fff521858e 280 } //end readFIFO
laserdad 0:74fff521858e 281
laserdad 0:74fff521858e 282 //for serial monitoring
laserdad 0:74fff521858e 283 void printData(uint16_t numSamples,char *fifodata) {
laserdad 0:74fff521858e 284 //cat and mask the bits from the FIFO
laserdad 0:74fff521858e 285 for (int n = 0; n < numSamples; n++) { //for every sample
laserdad 0:74fff521858e 286 char p = bytesPerSample;
laserdad 0:74fff521858e 287 for (int m=0;m<numMeasEnabled;m++) { //for every enabled measurement
laserdad 0:74fff521858e 288 data[m][n] = ( (long)(fifodata[p*n +3*m] & 0x7) << 16) | ( (long)fifodata[p*n + 1+3*m] << 8) | ( (long)fifodata[p*n + 2+3*m]);
laserdad 0:74fff521858e 289 if (bitRead(data[m][n], 17) && ( (ecgChannel==m) || (etiChannel==m) ) ) {//handle ECG and ETI differently than PPG data. data[m][n] |= 0xFFFC0000;
laserdad 0:74fff521858e 290 data[m][n] |= 0xFFFC0000;
laserdad 0:74fff521858e 291 }
laserdad 0:74fff521858e 292 }
laserdad 0:74fff521858e 293 }
laserdad 0:74fff521858e 294 for (int n = 0; n < numSamples; n++) { //for every sample
laserdad 0:74fff521858e 295 ind++;
laserdad 0:74fff521858e 296 ind = ind % printEvery;
laserdad 0:74fff521858e 297
laserdad 0:74fff521858e 298 //calc avg and baseline
laserdad 0:74fff521858e 299 for(int m=0;m<numMeasEnabled;m++) { //for every enabled measurement
laserdad 0:74fff521858e 300 dataAvg[m] += ( data[m][n] - dataAvg[m] ) >> bits2Avg[m] ; //get the running average
laserdad 0:74fff521858e 301 dataBaseline[m] += ( data[m][n] - dataBaseline[m] ) >> bits2AvgBaseline[m]; //get the long baseline
laserdad 0:74fff521858e 302 }
laserdad 0:74fff521858e 303
laserdad 0:74fff521858e 304 //print data
laserdad 0:74fff521858e 305 if (ind == 1) { //printing only every specified number of samples to reduce serial traffic to manageable level
laserdad 0:74fff521858e 306 for (int m=0;m<numMeasEnabled;m++) {//for every enabled measurement
laserdad 0:74fff521858e 307 if(bits2AvgBaseline[m]>0) {
laserdad 0:74fff521858e 308 pc.printf("%i, ",dataAvg[m]-dataBaseline[m]); //print with baseline subtraction
laserdad 0:74fff521858e 309 }
laserdad 0:74fff521858e 310 else {
laserdad 0:74fff521858e 311 pc.printf("%i, ", dataAvg[m]); //print without baseline subtraction
laserdad 0:74fff521858e 312 }
laserdad 0:74fff521858e 313 }
laserdad 0:74fff521858e 314 pc.printf("\r\n");
laserdad 0:74fff521858e 315 } //end print loop
laserdad 0:74fff521858e 316 } //end sample loop
laserdad 0:74fff521858e 317 }//end printData()
laserdad 0:74fff521858e 318
laserdad 0:74fff521858e 319
laserdad 0:74fff521858e 320
laserdad 0:74fff521858e 321
laserdad 0:74fff521858e 322 //for debugging
laserdad 0:74fff521858e 323 void printRawFIFO(int numSamples,char *fifodata) {
laserdad 0:74fff521858e 324 // Serial.print("FIFO bytes ");
laserdad 0:74fff521858e 325 for (int n = 0; n < numSamples; n++) {//for every sample.
laserdad 0:74fff521858e 326 for (int m=0;m<numMeasEnabled;m++) {//for every kind of measurement
laserdad 0:74fff521858e 327 pc.printf("%d: ",m);
laserdad 0:74fff521858e 328 pc.printf("%x, %x, %x, ",fifodata[bytesPerSample * n +3*m], fifodata[bytesPerSample * n + 1 +3*m], fifodata[bytesPerSample * n + 2 + 3*m] );
laserdad 0:74fff521858e 329 } //end measurement loop
laserdad 0:74fff521858e 330 pc.printf("\r\n");
laserdad 0:74fff521858e 331 } //end sample loop
laserdad 0:74fff521858e 332 } //end function
laserdad 0:74fff521858e 333
laserdad 0:74fff521858e 334
laserdad 0:74fff521858e 335 void setupASIC(void) {
laserdad 0:74fff521858e 336 pc.printf("Running Setup\r\n");
laserdad 0:74fff521858e 337 runSetup = 0; //only run once
laserdad 0:74fff521858e 338 i2c.frequency(recommendedi2cFreq); //set I2C frequency to 400kHz
laserdad 0:74fff521858e 339 // intPin.mode(PullUp); //pullups on the sensor board
laserdad 0:74fff521858e 340 //configure MAX86150 register settings
laserdad 0:74fff521858e 341 initMAX86150();
laserdad 0:74fff521858e 342 pc.printf("register dump\r\n");
laserdad 0:74fff521858e 343
laserdad 0:74fff521858e 344 // //print register configuration
laserdad 0:74fff521858e 345 // regDump(MAX86150_Addr,0x00, 0x06);
laserdad 0:74fff521858e 346 // regDump(MAX86150_Addr,0x08, 0x15);
laserdad 0:74fff521858e 347 // regDump(MAX86150_Addr,0x3C, 0x3F);
laserdad 0:74fff521858e 348 // //go to test mode
laserdad 0:74fff521858e 349 // writeRegister(MAX86150_Addr,0xFF,0x54);
laserdad 0:74fff521858e 350 // writeRegister(MAX86150_Addr,0xFF,0x4D);
laserdad 0:74fff521858e 351 // regDump(MAX86150_Addr,0xCE, 0xCF);
laserdad 0:74fff521858e 352 // regDump(MAX86150_Addr,0xD0, 0xD0);
laserdad 0:74fff521858e 353 // writeRegister(MAX86150_Addr,0xFF,0x00);
laserdad 0:74fff521858e 354 clearInterrupts(i2cReadBuffer);
laserdad 0:74fff521858e 355 i2c.frequency(maxi2cFreq);
laserdad 0:74fff521858e 356 //configure averaging
laserdad 0:74fff521858e 357 if(ppgOn) {
laserdad 0:74fff521858e 358 bits2Avg[rChannel]=ppgBits2Avg;
laserdad 0:74fff521858e 359 bits2Avg[irChannel]=ppgBits2Avg;
laserdad 0:74fff521858e 360 bits2AvgBaseline[rChannel]=ppgBaselineBits;
laserdad 0:74fff521858e 361 bits2AvgBaseline[irChannel]=ppgBaselineBits;
laserdad 0:74fff521858e 362 }
laserdad 0:74fff521858e 363 if(ecgOn){
laserdad 0:74fff521858e 364 bits2Avg[ecgChannel]=ecgBits2Avg;
laserdad 0:74fff521858e 365 bits2AvgBaseline[ecgChannel]=ecgBaselineBits;
laserdad 0:74fff521858e 366 }
laserdad 0:74fff521858e 367 if(etiOn){
laserdad 0:74fff521858e 368 bits2Avg[etiChannel]=etiBits2Avg;
laserdad 0:74fff521858e 369 bits2AvgBaseline[etiChannel]=etiBaselineBits;
laserdad 0:74fff521858e 370 }
laserdad 0:74fff521858e 371 pc.printf("Done w/setup\r\n");
laserdad 0:74fff521858e 372 }
laserdad 0:74fff521858e 373
laserdad 0:74fff521858e 374
laserdad 0:74fff521858e 375
laserdad 0:74fff521858e 376 int main() {
laserdad 0:74fff521858e 377 char FIFOData[bytesPerSample];
laserdad 0:74fff521858e 378 if(runSetup) {
laserdad 0:74fff521858e 379 setupASIC();
laserdad 0:74fff521858e 380 }
laserdad 0:74fff521858e 381
laserdad 0:74fff521858e 382 intPin.fall(&intEvent);
laserdad 0:74fff521858e 383 while(1) {
laserdad 0:74fff521858e 384 char stat[1];
laserdad 0:74fff521858e 385 static int n = 0;
laserdad 0:74fff521858e 386 if (intFlagged) {
laserdad 0:74fff521858e 387 // pc.printf("intFlagged\r\n");
laserdad 0:74fff521858e 388 if (almostFullIntEn) {
laserdad 0:74fff521858e 389 n = 0;
laserdad 0:74fff521858e 390 intFlagged = 0;
laserdad 0:74fff521858e 391 readFIFO(samples2Read,FIFOData);
laserdad 0:74fff521858e 392 printData(samples2Read,FIFOData);
laserdad 0:74fff521858e 393 // printRawFIFO(samples2Read,FIFOData); //for debugging
laserdad 0:74fff521858e 394 } //end if AFULL
laserdad 0:74fff521858e 395 else { //this is to handle end of conversion interrupts (not configured by default)
laserdad 0:74fff521858e 396 if (n < samples2Read) {
laserdad 0:74fff521858e 397 n++;
laserdad 0:74fff521858e 398 intFlagged = 0;
laserdad 0:74fff521858e 399 clearInterrupts(stat);
laserdad 0:74fff521858e 400 // Serial.println(n);
laserdad 0:74fff521858e 401 }
laserdad 0:74fff521858e 402 else {
laserdad 0:74fff521858e 403 n = 0;
laserdad 0:74fff521858e 404 intFlagged = 0;
laserdad 0:74fff521858e 405 readFIFO(samples2Read,FIFOData);
laserdad 0:74fff521858e 406 printData(samples2Read,FIFOData);
laserdad 0:74fff521858e 407 pc.printf("\r\n");
laserdad 0:74fff521858e 408 // printRawFIFO(samples2Read);
laserdad 0:74fff521858e 409 }
laserdad 0:74fff521858e 410 } //end if/else AFULL
laserdad 0:74fff521858e 411 } //end if intFlagged
laserdad 0:74fff521858e 412 } //end while
laserdad 0:74fff521858e 413
laserdad 0:74fff521858e 414 }//end main
laserdad 0:74fff521858e 415
laserdad 0:74fff521858e 416
laserdad 0:74fff521858e 417
laserdad 0:74fff521858e 418
laserdad 0:74fff521858e 419 /* FYI seee this table for effective 3dB bandwidth for IIR filter given sample rate and number of bits shifted
laserdad 0:74fff521858e 420 * fsample bits f3dB
laserdad 0:74fff521858e 421 * 1600 1 89.6
laserdad 0:74fff521858e 422 * 1600 2 72
laserdad 0:74fff521858e 423 * 1600 3 24
laserdad 0:74fff521858e 424 * 1600 4 8
laserdad 0:74fff521858e 425 * 800 1 44.8
laserdad 0:74fff521858e 426 * 800 2 36
laserdad 0:74fff521858e 427 * 800 3 12
laserdad 0:74fff521858e 428 * 800 4 4
laserdad 0:74fff521858e 429 * 400 1 22.4
laserdad 0:74fff521858e 430 * 400 2 18
laserdad 0:74fff521858e 431 * 400 3 6
laserdad 0:74fff521858e 432 * 400 4 2
laserdad 0:74fff521858e 433 * 200 1 11.2
laserdad 0:74fff521858e 434 * 200 2 9
laserdad 0:74fff521858e 435 * 200 3 3
laserdad 0:74fff521858e 436 * 200 4 1
laserdad 0:74fff521858e 437 */
laserdad 0:74fff521858e 438