MAX86150 code

Dependencies:   mbed

Fork of MAX86150_ECG_PPG by Bidet Remote

Revision:
1:f62247cbeac6
Parent:
0:74fff521858e
Child:
2:c8b7ef52c65c
--- a/main.cpp	Wed Jan 04 17:00:04 2017 +0000
+++ b/main.cpp	Wed Jan 04 17:00:53 2017 +0000
@@ -1,7 +1,7 @@
 
 //********************************************** Arduino code
 /* This program configures and reads data from the MAX86150 ECG/PPG (BioZ to come) ASIC from Maxim Integrated.
- *  Originally writter for Arduino. The MAX86150r4 or MAX86150r8 boards work well (others are noisy). 
+ *  Originally writter for Arduino. The MAX86150r4 or MAX86150r8 boards work well (others are noisy).
  *  Keep ECG electrodes as short as possible. Due to the nature of this chip low frequency RC filters cannot be used.
  *  Note the ECG input oscillates when not loaded with human body impedance.
  *  ECG inputs have internal ESD protection.
@@ -11,12 +11,12 @@
  *  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.
  *  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,
  *  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
- *  of an I2C transaction, so we have to keep I2C transactions short. 
- *  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 
+ *  of an I2C transaction, so we have to keep I2C transactions short.
+ *  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
  *  library you use. For Arduino the default is 32 bytes.
  *  ECG data and PPG data are different. PPG data is unipolar 18 bits and has garbage in the MSBs that has to be masked.
  *  ECG data is bipolar (2's complement), 17 bits and has to have the MSBs masked with FFF.. if the signal is negative.
- *  ECG data is displayed with a short IIR noise filter and longer IIR baseline removal filter. The filter length is specified in bits 
+ *  ECG data is displayed with a short IIR noise filter and longer IIR baseline removal filter. The filter length is specified in bits
  *  so the math can be done with integers using register shifting, rather than floats.
  *  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.)
  *  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.
@@ -25,24 +25,24 @@
  *  PPG data is measured at a much lower rate than ECG, but data is buffered through in the FIFO, showing the most recent sample.
  *  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
  *  filtered data sent at a the reduced bandwidth (what Maxim does on their BLE EV kit).
- *  
+ *
  *  IMPORTANT: Maxim recommends to read the FIFO pointer after getting data to make sure it changed. I have not implemented that yet.
  *  Basically, if you try to read the FIFO during the few clock cycles while it is being updated (a rare but eventual event),
- *  then the FIFO data will be garbage. You have to reread the FIFO. 
- *  
+ *  then the FIFO data will be garbage. You have to reread the FIFO.
+ *
  *  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
- *  
- *  Note: IR and R LED power should be closed loop controlled to an optimal region above 90% of full scale for best resolution. 
+ *
+ *  Note: IR and R LED power should be closed loop controlled to an optimal region above 90% of full scale for best resolution.
  *  (Not yet implemented).
- *  
+ *
  *  Note: PPG system uses sophisticated background subtraction to cancel ambient light flicker and large ambient light signals (sunlight).
  *  This is important for finger measurements, but less important for measurements indoors under the thigh, for example, where a generic
  *  light source and LED can be used in DC operation.
- *  
+ *
  *  Note the PPG ADC uses feedback cancellation from the current source to reduce noise. No LED current will result in noisy ADC readings.
  *  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
  *  measure with noise with test currents on the chip.
- *  
+ *
  *  Note ASIC has configurable on-chip PPG averaging if-desired (prior to being written to FIFO).
  */
 #include "mbed.h"
@@ -115,7 +115,7 @@
 const int16_t etiChannel = etiOn*(1+ecgOn+2*ppgOn)-1; //-1, 0,1 or 3
 const uint8_t numMeasEnabled = 2*ppgOn + ecgOn + etiOn; //Index # of how many measurements will be in each block of the FIFO
 const uint8_t bytesPerSample = 3*numMeasEnabled; //each measurement is 3bytes
-const int16_t samples2Read = i2cBufferSize / bytesPerSample ; //assuming 32 byte I2C buffer default 
+const int16_t samples2Read = i2cBufferSize / bytesPerSample ; //assuming 32 byte I2C buffer default
 const uint8_t almostFullIntEn = 1; //priority to AFULL vs. PPG in code
 const char bytes2Read = bytesPerSample*samples2Read;
 char i2cWriteBuffer[10];
