MAX86150 code

Dependencies:   mbed

Fork of MAX86150_ECG_PPG by Bidet Remote

Committer:
laserdad
Date:
Wed Jan 04 17:00:53 2017 +0000
Revision:
1:f62247cbeac6
Parent:
0:74fff521858e
Child:
2:c8b7ef52c65c
code formated

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 1:f62247cbeac6 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 1:f62247cbeac6 14 * of an I2C transaction, so we have to keep I2C transactions short.
laserdad 1:f62247cbeac6 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 1:f62247cbeac6 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 1:f62247cbeac6 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 1:f62247cbeac6 31 * then the FIFO data will be garbage. You have to reread the FIFO.
laserdad 1:f62247cbeac6 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 1:f62247cbeac6 34 *
laserdad 1:f62247cbeac6 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 1:f62247cbeac6 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 1:f62247cbeac6 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 1:f62247cbeac6 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 1:f62247cbeac6 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 1:f62247cbeac6 142 void writeRegister(uint8_t addr, uint8_t reg, uint8_t val)
laserdad 1:f62247cbeac6 143 {
laserdad 1:f62247cbeac6 144 /*writes 1 byte to a single register*/
laserdad 0:74fff521858e 145 char writeData[2];
laserdad 0:74fff521858e 146 writeData[0] = reg ;
laserdad 0:74fff521858e 147 writeData[1] = val;
laserdad 0:74fff521858e 148 i2c.write(addr,writeData, 2);
laserdad 0:74fff521858e 149 }
laserdad 0:74fff521858e 150
laserdad 1:f62247cbeac6 151 void writeBlock(uint8_t addr, uint8_t startReg, uint8_t *data, uint8_t numBytes)
laserdad 1:f62247cbeac6 152 {
laserdad 1:f62247cbeac6 153 /*writes data from an array beginning at the startReg*/
laserdad 0:74fff521858e 154 char writeData[numBytes+1];
laserdad 0:74fff521858e 155 writeData[0]=startReg;
laserdad 1:f62247cbeac6 156 for(int n=1; n<numBytes; n++) {
laserdad 0:74fff521858e 157 writeData[n]=data[n-1];
laserdad 0:74fff521858e 158 }
laserdad 0:74fff521858e 159 i2c.write(addr,writeData,numBytes+1);
laserdad 0:74fff521858e 160 }
laserdad 0:74fff521858e 161
laserdad 1:f62247cbeac6 162 void readRegisters(uint8_t addr, uint8_t startReg, char *regData, int numBytes)
laserdad 1:f62247cbeac6 163 {
laserdad 0:74fff521858e 164 char writeData = startReg;
laserdad 0:74fff521858e 165 i2c.write(addr,&writeData,1,true); //true is for repeated start
laserdad 0:74fff521858e 166 i2c.read(addr,regData,numBytes);
laserdad 0:74fff521858e 167 }
laserdad 0:74fff521858e 168
laserdad 0:74fff521858e 169 //clears interrupts
laserdad 1:f62247cbeac6 170 void clearInterrupts(char *data)
laserdad 1:f62247cbeac6 171 {
laserdad 0:74fff521858e 172 readRegisters(MAX86150_Addr,InterruptStatusReg1,data,1);
laserdad 0:74fff521858e 173 }
laserdad 0:74fff521858e 174
laserdad 1:f62247cbeac6 175 void regDump(uint8_t Addr, uint8_t startByte, uint8_t endByte)
laserdad 1:f62247cbeac6 176 {
laserdad 1:f62247cbeac6 177 /*print the values of up to 20 registers*/
laserdad 0:74fff521858e 178 char regData[20];
laserdad 0:74fff521858e 179 int numBytes;
laserdad 0:74fff521858e 180 if (endByte>=startByte) {
laserdad 0:74fff521858e 181 numBytes = (endByte-startByte+1) < 20 ? (endByte-startByte+1) : 20;
laserdad 1:f62247cbeac6 182 } else {
laserdad 0:74fff521858e 183 numBytes=1;
laserdad 1:f62247cbeac6 184 }
laserdad 1:f62247cbeac6 185
laserdad 0:74fff521858e 186 regData[0] = startByte;
laserdad 0:74fff521858e 187 i2c.write(Addr,regData,1,true);
laserdad 0:74fff521858e 188 i2c.read(Addr, regData, numBytes);
laserdad 1:f62247cbeac6 189 for(int n=0; n<numBytes; n++) {
laserdad 1:f62247cbeac6 190 pc.printf("%X, %X \r\n", startByte+n, regData[n]);
laserdad 0:74fff521858e 191 }
laserdad 0:74fff521858e 192 }
laserdad 0:74fff521858e 193
laserdad 1:f62247cbeac6 194 bool bitRead(long data, uint8_t bitNum)
laserdad 1:f62247cbeac6 195 {
laserdad 1:f62247cbeac6 196 long mask = 1<<bitNum;
laserdad 1:f62247cbeac6 197 long masked_bit = data & mask;
laserdad 1:f62247cbeac6 198 return masked_bit >> bitNum;
laserdad 0:74fff521858e 199 }
laserdad 0:74fff521858e 200
laserdad 1:f62247cbeac6 201 void intEvent(void)
laserdad 1:f62247cbeac6 202 {
laserdad 1:f62247cbeac6 203 intFlagged = 1;
laserdad 0:74fff521858e 204 }
laserdad 0:74fff521858e 205
laserdad 1:f62247cbeac6 206 void initMAX86150(void)
laserdad 1:f62247cbeac6 207 {
laserdad 0:74fff521858e 208 pc.printf("Initializing MAX86150\r\n");
laserdad 0:74fff521858e 209
laserdad 1:f62247cbeac6 210 //print configurations
laserdad 0:74fff521858e 211 pc.printf( (ppgOn ? "PPG on" : "PPG off") );
laserdad 0:74fff521858e 212 pc.printf( (ecgOn ? ", ECG On" : ", ECG off") );
laserdad 0:74fff521858e 213 pc.printf( (etiOn ? ", ETI On\r\n" : ", ETI off\r\n") );
laserdad 0:74fff521858e 214 pc.printf( (ppgRdyIntEn ? "PPG Int On" : "PPG Int off") );
laserdad 0:74fff521858e 215 pc.printf( (ecgRdyIntEn ? ", ECG Int On" : ", ECG Int off") );
laserdad 0:74fff521858e 216 pc.printf( (almostFullIntEn ? ", Afull Int On\r\n" : ", Afull Int off\r\n") );
laserdad 0:74fff521858e 217 //write register configurations
laserdad 0:74fff521858e 218 writeRegister(MAX86150_Addr,SystemControlReg,0x01); //chip reset
laserdad 0:74fff521858e 219 wait_ms(2); //wait for chip to come back on line
laserdad 0:74fff521858e 220 //if PPG or ETI are not enabled, then FIFO is setup for ECG
laserdad 0:74fff521858e 221 writeRegister(MAX86150_Addr,FIFOConfigReg,0x1F); // [4] FIFO_ROLLS_ON_FULL, clears with status read or FIFO_data read
laserdad 0:74fff521858e 222 uint16_t FIFOCode;
laserdad 0:74fff521858e 223 FIFOCode = etiOn ? 0x000A : 0x0000 ; //ETI is last in FIFO
laserdad 0:74fff521858e 224 FIFOCode = ecgOn ? (FIFOCode<<4 | 0x0009) : FIFOCode; //insert ECG front of ETI in FIFO
laserdad 0:74fff521858e 225 FIFOCode = ppgOn ? (FIFOCode<<8 | 0x0021) : FIFOCode; //insert Red(2) and IR (1) in front of ECG in FIFO
laserdad 0:74fff521858e 226 writeRegister(MAX86150_Addr,FIFODataControlReg1, (char)(FIFOCode & 0x00FF) );
laserdad 0:74fff521858e 227 writeRegister(MAX86150_Addr,FIFODataControlReg2, (char)(FIFOCode >>8) );
laserdad 1:f62247cbeac6 228 writeRegister(MAX86150_Addr, ppgConfigReg0,0b11010111); //D3 for 100Hz, PPG_ADC_RGE: 32768nA, PPG_SR: 100SpS, PPG_LED_PW: 400uS
laserdad 0:74fff521858e 229 writeRegister(MAX86150_Addr,LED1PulseAmpReg, ppgOn ? rCurrent : 0x00 );
laserdad 0:74fff521858e 230 writeRegister(MAX86150_Addr,LED2PulseAmpReg, ppgOn ? irCurrent : 0x00);
laserdad 0:74fff521858e 231 writeRegister(MAX86150_Addr,LEDRangeReg, irHiPWR * 2 + redHiPWR ); // PPG_ADC_RGE: 32768nA
laserdad 0:74fff521858e 232 //ecg configuration
laserdad 0:74fff521858e 233 if (ecgOn) {
laserdad 0:74fff521858e 234 //****************************************
laserdad 1:f62247cbeac6 235 //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 236 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 237 writeRegister(MAX86150_Addr,EcgConfigReg2,0x11); //hidden register at ECG config 2, per JY's settings
laserdad 0:74fff521858e 238 writeRegister(MAX86150_Addr,EcgConfigReg3,0x3D); //ECG config 3
laserdad 0:74fff521858e 239 writeRegister(MAX86150_Addr,EcgConfigReg4,0x02); //ECG config 4 per JY's settings
laserdad 1:f62247cbeac6 240 //enter test mode
laserdad 0:74fff521858e 241 writeRegister(MAX86150_Addr,0xFF,0x54); //write 0x54 to register 0xFF
laserdad 0:74fff521858e 242 writeRegister(MAX86150_Addr,0xFF,0x4D); //write 0x4D to register 0xFF
laserdad 0:74fff521858e 243 writeRegister(MAX86150_Addr,0xCE,0x01);
laserdad 0:74fff521858e 244 writeRegister(MAX86150_Addr,0xCF,0x18); //adjust hidden registers at CE and CF per JY's settings in EV kit
laserdad 0:74fff521858e 245 writeRegister(MAX86150_Addr,0xD0,0x01); //adjust hidden registers D0 (probably ETI)
laserdad 1:f62247cbeac6 246 writeRegister(MAX86150_Addr,0xFF,0x00); //exit test mode
laserdad 0:74fff521858e 247 }
laserdad 0:74fff521858e 248 //setup interrupts last
laserdad 0:74fff521858e 249 writeRegister(MAX86150_Addr,InterruptEnableReg1,( almostFullIntEn ? 0x80 : (ppgRdyIntEn ? 0x40 : 0x00) ) );
laserdad 0:74fff521858e 250 writeRegister(MAX86150_Addr,InterruptEnableReg2, (ecgRdyIntEn ? 0x04 : 0x00) );
laserdad 0:74fff521858e 251 writeRegister(MAX86150_Addr,SystemControlReg,0x04);//start FIFO
laserdad 1:f62247cbeac6 252
laserdad 0:74fff521858e 253 pc.printf("done configuring MAX86150\r\n");
laserdad 0:74fff521858e 254 } //end initMAX86150
laserdad 0:74fff521858e 255
laserdad 0:74fff521858e 256
laserdad 1:f62247cbeac6 257 bool readFIFO(int numSamples, char *fifodata)
laserdad 1:f62247cbeac6 258 {
laserdad 0:74fff521858e 259 char stat[1];
laserdad 0:74fff521858e 260 bool dataValid = 0;
laserdad 0:74fff521858e 261 uint8_t tries = 0;
laserdad 0:74fff521858e 262 char newReadPointer;
laserdad 0:74fff521858e 263 clearInterrupts(stat);
laserdad 0:74fff521858e 264 //get FIFO position
laserdad 0:74fff521858e 265 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 1:f62247cbeac6 266 char readPointer = i2cReadBuffer[0];
laserdad 1:f62247cbeac6 267 while(!dataValid) {
laserdad 0:74fff521858e 268 tries++;
laserdad 0:74fff521858e 269 //try reading FIFO
laserdad 0:74fff521858e 270 readRegisters(MAX86150_Addr, FIFODataReg, fifodata, bytes2Read); //get data
laserdad 0:74fff521858e 271 //see if it worked if you are not servicing interrupts faster than the sample rate
laserdad 0:74fff521858e 272 //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 273 dataValid=1;
laserdad 1:f62247cbeac6 274 //readRegisters(MAX86150_Addr, FIFOReadPointerReg, i2cReadBuffer, 1); //check that the read pointer has moved (otherwise FIFO was being written to)
laserdad 0:74fff521858e 275 // newReadPointer = i2cReadBuffer[0];
laserdad 0:74fff521858e 276 // 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 277 // dataValid=1;
laserdad 0:74fff521858e 278 // return 1;
laserdad 0:74fff521858e 279 // }
laserdad 0:74fff521858e 280 // 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 281 // break;
laserdad 0:74fff521858e 282 // }
laserdad 0:74fff521858e 283 // else {
laserdad 0:74fff521858e 284 // wait_us(100); //try again a moment later
laserdad 1:f62247cbeac6 285 // }
laserdad 0:74fff521858e 286 }
laserdad 0:74fff521858e 287 return dataValid;
laserdad 0:74fff521858e 288 } //end readFIFO
laserdad 0:74fff521858e 289
laserdad 0:74fff521858e 290 //for serial monitoring
laserdad 1:f62247cbeac6 291 void printData(uint16_t numSamples,char *fifodata)
laserdad 1:f62247cbeac6 292 {
laserdad 1:f62247cbeac6 293 //cat and mask the bits from the FIFO
laserdad 1:f62247cbeac6 294 for (int n = 0; n < numSamples; n++) { //for every sample
laserdad 1:f62247cbeac6 295 char p = bytesPerSample;
laserdad 1:f62247cbeac6 296 for (int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
laserdad 1:f62247cbeac6 297 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 1:f62247cbeac6 298 if (bitRead(data[m][n], 17) && ( (ecgChannel==m) || (etiChannel==m) ) ) {//handle ECG and ETI differently than PPG data. data[m][n] |= 0xFFFC0000;
laserdad 1:f62247cbeac6 299 data[m][n] |= 0xFFFC0000;
laserdad 1:f62247cbeac6 300 }
laserdad 1:f62247cbeac6 301 }
laserdad 0:74fff521858e 302 }
laserdad 1:f62247cbeac6 303 for (int n = 0; n < numSamples; n++) { //for every sample
laserdad 1:f62247cbeac6 304 ind++;
laserdad 1:f62247cbeac6 305 ind = ind % printEvery;
laserdad 1:f62247cbeac6 306
laserdad 1:f62247cbeac6 307 //calc avg and baseline
laserdad 1:f62247cbeac6 308 for(int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
laserdad 1:f62247cbeac6 309 dataAvg[m] += ( data[m][n] - dataAvg[m] ) >> bits2Avg[m] ; //get the running average
laserdad 1:f62247cbeac6 310 dataBaseline[m] += ( data[m][n] - dataBaseline[m] ) >> bits2AvgBaseline[m]; //get the long baseline
laserdad 1:f62247cbeac6 311 }
laserdad 0:74fff521858e 312
laserdad 1:f62247cbeac6 313 //print data
laserdad 1:f62247cbeac6 314 if (ind == 1) { //printing only every specified number of samples to reduce serial traffic to manageable level
laserdad 1:f62247cbeac6 315 for (int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
laserdad 1:f62247cbeac6 316 if(bits2AvgBaseline[m]>0) {
laserdad 1:f62247cbeac6 317 pc.printf("%i, ",dataAvg[m]-dataBaseline[m]); //print with baseline subtraction
laserdad 1:f62247cbeac6 318 } else {
laserdad 1:f62247cbeac6 319 pc.printf("%i, ", dataAvg[m]); //print without baseline subtraction
laserdad 1:f62247cbeac6 320 }
laserdad 1:f62247cbeac6 321 }
laserdad 1:f62247cbeac6 322 pc.printf("\r\n");
laserdad 1:f62247cbeac6 323 } //end print loop
laserdad 1:f62247cbeac6 324 } //end sample loop
laserdad 0:74fff521858e 325 }//end printData()
laserdad 0:74fff521858e 326
laserdad 0:74fff521858e 327
laserdad 0:74fff521858e 328
laserdad 0:74fff521858e 329
laserdad 0:74fff521858e 330 //for debugging
laserdad 1:f62247cbeac6 331 void printRawFIFO(int numSamples,char *fifodata)
laserdad 1:f62247cbeac6 332 {
laserdad 1:f62247cbeac6 333 // Serial.print("FIFO bytes ");
laserdad 1:f62247cbeac6 334 for (int n = 0; n < numSamples; n++) {//for every sample.
laserdad 1:f62247cbeac6 335 for (int m=0; m<numMeasEnabled; m++) { //for every kind of measurement
laserdad 1:f62247cbeac6 336 pc.printf("%d: ",m);
laserdad 1:f62247cbeac6 337 pc.printf("%x, %x, %x, ",fifodata[bytesPerSample * n +3*m], fifodata[bytesPerSample * n + 1 +3*m], fifodata[bytesPerSample * n + 2 + 3*m] );
laserdad 1:f62247cbeac6 338 } //end measurement loop
laserdad 1:f62247cbeac6 339 pc.printf("\r\n");
laserdad 1:f62247cbeac6 340 } //end sample loop
laserdad 0:74fff521858e 341 } //end function
laserdad 0:74fff521858e 342
laserdad 0:74fff521858e 343
laserdad 1:f62247cbeac6 344 void setupASIC(void)
laserdad 1:f62247cbeac6 345 {
laserdad 0:74fff521858e 346 pc.printf("Running Setup\r\n");
laserdad 0:74fff521858e 347 runSetup = 0; //only run once
laserdad 0:74fff521858e 348 i2c.frequency(recommendedi2cFreq); //set I2C frequency to 400kHz
laserdad 0:74fff521858e 349 // intPin.mode(PullUp); //pullups on the sensor board
laserdad 0:74fff521858e 350 //configure MAX86150 register settings
laserdad 0:74fff521858e 351 initMAX86150();
laserdad 1:f62247cbeac6 352 pc.printf("register dump\r\n");
laserdad 0:74fff521858e 353
laserdad 0:74fff521858e 354 // //print register configuration
laserdad 0:74fff521858e 355 // regDump(MAX86150_Addr,0x00, 0x06);
laserdad 0:74fff521858e 356 // regDump(MAX86150_Addr,0x08, 0x15);
laserdad 0:74fff521858e 357 // regDump(MAX86150_Addr,0x3C, 0x3F);
laserdad 0:74fff521858e 358 // //go to test mode
laserdad 0:74fff521858e 359 // writeRegister(MAX86150_Addr,0xFF,0x54);
laserdad 0:74fff521858e 360 // writeRegister(MAX86150_Addr,0xFF,0x4D);
laserdad 0:74fff521858e 361 // regDump(MAX86150_Addr,0xCE, 0xCF);
laserdad 0:74fff521858e 362 // regDump(MAX86150_Addr,0xD0, 0xD0);
laserdad 0:74fff521858e 363 // writeRegister(MAX86150_Addr,0xFF,0x00);
laserdad 0:74fff521858e 364 clearInterrupts(i2cReadBuffer);
laserdad 1:f62247cbeac6 365 i2c.frequency(maxi2cFreq);
laserdad 0:74fff521858e 366 //configure averaging
laserdad 0:74fff521858e 367 if(ppgOn) {
laserdad 0:74fff521858e 368 bits2Avg[rChannel]=ppgBits2Avg;
laserdad 0:74fff521858e 369 bits2Avg[irChannel]=ppgBits2Avg;
laserdad 0:74fff521858e 370 bits2AvgBaseline[rChannel]=ppgBaselineBits;
laserdad 0:74fff521858e 371 bits2AvgBaseline[irChannel]=ppgBaselineBits;
laserdad 0:74fff521858e 372 }
laserdad 1:f62247cbeac6 373 if(ecgOn) {
laserdad 0:74fff521858e 374 bits2Avg[ecgChannel]=ecgBits2Avg;
laserdad 0:74fff521858e 375 bits2AvgBaseline[ecgChannel]=ecgBaselineBits;
laserdad 0:74fff521858e 376 }
laserdad 1:f62247cbeac6 377 if(etiOn) {
laserdad 0:74fff521858e 378 bits2Avg[etiChannel]=etiBits2Avg;
laserdad 0:74fff521858e 379 bits2AvgBaseline[etiChannel]=etiBaselineBits;
laserdad 0:74fff521858e 380 }
laserdad 0:74fff521858e 381 pc.printf("Done w/setup\r\n");
laserdad 0:74fff521858e 382 }
laserdad 0:74fff521858e 383
laserdad 0:74fff521858e 384
laserdad 0:74fff521858e 385
laserdad 1:f62247cbeac6 386 int main()
laserdad 1:f62247cbeac6 387 {
laserdad 0:74fff521858e 388 char FIFOData[bytesPerSample];
laserdad 0:74fff521858e 389 if(runSetup) {
laserdad 0:74fff521858e 390 setupASIC();
laserdad 1:f62247cbeac6 391 }
laserdad 1:f62247cbeac6 392
laserdad 0:74fff521858e 393 intPin.fall(&intEvent);
laserdad 0:74fff521858e 394 while(1) {
laserdad 1:f62247cbeac6 395 char stat[1];
laserdad 1:f62247cbeac6 396 static int n = 0;
laserdad 1:f62247cbeac6 397 if (intFlagged) {
laserdad 0:74fff521858e 398 // pc.printf("intFlagged\r\n");
laserdad 0:74fff521858e 399 if (almostFullIntEn) {
laserdad 0:74fff521858e 400 n = 0;
laserdad 0:74fff521858e 401 intFlagged = 0;
laserdad 0:74fff521858e 402 readFIFO(samples2Read,FIFOData);
laserdad 0:74fff521858e 403 printData(samples2Read,FIFOData);
laserdad 1:f62247cbeac6 404 // printRawFIFO(samples2Read,FIFOData); //for debugging
laserdad 1:f62247cbeac6 405 } //end if AFULL
laserdad 1:f62247cbeac6 406 else { //this is to handle end of conversion interrupts (not configured by default)
laserdad 1:f62247cbeac6 407 if (n < samples2Read) {
laserdad 1:f62247cbeac6 408 n++;
laserdad 1:f62247cbeac6 409 intFlagged = 0;
laserdad 1:f62247cbeac6 410 clearInterrupts(stat);
laserdad 1:f62247cbeac6 411 // Serial.println(n);
laserdad 1:f62247cbeac6 412 } else {
laserdad 1:f62247cbeac6 413 n = 0;
laserdad 1:f62247cbeac6 414 intFlagged = 0;
laserdad 1:f62247cbeac6 415 readFIFO(samples2Read,FIFOData);
laserdad 1:f62247cbeac6 416 printData(samples2Read,FIFOData);
laserdad 1:f62247cbeac6 417 pc.printf("\r\n");
laserdad 1:f62247cbeac6 418 // printRawFIFO(samples2Read);
laserdad 1:f62247cbeac6 419 }
laserdad 0:74fff521858e 420 } //end if/else AFULL
laserdad 1:f62247cbeac6 421 } //end if intFlagged
laserdad 1:f62247cbeac6 422 } //end while
laserdad 0:74fff521858e 423
laserdad 0:74fff521858e 424 }//end main
laserdad 0:74fff521858e 425
laserdad 0:74fff521858e 426
laserdad 0:74fff521858e 427
laserdad 0:74fff521858e 428
laserdad 0:74fff521858e 429 /* FYI seee this table for effective 3dB bandwidth for IIR filter given sample rate and number of bits shifted
laserdad 0:74fff521858e 430 * fsample bits f3dB
laserdad 0:74fff521858e 431 * 1600 1 89.6
laserdad 0:74fff521858e 432 * 1600 2 72
laserdad 0:74fff521858e 433 * 1600 3 24
laserdad 0:74fff521858e 434 * 1600 4 8
laserdad 0:74fff521858e 435 * 800 1 44.8
laserdad 0:74fff521858e 436 * 800 2 36
laserdad 0:74fff521858e 437 * 800 3 12
laserdad 0:74fff521858e 438 * 800 4 4
laserdad 0:74fff521858e 439 * 400 1 22.4
laserdad 0:74fff521858e 440 * 400 2 18
laserdad 0:74fff521858e 441 * 400 3 6
laserdad 0:74fff521858e 442 * 400 4 2
laserdad 0:74fff521858e 443 * 200 1 11.2
laserdad 0:74fff521858e 444 * 200 2 9
laserdad 0:74fff521858e 445 * 200 3 3
laserdad 0:74fff521858e 446 * 200 4 1
laserdad 0:74fff521858e 447 */