MAX30100 pulse rate sensor

Dependencies:   PulseRate

Dependents:   PulseRate

MAX30100.h

Committer:
kohlerba
Date:
2017-11-26
Revision:
4:008e40a7d035
Parent:
3:fa37b0c705b3

File content as of revision 4:008e40a7d035:

#ifndef MAX30100_H
#define MAX30100_H

#include "mbed.h"

//definitions
#define MAX30100_ADDRESS 0xAE

// Registers
#define MAX30100_INT_STATUS     0x00  // Which interrupts are tripped
#define MAX30100_INT_ENABLE     0x01  // Which interrupts are active
#define MAX30100_FIFO_WR_PTR    0x02  // Where data is being written
#define MAX30100_OVRFLOW_CTR    0x03  // Number of lost samples
#define MAX30100_FIFO_RD_PTR    0x04  // Where to read from
#define MAX30100_FIFO_DATA      0x05  // Ouput data buffer
#define MAX30100_MODE_CONFIG    0x06  // Control register
#define MAX30100_SPO2_CONFIG    0x07  // Oximetry settings
#define MAX30100_LED_CONFIG     0x09  // Pulse width and power of LEDs
#define MAX30100_TEMP_INTG      0x16  // Temperature value, whole number
#define MAX30100_TEMP_FRAC      0x17  // Temperature value, fraction
#define MAX30100_REV_ID         0xFE  // Part revision
#define MAX30100_PART_ID        0xFF  // Part ID, normally 0x11

#define POR_PART_ID             0x11

//Mode Configuration register
#define MAX30100_MC_TEMP_EN                     (1 << 3)
#define MAX30100_MC_RESET                       (1 << 6)
#define MAX30100_MC_SHDN                        (1 << 7)

typedef enum Mode {
    MAX30100_MODE_HRONLY    = 0x02,
    MAX30100_MODE_SPO2_HR   = 0x03
} Mode;

// SpO2 Configuration register
// Check tables 8 and 9, p19 of the MAX30100 datasheet to see the permissible
// combinations of sampling rates and pulse widths
#define MAX30100_SPC_SPO2_HI_RES_EN             (1 << 6)
typedef enum SamplingRate {
    MAX30100_SAMPRATE_50HZ      = 0x00,
    MAX30100_SAMPRATE_100HZ     = 0x01,
    MAX30100_SAMPRATE_167HZ     = 0x02,
    MAX30100_SAMPRATE_200HZ     = 0x03,
    MAX30100_SAMPRATE_400HZ     = 0x04,
    MAX30100_SAMPRATE_600HZ     = 0x05,
    MAX30100_SAMPRATE_800HZ     = 0x06,
    MAX30100_SAMPRATE_1000HZ    = 0x07
} SamplingRate;

typedef enum LEDPulseWidth {
    MAX30100_SPC_PW_200US_13BITS    = 0x00,
    MAX30100_SPC_PW_400US_14BITS    = 0x01,
    MAX30100_SPC_PW_800US_15BITS    = 0x02,
    MAX30100_SPC_PW_1600US_16BITS   = 0x03
} LEDPulseWidth;

// LED Configuration register
typedef enum LEDCurrent {
    MAX30100_LED_CURR_0MA      = 0x00,
    MAX30100_LED_CURR_4_4MA    = 0x01,
    MAX30100_LED_CURR_7_6MA    = 0x02,
    MAX30100_LED_CURR_11MA     = 0x03,
    MAX30100_LED_CURR_14_2MA   = 0x04,
    MAX30100_LED_CURR_17_4MA   = 0x05,
    MAX30100_LED_CURR_20_8MA   = 0x06,
    MAX30100_LED_CURR_24MA     = 0x07,
    MAX30100_LED_CURR_27_1MA   = 0x08,
    MAX30100_LED_CURR_30_6MA   = 0x09,
    MAX30100_LED_CURR_33_8MA   = 0x0a,
    MAX30100_LED_CURR_37MA     = 0x0b,
    MAX30100_LED_CURR_40_2MA   = 0x0c,
    MAX30100_LED_CURR_43_6MA   = 0x0d,
    MAX30100_LED_CURR_46_8MA   = 0x0e,
    MAX30100_LED_CURR_50MA     = 0x0f
} LEDCurrent;

