MAX86150 code

Dependencies:   mbed

Fork of MAX86150_ECG_PPG by Bidet Remote

Committer:
laserdad
Date:
Wed Jan 04 23:16:05 2017 +0000
Revision:
3:a7df33374b48
Parent:
2:c8b7ef52c65c
Child:
4:3c728f3d1f10
removing read pointer check. Not necessary. Also the previous commit included an increase of the ECG data rate to max 1600 sps.

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 2:c8b7ef52c65c 78 #define interrupt_pin D12 //INTB pin --see InterruptIn declaration
laserdad 0:74fff521858e 79 #define maxECGrate 0
laserdad 0:74fff521858e 80 #define normECGrate 1
laserdad 2:c8b7ef52c65c 81 #define BaudRate 921600
laserdad 2:c8b7ef52c65c 82 //also try 921600, 460800 230400
laserdad 2:c8b7ef52c65c 83 const int16_t i2cBufferSize=36; //32 was stable. In this rev exploring 36
laserdad 0:74fff521858e 84
laserdad 0:74fff521858e 85 //global variables
laserdad 0:74fff521858e 86
laserdad 0:74fff521858e 87 //USER SELECTABLE****************************
laserdad 0:74fff521858e 88 const uint8_t ppgOn = 1; //turn on PPG (IR and Red both)
laserdad 0:74fff521858e 89 const uint8_t ecgOn = 1; //turn on ECG measurement
laserdad 0:74fff521858e 90 const uint8_t etiOn = 1; //turn on ETI (lead check) electrical tissue impedance. Checks if your fingers are on or not.
laserdad 2:c8b7ef52c65c 91 //const uint8_t ecgRate = maxECGrate; //use normECGrate 800Hz or maxECGrate 1600Hz
laserdad 0:74fff521858e 92 const uint8_t ecgRate = maxECGrate; //use normECGrate 800Hz or maxECGrate 1600Hz
laserdad 0:74fff521858e 93 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 94 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 95 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 96 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 97 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 98 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 99 const int16_t etiBaselineBits = 0; //log(2) of baseline IIR filter divisor for eti, use 0 for no baseline removal
laserdad 0:74fff521858e 100 const uint8_t rCurrent = 0x50; //PPG LED current (when enabled), max=0xFF (255)
laserdad 0:74fff521858e 101 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 102 const uint8_t redHiPWR = 0; //0 = use normal pwr level (recommended for PPG). Note hi pwr is useful for proximity detection.
laserdad 0:74fff521858e 103 const uint8_t irHiPWR = 0; //0 = use normal pwr level (recommended for PPG). Note hi pwr is useful for proximity detection.
laserdad 0:74fff521858e 104
laserdad 0:74fff521858e 105 bool runSetup =1; //tells program to reprogram ASIC (used on startup)
laserdad 0:74fff521858e 106 //***************************************
laserdad 0:74fff521858e 107
laserdad 0:74fff521858e 108 //USER SELECTABLE (though not recommended)
laserdad 0:74fff521858e 109 const uint8_t ppgRdyIntEn = 0; //not using ppgRdyInt (too slow)
laserdad 0:74fff521858e 110 const uint8_t ecgRdyIntEn = 0; //not using ECG_RDY interrrupt. It will interrupt frequently if this is enabled (too fast)
laserdad 0:74fff521858e 111 //**************************************
laserdad 0:74fff521858e 112
laserdad 0:74fff521858e 113 //NOT USER CONFIGURABLE******************
laserdad 0:74fff521858e 114
laserdad 2:c8b7ef52c65c 115
laserdad 0:74fff521858e 116 const int16_t irChannel = ppgOn-1; //-1 or 0
laserdad 0:74fff521858e 117 const int16_t rChannel = ppgOn*(2)-1; //-1 or 1
laserdad 0:74fff521858e 118 const int16_t ecgChannel = ecgOn*(1+2*ppgOn)-1; //-1, 0, or 2
laserdad 0:74fff521858e 119 const int16_t etiChannel = etiOn*(1+ecgOn+2*ppgOn)-1; //-1, 0,1 or 3
laserdad 0:74fff521858e 120 const uint8_t numMeasEnabled = 2*ppgOn + ecgOn + etiOn; //Index # of how many measurements will be in each block of the FIFO
laserdad 0:74fff521858e 121 const uint8_t bytesPerSample = 3*numMeasEnabled; //each measurement is 3bytes
laserdad 1:f62247cbeac6 122 const int16_t samples2Read = i2cBufferSize / bytesPerSample ; //assuming 32 byte I2C buffer default
laserdad 0:74fff521858e 123 const uint8_t almostFullIntEn = 1; //priority to AFULL vs. PPG in code
laserdad 0:74fff521858e 124 const char bytes2Read = bytesPerSample*samples2Read;
laserdad 0:74fff521858e 125 char i2cWriteBuffer[10];
laserdad 0:74fff521858e 126 char i2cReadBuffer[i2cBufferSize]; //32 bytes in i2c buffer size in Arduino by default.
laserdad 0:74fff521858e 127 unsigned long tim = 0; //for counting milliseconds
laserdad 0:74fff521858e 128 volatile bool intFlagged = 0; //ISR variable
laserdad 0:74fff521858e 129 long data[4][5]; //data from the first measurement type
laserdad 0:74fff521858e 130 long dataAvg[4]; //currently using data1 for ECG. This variable stores the IIR filtered avg.
laserdad 0:74fff521858e 131 long dataBaseline[4]; //this variable stores the few second baseline for substraction (IIR filter)
laserdad 0:74fff521858e 132 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 133 int bits2Avg[4]; //array stores the selected averaging time constants set below for filtering (loaded in setup)
laserdad 0:74fff521858e 134 int bits2AvgBaseline[4]; //stores below filter time constants (loaded in setup)
laserdad 0:74fff521858e 135 char FIFOData[bytes2Read];
laserdad 0:74fff521858e 136
laserdad 0:74fff521858e 137
laserdad 0:74fff521858e 138
laserdad 0:74fff521858e 139 //setup I2C, serial connection and timer
laserdad 0:74fff521858e 140 InterruptIn intPin(interrupt_pin); //config p5 as interrupt
laserdad 0:74fff521858e 141 I2C i2c(I2C_SDA,I2C_SCL);
laserdad 2:c8b7ef52c65c 142 Serial pc(USBTX,USBRX,NULL,BaudRate); //open serial port (optionally add device name and baud rate after specifying TX and RX pins)
laserdad 0:74fff521858e 143
laserdad 0:74fff521858e 144
laserdad 0:74fff521858e 145 //declare subroutines
laserdad 1:f62247cbeac6 146 void writeRegister(uint8_t addr, uint8_t reg, uint8_t val)
laserdad 1:f62247cbeac6 147 {
laserdad 1:f62247cbeac6 148 /*writes 1 byte to a single register*/
laserdad 0:74fff521858e 149 char writeData[2];
laserdad 0:74fff521858e 150 writeData[0] = reg ;
laserdad 0:74fff521858e 151 writeData[1] = val;
laserdad 0:74fff521858e 152 i2c.write(addr,writeData, 2);
laserdad 0:74fff521858e 153 }
laserdad 0:74fff521858e 154
laserdad 1:f62247cbeac6 155 void writeBlock(uint8_t addr, uint8_t startReg, uint8_t *data, uint8_t numBytes)
laserdad 1:f62247cbeac6 156 {
laserdad 1:f62247cbeac6 157 /*writes data from an array beginning at the startReg*/
laserdad 0:74fff521858e 158 char writeData[numBytes+1];
laserdad 0:74fff521858e 159 writeData[0]=startReg;
laserdad 1:f62247cbeac6 160 for(int n=1; n<numBytes; n++) {
laserdad 0:74fff521858e 161 writeData[n]=data[n-1];
laserdad 0:74fff521858e 162 }
laserdad 0:74fff521858e 163 i2c.write(addr,writeData,numBytes+1);
laserdad 0:74fff521858e 164 }
laserdad 0:74fff521858e 165
laserdad 1:f62247cbeac6 166 void readRegisters(uint8_t addr, uint8_t startReg, char *regData, int numBytes)
laserdad 1:f62247cbeac6 167 {
laserdad 0:74fff521858e 168 char writeData = startReg;
laserdad 0:74fff521858e 169 i2c.write(addr,&writeData,1,true); //true is for repeated start
laserdad 0:74fff521858e 170 i2c.read(addr,regData,numBytes);
laserdad 0:74fff521858e 171 }
laserdad 0:74fff521858e 172
laserdad 0:74fff521858e 173 //clears interrupts
laserdad 1:f62247cbeac6 174 void clearInterrupts(char *data)
laserdad 1:f62247cbeac6 175 {
laserdad 0:74fff521858e 176 readRegisters(MAX86150_Addr,InterruptStatusReg1,data,1);
laserdad 0:74fff521858e 177 }
laserdad 0:74fff521858e 178
laserdad 1:f62247cbeac6 179 void regDump(uint8_t Addr, uint8_t startByte, uint8_t endByte)
laserdad 1:f62247cbeac6 180 {
laserdad 1:f62247cbeac6 181 /*print the values of up to 20 registers*/
laserdad 0:74fff521858e 182 char regData[20];
laserdad 0:74fff521858e 183 int numBytes;
laserdad 0:74fff521858e 184 if (endByte>=startByte) {
laserdad 0:74fff521858e 185 numBytes = (endByte-startByte+1) < 20 ? (endByte-startByte+1) : 20;
laserdad 1:f62247cbeac6 186 } else {
laserdad 0:74fff521858e 187 numBytes=1;
laserdad 1:f62247cbeac6 188 }
laserdad 1:f62247cbeac6 189
laserdad 0:74fff521858e 190 regData[0] = startByte;
laserdad 0:74fff521858e 191 i2c.write(Addr,regData,1,true);
laserdad 0:74fff521858e 192 i2c.read(Addr, regData, numBytes);
laserdad 1:f62247cbeac6 193 for(int n=0; n<numBytes; n++) {
laserdad 1:f62247cbeac6 194 pc.printf("%X, %X \r\n", startByte+n, regData[n]);
laserdad 0:74fff521858e 195 }
laserdad 0:74fff521858e 196 }
laserdad 0:74fff521858e 197
laserdad 1:f62247cbeac6 198 bool bitRead(long data, uint8_t bitNum)
laserdad 1:f62247cbeac6 199 {
laserdad 1:f62247cbeac6 200 long mask = 1<<bitNum;
laserdad 1:f62247cbeac6 201 long masked_bit = data & mask;
laserdad 1:f62247cbeac6 202 return masked_bit >> bitNum;
laserdad 0:74fff521858e 203 }
laserdad 0:74fff521858e 204
laserdad 1:f62247cbeac6 205 void intEvent(void)
laserdad 1:f62247cbeac6 206 {
laserdad 1:f62247cbeac6 207 intFlagged = 1;
laserdad 0:74fff521858e 208 }
laserdad 0:74fff521858e 209
laserdad 1:f62247cbeac6 210 void initMAX86150(void)
laserdad 1:f62247cbeac6 211 {
laserdad 0:74fff521858e 212 pc.printf("Initializing MAX86150\r\n");
laserdad 0:74fff521858e 213
laserdad 1:f62247cbeac6 214 //print configurations
laserdad 0:74fff521858e 215 pc.printf( (ppgOn ? "PPG on" : "PPG off") );
laserdad 0:74fff521858e 216 pc.printf( (ecgOn ? ", ECG On" : ", ECG off") );
laserdad 0:74fff521858e 217 pc.printf( (etiOn ? ", ETI On\r\n" : ", ETI off\r\n") );
laserdad 0:74fff521858e 218 pc.printf( (ppgRdyIntEn ? "PPG Int On" : "PPG Int off") );
laserdad 0:74fff521858e 219 pc.printf( (ecgRdyIntEn ? ", ECG Int On" : ", ECG Int off") );
laserdad 0:74fff521858e 220 pc.printf( (almostFullIntEn ? ", Afull Int On\r\n" : ", Afull Int off\r\n") );
laserdad 0:74fff521858e 221 //write register configurations
laserdad 0:74fff521858e 222 writeRegister(MAX86150_Addr,SystemControlReg,0x01); //chip reset
laserdad 0:74fff521858e 223 wait_ms(2); //wait for chip to come back on line
laserdad 0:74fff521858e 224 //if PPG or ETI are not enabled, then FIFO is setup for ECG
laserdad 2:c8b7ef52c65c 225 writeRegister(MAX86150_Addr,FIFOConfigReg,0x7F); // [4] FIFO_ROLLS_ON_FULL, clears with status read or FIFO_data read, asserts only once
laserdad 0:74fff521858e 226 uint16_t FIFOCode;
laserdad 0:74fff521858e 227 FIFOCode = etiOn ? 0x000A : 0x0000 ; //ETI is last in FIFO
laserdad 0:74fff521858e 228 FIFOCode = ecgOn ? (FIFOCode<<4 | 0x0009) : FIFOCode; //insert ECG front of ETI in FIFO
laserdad 0:74fff521858e 229 FIFOCode = ppgOn ? (FIFOCode<<8 | 0x0021) : FIFOCode; //insert Red(2) and IR (1) in front of ECG in FIFO
laserdad 0:74fff521858e 230 writeRegister(MAX86150_Addr,FIFODataControlReg1, (char)(FIFOCode & 0x00FF) );
laserdad 0:74fff521858e 231 writeRegister(MAX86150_Addr,FIFODataControlReg2, (char)(FIFOCode >>8) );
laserdad 1:f62247cbeac6 232 writeRegister(MAX86150_Addr, ppgConfigReg0,0b11010111); //D3 for 100Hz, PPG_ADC_RGE: 32768nA, PPG_SR: 100SpS, PPG_LED_PW: 400uS
laserdad 0:74fff521858e 233 writeRegister(MAX86150_Addr,LED1PulseAmpReg, ppgOn ? rCurrent : 0x00 );
laserdad 0:74fff521858e 234 writeRegister(MAX86150_Addr,LED2PulseAmpReg, ppgOn ? irCurrent : 0x00);
laserdad 0:74fff521858e 235 writeRegister(MAX86150_Addr,LEDRangeReg, irHiPWR * 2 + redHiPWR ); // PPG_ADC_RGE: 32768nA
laserdad 0:74fff521858e 236 //ecg configuration
laserdad 0:74fff521858e 237 if (ecgOn) {
laserdad 0:74fff521858e 238 //****************************************
laserdad 1:f62247cbeac6 239 //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 240 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 241 writeRegister(MAX86150_Addr,EcgConfigReg2,0x11); //hidden register at ECG config 2, per JY's settings
laserdad 0:74fff521858e 242 writeRegister(MAX86150_Addr,EcgConfigReg3,0x3D); //ECG config 3
laserdad 0:74fff521858e 243 writeRegister(MAX86150_Addr,EcgConfigReg4,0x02); //ECG config 4 per JY's settings
laserdad 1:f62247cbeac6 244 //enter test mode
laserdad 0:74fff521858e 245 writeRegister(MAX86150_Addr,0xFF,0x54); //write 0x54 to register 0xFF
laserdad 0:74fff521858e 246 writeRegister(MAX86150_Addr,0xFF,0x4D); //write 0x4D to register 0xFF
laserdad 0:74fff521858e 247 writeRegister(MAX86150_Addr,0xCE,0x01);
laserdad 0:74fff521858e 248 writeRegister(MAX86150_Addr,0xCF,0x18); //adjust hidden registers at CE and CF per JY's settings in EV kit
laserdad 0:74fff521858e 249 writeRegister(MAX86150_Addr,0xD0,0x01); //adjust hidden registers D0 (probably ETI)
laserdad 1:f62247cbeac6 250 writeRegister(MAX86150_Addr,0xFF,0x00); //exit test mode
laserdad 0:74fff521858e 251 }
laserdad 0:74fff521858e 252 //setup interrupts last
laserdad 0:74fff521858e 253 writeRegister(MAX86150_Addr,InterruptEnableReg1,( almostFullIntEn ? 0x80 : (ppgRdyIntEn ? 0x40 : 0x00) ) );
laserdad 0:74fff521858e 254 writeRegister(MAX86150_Addr,InterruptEnableReg2, (ecgRdyIntEn ? 0x04 : 0x00) );
laserdad 0:74fff521858e 255 writeRegister(MAX86150_Addr,SystemControlReg,0x04);//start FIFO
laserdad 1:f62247cbeac6 256
laserdad 0:74fff521858e 257 pc.printf("done configuring MAX86150\r\n");
laserdad 0:74fff521858e 258 } //end initMAX86150
laserdad 0:74fff521858e 259
laserdad 0:74fff521858e 260
laserdad 1:f62247cbeac6 261 bool readFIFO(int numSamples, char *fifodata)
laserdad 1:f62247cbeac6 262 {
laserdad 2:c8b7ef52c65c 263 // char stat[1];
laserdad 0:74fff521858e 264 bool dataValid = 0;
laserdad 2:c8b7ef52c65c 265 // uint8_t tries = 0;
laserdad 2:c8b7ef52c65c 266 // char newReadPointer;
laserdad 2:c8b7ef52c65c 267 // clearInterrupts(stat);
laserdad 0:74fff521858e 268 //get FIFO position
laserdad 3:a7df33374b48 269 // 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 3:a7df33374b48 270 // char readPointer = i2cReadBuffer[0];
laserdad 2:c8b7ef52c65c 271 // while(!dataValid) {
laserdad 2:c8b7ef52c65c 272 // tries++;
laserdad 0:74fff521858e 273 //try reading FIFO
laserdad 0:74fff521858e 274 readRegisters(MAX86150_Addr, FIFODataReg, fifodata, bytes2Read); //get data
laserdad 0:74fff521858e 275 //see if it worked if you are not servicing interrupts faster than the sample rate
laserdad 0:74fff521858e 276 //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 277 dataValid=1;
laserdad 1:f62247cbeac6 278 //readRegisters(MAX86150_Addr, FIFOReadPointerReg, i2cReadBuffer, 1); //check that the read pointer has moved (otherwise FIFO was being written to)
laserdad 0:74fff521858e 279 // newReadPointer = i2cReadBuffer[0];
laserdad 0:74fff521858e 280 // 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 281 // dataValid=1;
laserdad 0:74fff521858e 282 // return 1;
laserdad 0:74fff521858e 283 // }
laserdad 0:74fff521858e 284 // 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 285 // break;
laserdad 0:74fff521858e 286 // }
laserdad 0:74fff521858e 287 // else {
laserdad 0:74fff521858e 288 // wait_us(100); //try again a moment later
laserdad 1:f62247cbeac6 289 // }
laserdad 2:c8b7ef52c65c 290 // }
laserdad 0:74fff521858e 291 return dataValid;
laserdad 0:74fff521858e 292 } //end readFIFO
laserdad 0:74fff521858e 293
laserdad 0:74fff521858e 294 //for serial monitoring
laserdad 1:f62247cbeac6 295 void printData(uint16_t numSamples,char *fifodata)
laserdad 1:f62247cbeac6 296 {
laserdad 1:f62247cbeac6 297 //cat and mask the bits from the FIFO
laserdad 1:f62247cbeac6 298 for (int n = 0; n < numSamples; n++) { //for every sample
laserdad 1:f62247cbeac6 299 char p = bytesPerSample;
laserdad 1:f62247cbeac6 300 for (int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
laserdad 1:f62247cbeac6 301 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 302 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 303 data[m][n] |= 0xFFFC0000;
laserdad 1:f62247cbeac6 304 }
laserdad 1:f62247cbeac6 305 }
laserdad 0:74fff521858e 306 }
laserdad 1:f62247cbeac6 307 for (int n = 0; n < numSamples; n++) { //for every sample
laserdad 1:f62247cbeac6 308 ind++;
laserdad 1:f62247cbeac6 309 ind = ind % printEvery;
laserdad 1:f62247cbeac6 310
laserdad 1:f62247cbeac6 311 //calc avg and baseline
laserdad 1:f62247cbeac6 312 for(int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
laserdad 1:f62247cbeac6 313 dataAvg[m] += ( data[m][n] - dataAvg[m] ) >> bits2Avg[m] ; //get the running average
laserdad 1:f62247cbeac6 314 dataBaseline[m] += ( data[m][n] - dataBaseline[m] ) >> bits2AvgBaseline[m]; //get the long baseline
laserdad 1:f62247cbeac6 315 }
laserdad 0:74fff521858e 316
laserdad 1:f62247cbeac6 317 //print data
laserdad 1:f62247cbeac6 318 if (ind == 1) { //printing only every specified number of samples to reduce serial traffic to manageable level
laserdad 1:f62247cbeac6 319 for (int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
laserdad 1:f62247cbeac6 320 if(bits2AvgBaseline[m]>0) {
laserdad 1:f62247cbeac6 321 pc.printf("%i, ",dataAvg[m]-dataBaseline[m]); //print with baseline subtraction
laserdad 1:f62247cbeac6 322 } else {
laserdad 1:f62247cbeac6 323 pc.printf("%i, ", dataAvg[m]); //print without baseline subtraction
laserdad 1:f62247cbeac6 324 }
laserdad 1:f62247cbeac6 325 }
laserdad 1:f62247cbeac6 326 pc.printf("\r\n");
laserdad 1:f62247cbeac6 327 } //end print loop
laserdad 1:f62247cbeac6 328 } //end sample loop
laserdad 0:74fff521858e 329 }//end printData()
laserdad 0:74fff521858e 330
laserdad 0:74fff521858e 331
laserdad 0:74fff521858e 332
laserdad 0:74fff521858e 333
laserdad 0:74fff521858e 334 //for debugging
laserdad 1:f62247cbeac6 335 void printRawFIFO(int numSamples,char *fifodata)
laserdad 1:f62247cbeac6 336 {
laserdad 1:f62247cbeac6 337 // Serial.print("FIFO bytes ");
laserdad 1:f62247cbeac6 338 for (int n = 0; n < numSamples; n++) {//for every sample.
laserdad 1:f62247cbeac6 339 for (int m=0; m<numMeasEnabled; m++) { //for every kind of measurement
laserdad 1:f62247cbeac6 340 pc.printf("%d: ",m);
laserdad 1:f62247cbeac6 341 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 342 } //end measurement loop
laserdad 1:f62247cbeac6 343 pc.printf("\r\n");
laserdad 1:f62247cbeac6 344 } //end sample loop
laserdad 0:74fff521858e 345 } //end function
laserdad 0:74fff521858e 346
laserdad 0:74fff521858e 347
laserdad 1:f62247cbeac6 348 void setupASIC(void)
laserdad 1:f62247cbeac6 349 {
laserdad 0:74fff521858e 350 pc.printf("Running Setup\r\n");
laserdad 0:74fff521858e 351 runSetup = 0; //only run once
laserdad 0:74fff521858e 352 i2c.frequency(recommendedi2cFreq); //set I2C frequency to 400kHz
laserdad 0:74fff521858e 353 // intPin.mode(PullUp); //pullups on the sensor board
laserdad 0:74fff521858e 354 //configure MAX86150 register settings
laserdad 0:74fff521858e 355 initMAX86150();
laserdad 1:f62247cbeac6 356 pc.printf("register dump\r\n");
laserdad 0:74fff521858e 357
laserdad 0:74fff521858e 358 // //print register configuration
laserdad 0:74fff521858e 359 // regDump(MAX86150_Addr,0x00, 0x06);
laserdad 0:74fff521858e 360 // regDump(MAX86150_Addr,0x08, 0x15);
laserdad 0:74fff521858e 361 // regDump(MAX86150_Addr,0x3C, 0x3F);
laserdad 0:74fff521858e 362 // //go to test mode
laserdad 0:74fff521858e 363 // writeRegister(MAX86150_Addr,0xFF,0x54);
laserdad 0:74fff521858e 364 // writeRegister(MAX86150_Addr,0xFF,0x4D);
laserdad 0:74fff521858e 365 // regDump(MAX86150_Addr,0xCE, 0xCF);
laserdad 0:74fff521858e 366 // regDump(MAX86150_Addr,0xD0, 0xD0);
laserdad 0:74fff521858e 367 // writeRegister(MAX86150_Addr,0xFF,0x00);
laserdad 0:74fff521858e 368 clearInterrupts(i2cReadBuffer);
laserdad 2:c8b7ef52c65c 369 // i2c.frequency(maxi2cFreq);
laserdad 0:74fff521858e 370 //configure averaging
laserdad 0:74fff521858e 371 if(ppgOn) {
laserdad 0:74fff521858e 372 bits2Avg[rChannel]=ppgBits2Avg;
laserdad 0:74fff521858e 373 bits2Avg[irChannel]=ppgBits2Avg;
laserdad 0:74fff521858e 374 bits2AvgBaseline[rChannel]=ppgBaselineBits;
laserdad 0:74fff521858e 375 bits2AvgBaseline[irChannel]=ppgBaselineBits;
laserdad 0:74fff521858e 376 }
laserdad 1:f62247cbeac6 377 if(ecgOn) {
laserdad 0:74fff521858e 378 bits2Avg[ecgChannel]=ecgBits2Avg;
laserdad 0:74fff521858e 379 bits2AvgBaseline[ecgChannel]=ecgBaselineBits;
laserdad 0:74fff521858e 380 }
laserdad 1:f62247cbeac6 381 if(etiOn) {
laserdad 0:74fff521858e 382 bits2Avg[etiChannel]=etiBits2Avg;
laserdad 0:74fff521858e 383 bits2AvgBaseline[etiChannel]=etiBaselineBits;
laserdad 0:74fff521858e 384 }
laserdad 0:74fff521858e 385 pc.printf("Done w/setup\r\n");
laserdad 0:74fff521858e 386 }
laserdad 0:74fff521858e 387
laserdad 0:74fff521858e 388
laserdad 0:74fff521858e 389
laserdad 1:f62247cbeac6 390 int main()
laserdad 1:f62247cbeac6 391 {
laserdad 0:74fff521858e 392 char FIFOData[bytesPerSample];
laserdad 0:74fff521858e 393 if(runSetup) {
laserdad 0:74fff521858e 394 setupASIC();
laserdad 1:f62247cbeac6 395 }
laserdad 1:f62247cbeac6 396
laserdad 0:74fff521858e 397 intPin.fall(&intEvent);
laserdad 0:74fff521858e 398 while(1) {
laserdad 1:f62247cbeac6 399 char stat[1];
laserdad 1:f62247cbeac6 400 static int n = 0;
laserdad 1:f62247cbeac6 401 if (intFlagged) {
laserdad 0:74fff521858e 402 // pc.printf("intFlagged\r\n");
laserdad 0:74fff521858e 403 if (almostFullIntEn) {
laserdad 0:74fff521858e 404 n = 0;
laserdad 0:74fff521858e 405 intFlagged = 0;
laserdad 0:74fff521858e 406 readFIFO(samples2Read,FIFOData);
laserdad 0:74fff521858e 407 printData(samples2Read,FIFOData);
laserdad 1:f62247cbeac6 408 // printRawFIFO(samples2Read,FIFOData); //for debugging
laserdad 1:f62247cbeac6 409 } //end if AFULL
laserdad 1:f62247cbeac6 410 else { //this is to handle end of conversion interrupts (not configured by default)
laserdad 1:f62247cbeac6 411 if (n < samples2Read) {
laserdad 1:f62247cbeac6 412 n++;
laserdad 1:f62247cbeac6 413 intFlagged = 0;
laserdad 1:f62247cbeac6 414 clearInterrupts(stat);
laserdad 1:f62247cbeac6 415 // Serial.println(n);
laserdad 1:f62247cbeac6 416 } else {
laserdad 1:f62247cbeac6 417 n = 0;
laserdad 1:f62247cbeac6 418 intFlagged = 0;
laserdad 1:f62247cbeac6 419 readFIFO(samples2Read,FIFOData);
laserdad 1:f62247cbeac6 420 printData(samples2Read,FIFOData);
laserdad 1:f62247cbeac6 421 pc.printf("\r\n");
laserdad 1:f62247cbeac6 422 // printRawFIFO(samples2Read);
laserdad 1:f62247cbeac6 423 }
laserdad 0:74fff521858e 424 } //end if/else AFULL
laserdad 1:f62247cbeac6 425 } //end if intFlagged
laserdad 1:f62247cbeac6 426 } //end while
laserdad 0:74fff521858e 427
laserdad 0:74fff521858e 428 }//end main
laserdad 0:74fff521858e 429
laserdad 0:74fff521858e 430
laserdad 0:74fff521858e 431
laserdad 0:74fff521858e 432
laserdad 0:74fff521858e 433 /* FYI seee this table for effective 3dB bandwidth for IIR filter given sample rate and number of bits shifted
laserdad 0:74fff521858e 434 * fsample bits f3dB
laserdad 0:74fff521858e 435 * 1600 1 89.6
laserdad 0:74fff521858e 436 * 1600 2 72
laserdad 0:74fff521858e 437 * 1600 3 24
laserdad 0:74fff521858e 438 * 1600 4 8
laserdad 0:74fff521858e 439 * 800 1 44.8
laserdad 0:74fff521858e 440 * 800 2 36
laserdad 0:74fff521858e 441 * 800 3 12
laserdad 0:74fff521858e 442 * 800 4 4
laserdad 0:74fff521858e 443 * 400 1 22.4
laserdad 0:74fff521858e 444 * 400 2 18
laserdad 0:74fff521858e 445 * 400 3 6
laserdad 0:74fff521858e 446 * 400 4 2
laserdad 0:74fff521858e 447 * 200 1 11.2
laserdad 0:74fff521858e 448 * 200 2 9
laserdad 0:74fff521858e 449 * 200 3 3
laserdad 0:74fff521858e 450 * 200 4 1
laserdad 0:74fff521858e 451 */