MAX86150 code

Dependencies:   mbed

Fork of MAX86150_ECG_PPG by Bidet Remote

Committer:
laserdad
Date:
Sat Jun 03 04:01:34 2017 +0000
Revision:
4:3c728f3d1f10
Parent:
3:a7df33374b48
MAX86150

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