#define DEFAULT_MODE                MAX30100_MODE_HRONLY
#define DEFAULT_SAMPLING_RATE       MAX30100_SAMPRATE_100HZ
#define DEFAULT_PULSE_WIDTH         MAX30100_SPC_PW_1600US_16BITS
#define DEFAULT_RED_LED_CURRENT     MAX30100_LED_CURR_50MA
#define DEFAULT_IR_LED_CURRENT      MAX30100_LED_CURR_50MA
#define EXPECTED_PART_ID            0x11

//Set up I2C, (SDA,SCL)
static I2C i2c(I2C_SDA, I2C_SCL);
static Serial pc(USBTX, USBRX); // tx, rx

class MAX30100 {
 
    protected:
 
    public:
    
    //Variables
    uint16_t rawIRValue;
    uint16_t rawRedValue;
    
    //Wire read and write protocols
static int i2c_write (uint8_t i2c_addr, uint8_t register_addr, char* buffer, uint8_t Nbyte )
{
    int ret;
    char *tmp_buffer;

    tmp_buffer = (char*)malloc(sizeof(char)*(Nbyte+1));

    /* First, send device address. Then, send data and STOP condition */
    tmp_buffer[0] = register_addr;
    memcpy(tmp_buffer+1, buffer, Nbyte);

    ret = i2c.write(i2c_addr, tmp_buffer, Nbyte+1, false);

    return ret;
}

static int i2c_read (uint8_t i2c_addr, uint8_t register_addr, char* buffer, uint8_t Nbyte )
{
    int ret;

    /* Send device address, with no STOP condition */
    ret = i2c.write(i2c_addr, (const char*)&register_addr, 1, true);
    if(!ret) {
        /* Read data, with STOP condition  */
        ret = i2c.read((i2c_addr|0x01), buffer, Nbyte, false);
    }

    return ret;
}
    //

uint8_t getRevID(void){
  char buffer[1];
  i2c_read(MAX30100_ADDRESS, MAX30100_REV_ID, &buffer[0], 1);
  return buffer[0];
}

uint8_t getPartID(void){
  char buffer[1];
  i2c_read(MAX30100_ADDRESS, MAX30100_PART_ID, &buffer[0], 1);
  return buffer[0];
}

void shutdown(void){
    char reg[1];
    i2c_read(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
    reg[0] = reg[0] | MAX30100_MC_SHDN;
    i2c_write(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
}

void resume(void){
    char reg[1];
    i2c_read(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
    reg[0] = reg[0] & ~MAX30100_MC_SHDN;
    i2c_write(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
}

void update(void){
    readFifoData();
}

void printRegisters(void){
    char reg[1];
    i2c_read(MAX30100_ADDRESS, MAX30100_INT_STATUS, &reg[0], 1);
    pc.printf("MAX30100_INT_STATUS: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_INT_ENABLE, &reg[0], 1);
    pc.printf("MAX30100_INT_ENABLE: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_FIFO_WR_PTR, &reg[0], 1);
    pc.printf("MAX30100_FIFO_WR_PTR: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_OVRFLOW_CTR, &reg[0], 1);
    pc.printf("MAX30100_OVRFLOW_CTR: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_FIFO_RD_PTR, &reg[0], 1);
    pc.printf("MAX30100_FIFO_RD_PTR: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_FIFO_DATA, &reg[0], 1);
    pc.printf("MAX30100_FIFO_DATA: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
    pc.printf("MAX30100_MODE_CONFIG: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_SPO2_CONFIG, &reg[0], 1);
    pc.printf("MAX30100_SPO2_CONFIG: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_LED_CONFIG, &reg[0], 1);
    pc.printf("MAX30100_LED_CONFIG: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_TEMP_INTG, &reg[0], 1);
    pc.printf("MAX30100_TEMP_INTG: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_TEMP_FRAC, &reg[0], 1);
    pc.printf("MAX30100_TEMP_FRAC: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_REV_ID, &reg[0], 1);
    pc.printf("MAX30100_REV_ID: %d\r\n",reg[0]);
    i2c_read(MAX30100_ADDRESS, MAX30100_PART_ID, &reg[0], 1);
    pc.printf("MAX30100_PART_ID: %d\r\n",reg[0]);
}

bool begin(){
    if(getPartID() != POR_PART_ID){
        return false;
    }
    setMode(DEFAULT_MODE);
    setLedsPulseWidth(DEFAULT_PULSE_WIDTH);
    setSamplingRate(DEFAULT_SAMPLING_RATE);
    setLedsCurrent(DEFAULT_IR_LED_CURRENT, DEFAULT_RED_LED_CURRENT);
    setHighresModeEnabled(true);
    
    return true;
}

void setMode(Mode mode){
    char reg[1];
    reg[0] = mode;
    i2c_write(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
}

void setLedsPulseWidth(LEDPulseWidth ledPulseWidth){
    char reg[1];
    i2c_read(MAX30100_ADDRESS, MAX30100_SPO2_CONFIG, &reg[0], 1);
    reg[0] = (reg[0] & 0xfc) | ledPulseWidth;
    i2c_write(MAX30100_ADDRESS, MAX30100_SPO2_CONFIG, &reg[0], 1);
}

void setSamplingRate(SamplingRate samplingRate){
    char reg[1];
    i2c_read(MAX30100_ADDRESS, MAX30100_SPO2_CONFIG, &reg[0], 1);
    reg[0] = (reg[0] & 0xe3) | (samplingRate << 2);
    i2c_write(MAX30100_ADDRESS, MAX30100_SPO2_CONFIG, &reg[0], 1);
}

void setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent){
    char reg[1];
    reg[0] = (redLedCurrent << 4) | irLedCurrent;
    i2c_write(MAX30100_ADDRESS, MAX30100_LED_CONFIG, &reg[0], 1);
}

void setHighresModeEnabled(bool enabled){
    char reg[1];
    i2c_read(MAX30100_ADDRESS, MAX30100_SPO2_CONFIG, &reg[0], 1);
    if(enabled){
        reg[0] = reg[0] | MAX30100_SPC_SPO2_HI_RES_EN;
    }
    else{
        reg[0] = reg[0] & ~MAX30100_SPC_SPO2_HI_RES_EN;
    }
    i2c_write(MAX30100_ADDRESS, MAX30100_SPO2_CONFIG, &reg[0], 1);
}

void readFifoData(void){
    char reg[4];
    i2c_read(MAX30100_ADDRESS, MAX30100_FIFO_DATA, &reg[0], 4);
    rawIRValue = (reg[0] << 8) | reg[1];
    rawRedValue = (reg[2] << 8) | reg[3];
}

void startTemperatureSampling(void){
    char reg[1];
    i2c_read(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
    reg[0] = reg[0] | MAX30100_MC_TEMP_EN;
    i2c_write(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
}

bool isTemperatureReady(void){
    char reg[1];
    bool ret;
    ret = i2c_read(MAX30100_ADDRESS, MAX30100_MODE_CONFIG, &reg[0], 1);
    ret = ret & MAX30100_MC_TEMP_EN;
    return !ret;
}

float retrieveTemperature(void){
    char reg[2];
    i2c_read(MAX30100_ADDRESS, MAX30100_TEMP_INTG, &reg[0], 1);
    i2c_read(MAX30100_ADDRESS, MAX30100_TEMP_FRAC, &reg[1], 1);
    return reg[0] + (reg[1] * 0.0625);
}

};
#endif