@@ -139,68 +139,75 @@
 
 
 //declare subroutines
-void writeRegister(uint8_t addr, uint8_t reg, uint8_t val) {
- /*writes 1 byte to a single register*/
+void writeRegister(uint8_t addr, uint8_t reg, uint8_t val)
+{
+    /*writes 1 byte to a single register*/
     char writeData[2];
     writeData[0] = reg ;
     writeData[1] = val;
     i2c.write(addr,writeData, 2);
 }
 
-void writeBlock(uint8_t addr, uint8_t startReg, uint8_t *data, uint8_t numBytes) {
-/*writes data from an array beginning at the startReg*/
+void writeBlock(uint8_t addr, uint8_t startReg, uint8_t *data, uint8_t numBytes)
+{
+    /*writes data from an array beginning at the startReg*/
     char writeData[numBytes+1];
     writeData[0]=startReg;
-    for(int n=1;n<numBytes;n++) {
+    for(int n=1; n<numBytes; n++) {
         writeData[n]=data[n-1];
     }
     i2c.write(addr,writeData,numBytes+1);
 }
 
-void readRegisters(uint8_t addr, uint8_t startReg, char *regData, int numBytes) {
+void readRegisters(uint8_t addr, uint8_t startReg, char *regData, int numBytes)
+{
     char writeData = startReg;
     i2c.write(addr,&writeData,1,true); //true is for repeated start
     i2c.read(addr,regData,numBytes);
 }
 
 //clears interrupts
-void clearInterrupts(char *data) {
+void clearInterrupts(char *data)
+{
     readRegisters(MAX86150_Addr,InterruptStatusReg1,data,1);
 }
 
-void regDump(uint8_t Addr, uint8_t startByte, uint8_t endByte) {
-/*print the values of up to 20 registers*/
+void regDump(uint8_t Addr, uint8_t startByte, uint8_t endByte)
+{
+    /*print the values of up to 20 registers*/
     char regData[20];
     int numBytes;
     if (endByte>=startByte) {
         numBytes =  (endByte-startByte+1) < 20 ? (endByte-startByte+1) : 20;
-    }
-    else {
+    } else {
         numBytes=1;
-    }    
-        
+    }
+
     regData[0] = startByte;
     i2c.write(Addr,regData,1,true);
     i2c.read(Addr, regData, numBytes);
-    for(int n=0;n<numBytes;n++) {
-      pc.printf("%X, %X \r\n", startByte+n, regData[n]);
+    for(int n=0; n<numBytes; n++) {
+        pc.printf("%X, %X \r\n", startByte+n, regData[n]);
     }
 }
 
-bool bitRead(long data, uint8_t bitNum) {
-        long mask = 1<<bitNum;
-        long masked_bit = data & mask;
-        return masked_bit >> bitNum;
+bool bitRead(long data, uint8_t bitNum)
+{
+    long mask = 1<<bitNum;
+    long masked_bit = data & mask;
+    return masked_bit >> bitNum;
 }
 
-void intEvent(void) {
-  intFlagged = 1;
+void intEvent(void)
+{
+    intFlagged = 1;
 }
 
-void initMAX86150(void) {
+void initMAX86150(void)
+{
     pc.printf("Initializing MAX86150\r\n");
 
-    //print configurations    
+    //print configurations
     pc.printf( (ppgOn ? "PPG on" : "PPG off") );
     pc.printf( (ecgOn ? ", ECG On" : ", ECG off") );
     pc.printf( (etiOn ? ", ETI On\r\n" : ",  ETI off\r\n") );
@@ -218,36 +225,37 @@
     FIFOCode = ppgOn ? (FIFOCode<<8 | 0x0021) : FIFOCode; //insert Red(2) and IR (1) in front of ECG in FIFO
     writeRegister(MAX86150_Addr,FIFODataControlReg1, (char)(FIFOCode & 0x00FF) );
     writeRegister(MAX86150_Addr,FIFODataControlReg2, (char)(FIFOCode >>8) );
-    writeRegister(MAX86150_Addr, ppgConfigReg0,0b11010111); //D3 for 100Hz, PPG_ADC_RGE: 32768nA, PPG_SR: 100SpS, PPG_LED_PW: 400uS 
+    writeRegister(MAX86150_Addr, ppgConfigReg0,0b11010111); //D3 for 100Hz, PPG_ADC_RGE: 32768nA, PPG_SR: 100SpS, PPG_LED_PW: 400uS
     writeRegister(MAX86150_Addr,LED1PulseAmpReg, ppgOn ? rCurrent : 0x00 );
     writeRegister(MAX86150_Addr,LED2PulseAmpReg, ppgOn ? irCurrent : 0x00);
     writeRegister(MAX86150_Addr,LEDRangeReg, irHiPWR * 2 + redHiPWR ); // PPG_ADC_RGE: 32768nA
     //ecg configuration
     if (ecgOn) {
         //****************************************
-        //ECG data rate is user configurable in theory, but you have to adjust your filter time constants and serial printEvery variables accordingly 
+        //ECG data rate is user configurable in theory, but you have to adjust your filter time constants and serial printEvery variables accordingly
         writeRegister(MAX86150_Addr,EcgConfigReg1,ecgRate); //ECG sample rate 0x00 =1600, 0x01=800Hz etc down to 200Hz. add 4 to double frequency (double ADC clock)
         writeRegister(MAX86150_Addr,EcgConfigReg2,0x11); //hidden register at ECG config 2, per JY's settings
         writeRegister(MAX86150_Addr,EcgConfigReg3,0x3D); //ECG config 3
         writeRegister(MAX86150_Addr,EcgConfigReg4,0x02); //ECG config 4 per JY's settings
-    //enter test mode
+        //enter test mode
         writeRegister(MAX86150_Addr,0xFF,0x54); //write 0x54 to register 0xFF
         writeRegister(MAX86150_Addr,0xFF,0x4D); //write 0x4D to register 0xFF
         writeRegister(MAX86150_Addr,0xCE,0x01);
         writeRegister(MAX86150_Addr,0xCF,0x18); //adjust hidden registers at CE and CF per JY's settings in EV kit
         writeRegister(MAX86150_Addr,0xD0,0x01);   //adjust hidden registers D0 (probably ETI)
-        writeRegister(MAX86150_Addr,0xFF,0x00); //exit test mode      
+        writeRegister(MAX86150_Addr,0xFF,0x00); //exit test mode
     }
     //setup interrupts last
     writeRegister(MAX86150_Addr,InterruptEnableReg1,( almostFullIntEn ? 0x80 : (ppgRdyIntEn ? 0x40 : 0x00) ) );
     writeRegister(MAX86150_Addr,InterruptEnableReg2, (ecgRdyIntEn ? 0x04 : 0x00) );
     writeRegister(MAX86150_Addr,SystemControlReg,0x04);//start FIFO
-    
+
     pc.printf("done configuring MAX86150\r\n");
 } //end initMAX86150
 
 
-bool readFIFO(int numSamples, char *fifodata) {
+bool readFIFO(int numSamples, char *fifodata)
+{
     char stat[1];
     bool dataValid = 0;
     uint8_t tries = 0;
@@ -255,15 +263,15 @@
     clearInterrupts(stat);
     //get FIFO position
     readRegisters(MAX86150_Addr, FIFOReadPointerReg, i2cReadBuffer, 1); //you can do more sophisticated stuff looking for missed samples, but I'm keeping this lean and simple
-    char readPointer = i2cReadBuffer[0];  
-    while(!dataValid) { 
+    char readPointer = i2cReadBuffer[0];
+    while(!dataValid) {
         tries++;
         //try reading FIFO
         readRegisters(MAX86150_Addr, FIFODataReg, fifodata, bytes2Read); //get data
         //see if it worked if you are not servicing interrupts faster than the sample rate
         //if you are servicing interrupts much faster than the sample rate, then you can get rid of the extra pointer register check.
         dataValid=1;
-        //readRegisters(MAX86150_Addr, FIFOReadPointerReg, i2cReadBuffer, 1); //check that the read pointer has moved (otherwise FIFO was being written to)        
+        //readRegisters(MAX86150_Addr, FIFOReadPointerReg, i2cReadBuffer, 1); //check that the read pointer has moved (otherwise FIFO was being written to)
 //        newReadPointer = i2cReadBuffer[0];
 //        if( (newReadPointer - readPointer == numSamples) || (newReadPointer+32 -readPointer ==numSamples ) ){ //check that we got the right number of samples (including FIFO pointer wrap around possiblity)
 //            dataValid=1;
@@ -274,72 +282,74 @@
 //        }
 //        else {
 //            wait_us(100); //try again a moment later
-//        } 
+//        }
     }
     return dataValid;
 } //end readFIFO
 
 //for serial monitoring
-void printData(uint16_t numSamples,char *fifodata) {
-  //cat and mask the bits from the FIFO
-  for (int n = 0; n < numSamples; n++) { //for every sample
-    char p = bytesPerSample;
-    for (int m=0;m<numMeasEnabled;m++) { //for every enabled measurement
-      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]);
-      if (bitRead(data[m][n], 17) &&  ( (ecgChannel==m) || (etiChannel==m) )  ) {//handle ECG and ETI differently than PPG data.       data[m][n] |= 0xFFFC0000;
-        data[m][n] |= 0xFFFC0000;
-      }
+void printData(uint16_t numSamples,char *fifodata)
+{
+    //cat and mask the bits from the FIFO
+    for (int n = 0; n < numSamples; n++) { //for every sample
+        char p = bytesPerSample;
+        for (int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
+            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]);
+            if (bitRead(data[m][n], 17) &&  ( (ecgChannel==m) || (etiChannel==m) )  ) {//handle ECG and ETI differently than PPG data.       data[m][n] |= 0xFFFC0000;
+                data[m][n] |= 0xFFFC0000;
+            }
+        }
     }
-  }
-  for (int n = 0; n < numSamples; n++) { //for every sample
-    ind++;
-    ind = ind % printEvery;
-    
-    //calc avg and baseline
-    for(int m=0;m<numMeasEnabled;m++) { //for every enabled measurement
-      dataAvg[m] += ( data[m][n] - dataAvg[m] ) >> bits2Avg[m] ; //get the running average
-      dataBaseline[m] +=  ( data[m][n] - dataBaseline[m] ) >> bits2AvgBaseline[m]; //get the long baseline
-    }
+    for (int n = 0; n < numSamples; n++) { //for every sample
+        ind++;
+        ind = ind % printEvery;
+
+        //calc avg and baseline
+        for(int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
+            dataAvg[m] += ( data[m][n] - dataAvg[m] ) >> bits2Avg[m] ; //get the running average
+            dataBaseline[m] +=  ( data[m][n] - dataBaseline[m] ) >> bits2AvgBaseline[m]; //get the long baseline
+        }
 
-    //print data
-    if (ind == 1) { //printing only every specified number of samples to reduce serial traffic to manageable level
-      for (int m=0;m<numMeasEnabled;m++) {//for every enabled measurement
-       if(bits2AvgBaseline[m]>0) {
-        pc.printf("%i, ",dataAvg[m]-dataBaseline[m]); //print with baseline subtraction 
-       }
-       else {
-        pc.printf("%i, ", dataAvg[m]); //print without baseline subtraction
-       }
-      }
-      pc.printf("\r\n");
-    } //end print loop
-  } //end sample loop
+        //print data
+        if (ind == 1) { //printing only every specified number of samples to reduce serial traffic to manageable level
+            for (int m=0; m<numMeasEnabled; m++) { //for every enabled measurement
+                if(bits2AvgBaseline[m]>0) {
+                    pc.printf("%i, ",dataAvg[m]-dataBaseline[m]); //print with baseline subtraction
+                } else {
+                    pc.printf("%i, ", dataAvg[m]); //print without baseline subtraction
+                }
+            }
+            pc.printf("\r\n");
+        } //end print loop
+    } //end sample loop
 }//end printData()
 
 
 
 
 //for debugging
-void printRawFIFO(int numSamples,char *fifodata) {
-  //  Serial.print("FIFO bytes ");
-  for (int n = 0; n < numSamples; n++) {//for every sample.
-    for (int m=0;m<numMeasEnabled;m++) {//for every kind of measurement
-      pc.printf("%d: ",m);
-      pc.printf("%x, %x, %x, ",fifodata[bytesPerSample * n +3*m], fifodata[bytesPerSample * n + 1 +3*m], fifodata[bytesPerSample * n + 2 + 3*m] );
-    } //end measurement loop
-    pc.printf("\r\n");
-  } //end sample loop
+void printRawFIFO(int numSamples,char *fifodata)
+{
+    //  Serial.print("FIFO bytes ");
+    for (int n = 0; n < numSamples; n++) {//for every sample.
+        for (int m=0; m<numMeasEnabled; m++) { //for every kind of measurement
+            pc.printf("%d: ",m);
+            pc.printf("%x, %x, %x, ",fifodata[bytesPerSample * n +3*m], fifodata[bytesPerSample * n + 1 +3*m], fifodata[bytesPerSample * n + 2 + 3*m] );
+        } //end measurement loop
+        pc.printf("\r\n");
+    } //end sample loop
 } //end function
 
 
-void setupASIC(void) {
+void setupASIC(void)
+{
     pc.printf("Running Setup\r\n");
     runSetup = 0; //only run once
     i2c.frequency(recommendedi2cFreq); //set I2C frequency to 400kHz
 //        intPin.mode(PullUp); //pullups on the sensor board
     //configure MAX86150 register settings
     initMAX86150();
-    pc.printf("register dump\r\n");       
+    pc.printf("register dump\r\n");
 
 //    //print register configuration
 //    regDump(MAX86150_Addr,0x00, 0x06);
@@ -352,7 +362,7 @@
 //    regDump(MAX86150_Addr,0xD0, 0xD0);
 //    writeRegister(MAX86150_Addr,0xFF,0x00);
     clearInterrupts(i2cReadBuffer);
-       i2c.frequency(maxi2cFreq);
+    i2c.frequency(maxi2cFreq);
     //configure averaging
     if(ppgOn) {
         bits2Avg[rChannel]=ppgBits2Avg;
@@ -360,11 +370,11 @@
         bits2AvgBaseline[rChannel]=ppgBaselineBits;
         bits2AvgBaseline[irChannel]=ppgBaselineBits;
     }
-    if(ecgOn){
+    if(ecgOn) {
         bits2Avg[ecgChannel]=ecgBits2Avg;
         bits2AvgBaseline[ecgChannel]=ecgBaselineBits;
     }
-    if(etiOn){
+    if(etiOn) {
         bits2Avg[etiChannel]=etiBits2Avg;
         bits2AvgBaseline[etiChannel]=etiBaselineBits;
     }
@@ -373,43 +383,43 @@
 
 
 
-int main() {
+int main()
+{
     char FIFOData[bytesPerSample];
     if(runSetup) {
         setupASIC();
-    }   
-        
+    }
+
     intPin.fall(&intEvent);
     while(1) {
-          char stat[1];
-          static int n = 0;
-          if (intFlagged) {
+        char stat[1];
+        static int n = 0;
+        if (intFlagged) {
 //            pc.printf("intFlagged\r\n");
             if (almostFullIntEn) {
-              n = 0;
-              intFlagged = 0;
-              readFIFO(samples2Read,FIFOData);
-              printData(samples2Read,FIFOData);
-//              printRawFIFO(samples2Read,FIFOData); //for debugging
-            } //end if AFULL
-            else { //this is to handle end of conversion interrupts (not configured by default)
-              if (n < samples2Read) {
-                n++;
-                intFlagged = 0;
-                clearInterrupts(stat);
-                //      Serial.println(n);
-              }
-              else {
                 n = 0;
                 intFlagged = 0;
                 readFIFO(samples2Read,FIFOData);
                 printData(samples2Read,FIFOData);
-                pc.printf("\r\n");
-                //      printRawFIFO(samples2Read);
-              }
+//              printRawFIFO(samples2Read,FIFOData); //for debugging
+            } //end if AFULL
+            else { //this is to handle end of conversion interrupts (not configured by default)
+                if (n < samples2Read) {
+                    n++;
+                    intFlagged = 0;
+                    clearInterrupts(stat);
+                    //      Serial.println(n);
+                } else {
+                    n = 0;
+                    intFlagged = 0;
+                    readFIFO(samples2Read,FIFOData);
+                    printData(samples2Read,FIFOData);
+                    pc.printf("\r\n");
+                    //      printRawFIFO(samples2Read);
+                }
             } //end if/else AFULL
-          } //end if intFlagged
-    } //end while  
+        } //end if intFlagged
+    } //end while
 
 }//end main
 
@@ -435,4 +445,3 @@
 *  200    3    3
 *  200    4    1
 */
- 
\ No newline at end of file