Library for MAX3010x optical sensors

Dependents:   Temp_Prox_Demo

MAX30105.cpp

Committer:
switches
Date:
2017-02-16
Revision:
1:411eb3796949
Parent:
0:62bc11b5bc43

File content as of revision 1:411eb3796949:

/** \file max30105.cpp ******************************************************
*
* Project: MAXREFDES117#
* Filename: max30105.cpp
* Description: This module is an embedded controller driver for the MAX30105
*
* ------------------------------------------------------------------------- */
/*******************************************************************************
* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated
* Products, Inc. shall not be used except as stated in the Maxim Integrated
* Products, Inc. Branding Policy.
*
* The mere transfer of this software does not imply any licenses
* of trade secrets, proprietary technology, copyrights, patents,
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
*******************************************************************************
*/
#include "mbed.h"
#include "MAX30105.h"

//******************************************************************************
MAX30105::MAX30105(I2C &i2c): _i2c(i2c)
{
}

//******************************************************************************
MAX30105::~MAX30105()
{
}

//******************************************************************************
int MAX30105::writeReg(registers_t reg,  char value)
{
    char cmdData[2] = { (char)reg, value };

    if (_i2c.write(MAX30105_I2C_ADDR, cmdData, sizeof(cmdData)) != 0) {
        return MAX30105_ERROR;
    }

    return MAX30105_NO_ERROR;
}

//******************************************************************************
int MAX30105::readReg(registers_t reg, char *value)
{
    char cmdData[1] = { (char)reg };

    if (_i2c.write(MAX30105_I2C_ADDR, cmdData, sizeof(cmdData)) != 0) {
        return MAX30105_ERROR;
    }

    if (_i2c.read(MAX30105_I2C_ADDR, value, 1) != 0) {
        return MAX30105_ERROR;
    }

    return MAX30105_NO_ERROR;
}

//******************************************************************************
int MAX30105::setSingleLED(smp_ave_t smpAve,
                    bool fifoRollOver,
                    fifo_a_full_t fifoAFull,
                    adc_rge_t adcRange,
                    smp_rt_t smpRate,
                    led_pw_t ledPW,
                    char led1PA) {
    char dataBuf[4];                    
    _fifoConfiguration = (smpAve & MASK_SMP_AVE) | (fifoAFull & MASK_FIFO_A_FULL);
    if(fifoRollOver) _fifoConfiguration |= MASK_FIFO_ROLLOVER_EN;
    _modeConfiguration = (_modeConfiguration & MASK_SHDN) | MODE_1LED;
    _spo2Configuration = (adcRange & MASK_ADC_RGE) | (smpRate & MASK_SMP_RT) | (ledPW & MASK_LED_PW);
    _led1PulseAmplitude = led1PA;
    dataBuf[0] = REG_LED1_PA;
    dataBuf[1] = _led1PulseAmplitude;
    if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 2) != 0) return MAX30105_ERROR;
    dataBuf[0] = REG_FIFO_CONFIG;
    dataBuf[1] = _fifoConfiguration;
    dataBuf[2] = _modeConfiguration;
    dataBuf[3] = _spo2Configuration;
    if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
    
    return MAX30105_NO_ERROR;
}

//******************************************************************************
int MAX30105::setDualLED(smp_ave_t smpAve,
                    bool fifoRollOver,
                    fifo_a_full_t fifoAFull,
                    adc_rge_t adcRange,
                    smp_rt_t smpRate,
                    led_pw_t ledPW,
                    char led1PA,
                    char led2PA) {
    char dataBuf[4];                    
    _fifoConfiguration = (smpAve & MASK_SMP_AVE) | (fifoAFull & MASK_FIFO_A_FULL);
    if(fifoRollOver) _fifoConfiguration |= MASK_FIFO_ROLLOVER_EN;
    _modeConfiguration = (_modeConfiguration & MASK_SHDN) | MODE_2LED;
    _spo2Configuration = (adcRange & MASK_ADC_RGE) | (smpRate & MASK_SMP_RT) | (ledPW & MASK_LED_PW);
    _led1PulseAmplitude = led1PA;
    _led2PulseAmplitude = led2PA;
    dataBuf[0] = REG_LED1_PA;
    dataBuf[1] = _led1PulseAmplitude;
    dataBuf[2] = _led2PulseAmplitude;
    if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 3) != 0) return MAX30105_ERROR;
    dataBuf[0] = REG_FIFO_CONFIG;
    dataBuf[1] = _fifoConfiguration;
    dataBuf[2] = _modeConfiguration;
    dataBuf[3] = _spo2Configuration;
    if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
    
    return MAX30105_NO_ERROR;
}

//******************************************************************************
int MAX30105::setMultiLED(smp_ave_t smpAve,
                    bool fifoRollOver,
                    fifo_a_full_t fifoAFull,
                    adc_rge_t adcRange,
                    smp_rt_t smpRate,
                    led_pw_t ledPW,
                    char led1PA,
                    char led2PA,
                    char led3PA,
                    char pilotPA,
                    slot_t slot1,
                    slot_t slot2,
                    slot_t slot3,
                    slot_t slot4) {
    char dataBuf[4];                    
    _fifoConfiguration = (smpAve & MASK_SMP_AVE) | (fifoAFull & MASK_FIFO_A_FULL);
    if(fifoRollOver) _fifoConfiguration |= MASK_FIFO_ROLLOVER_EN;
    _modeConfiguration = (_modeConfiguration & MASK_SHDN) | MODE_MULTI;
    _spo2Configuration = (adcRange & MASK_ADC_RGE) | (smpRate & MASK_SMP_RT) | (ledPW & MASK_LED_PW);
    _led1PulseAmplitude = led1PA;
    _led2PulseAmplitude = led2PA;
    _led3PulseAmplitude = led3PA;
    _pilotPulseAmplitude = pilotPA;
    _multiLedControl1 = (slot2 << 4) | slot1;
    _multiLedControl2 = (slot4 << 4) | slot3;
    dataBuf[0] = REG_PILOT_PA;
    dataBuf[1] = _pilotPulseAmplitude;
    dataBuf[2] = _multiLedControl1;
    dataBuf[3] = _multiLedControl2;
    if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
    dataBuf[0] = REG_LED1_PA;
    dataBuf[1] = _led1PulseAmplitude;
    dataBuf[2] = _led2PulseAmplitude;
    dataBuf[3] = _led3PulseAmplitude;
    if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
    dataBuf[0] = REG_FIFO_CONFIG;
    dataBuf[1] = _fifoConfiguration;
    dataBuf[2] = _modeConfiguration;
    dataBuf[3] = _spo2Configuration;
    if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
    
    return MAX30105_NO_ERROR;
}

//******************************************************************************
int MAX30105::init()
{
    if(writeReg(REG_INTR_ENABLE_1,0xc0) != MAX30105_NO_ERROR) // INTR setting
        return MAX30105_ERROR;
    if(writeReg(REG_INTR_ENABLE_2,0x00) != MAX30105_NO_ERROR)
        return MAX30105_ERROR;
    if(writeReg(REG_FIFO_WR_PTR,0x00) != MAX30105_NO_ERROR)  //FIFO_WR_PTR[4:0]
        return MAX30105_ERROR;
    if(writeReg(REG_OVF_COUNTER,0x00) != MAX30105_NO_ERROR)  //OVF_COUNTER[4:0]
        return MAX30105_ERROR;
    if(writeReg(REG_FIFO_RD_PTR,0x00) != MAX30105_NO_ERROR)  //FIFO_RD_PTR[4:0]
        return MAX30105_ERROR;
    if(writeReg(REG_FIFO_CONFIG,0x0f) != MAX30105_NO_ERROR)  //sample avg = 1, fifo rollover=false, fifo almost full = 17
        return MAX30105_ERROR;
    if(writeReg(REG_MODE_CONFIG,0x03) != MAX30105_NO_ERROR)   //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
        return MAX30105_ERROR;
    if(writeReg(REG_SPO2_CONFIG,0x27) != MAX30105_NO_ERROR)  // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
        return MAX30105_ERROR;
    if(writeReg(REG_LED1_PA,0x24) != MAX30105_NO_ERROR)   //Choose value for ~ 7mA for LED1
        return MAX30105_ERROR;
    if(writeReg(REG_LED2_PA,0x24) != MAX30105_NO_ERROR)   // Choose value for ~ 7mA for LED2
        return MAX30105_ERROR;
    if(writeReg(REG_PILOT_PA,0x7f) != MAX30105_NO_ERROR)   // Choose value for ~ 25mA for Pilot LED
        return MAX30105_ERROR;
    return MAX30105_NO_ERROR;
}

int MAX30105::readFIFO(uint32_t *redLED, uint32_t *irLED)
{
    uint32_t un_temp;
//    char uch_temp;
    *redLED=0;
    *irLED=0;
    char ach_i2c_data[6];

    //read and clear status register
    //readReg(REG_INTR_STATUS_1, &uch_temp);
    //readReg(REG_INTR_STATUS_2, &uch_temp);

    ach_i2c_data[0]=REG_FIFO_DATA;
    if(_i2c.write(MAX30105_I2C_ADDR, ach_i2c_data, 1, true)!=0)
        return MAX30105_ERROR;
    if(_i2c.read(MAX30105_I2C_ADDR, ach_i2c_data, 6, false)!=0) {
        return MAX30105_ERROR;
    }
    un_temp=(unsigned char) ach_i2c_data[0];
    un_temp<<=16;
    *redLED+=un_temp;
    un_temp=(unsigned char) ach_i2c_data[1];
    un_temp<<=8;
    *redLED+=un_temp;
    un_temp=(unsigned char) ach_i2c_data[2];
    *redLED+=un_temp;

    un_temp=(unsigned char) ach_i2c_data[3];
    un_temp<<=16;
    *irLED+=un_temp;
    un_temp=(unsigned char) ach_i2c_data[4];
    un_temp<<=8;
    *irLED+=un_temp;
    un_temp=(unsigned char) ach_i2c_data[5];
    *irLED+=un_temp;
    *redLED&=0x03FFFF;  //Mask MSB [23:18]
    *irLED&=0x03FFFF;  //Mask MSB [23:18]


    return MAX30105_NO_ERROR;
}


//******************************************************************************
int MAX30105::getIntr1()
{
    char * intStatus;
    if(readReg(REG_INTR_STATUS_1, intStatus) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
    return (int)*intStatus;
}

//******************************************************************************
int MAX30105::getIntr2()
{
    char * intStatus;
    if(readReg(REG_INTR_STATUS_2, intStatus) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
    return (int)*intStatus;
}

//******************************************************************************
int MAX30105::enableIntr(char intrBits)
{
    char intr1 = intrBits & (INTR_A_FULL|INTR_DATA_RDY|INTR_ALC_OVF|INTR_PROX);
    char intr2 = intrBits & INTR_TEMP_RDY;
    _interruptEnable1 |= intr1;
    if(writeReg(REG_INTR_ENABLE_1, _interruptEnable1) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;    
    _interruptEnable2 |= intr2;
    if(writeReg(REG_INTR_ENABLE_2, _interruptEnable2) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;    
    return MAX30105_NO_ERROR;
}

//******************************************************************************
int MAX30105::disableIntr(char intrBits)
{
    char intr1 = intrBits & (INTR_A_FULL|INTR_DATA_RDY|INTR_ALC_OVF|INTR_PROX);
    char intr2 = intrBits & INTR_TEMP_RDY;
    _interruptEnable1 &= ~intr1;
    if(writeReg(REG_INTR_ENABLE_1, _interruptEnable1) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;    
    _interruptEnable2 &= ~intr2;
    if(writeReg(REG_INTR_ENABLE_2, _interruptEnable2) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;    
    return MAX30105_NO_ERROR;
}

//******************************************************************************
int MAX30105::setProx(char proxAmp, char proxThresh)
{
    if(writeReg(REG_PILOT_PA, proxAmp) != MAX30105_NO_ERROR) return MAX30105_ERROR;
    if(writeReg(REG_PROX_INTR_THRESH, proxThresh) != MAX30105_NO_ERROR) return MAX30105_ERROR;
    return MAX30105_NO_ERROR;        
}


//******************************************************************************
float MAX30105::readTemperature()
{
    char dataBuf[2];
    int8_t * dataSigned = reinterpret_cast<int8_t *>(dataBuf);

    if(writeReg(REG_TEMP_CONFIG, 0x01) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
    wait_ms(30);
    if(readReg(REG_TEMP_CONFIG, dataBuf) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
    while (dataBuf[0]) {
//        Thread::wait(1);
        wait_ms(1);
        if(readReg(REG_TEMP_CONFIG, dataBuf) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
    }
    dataBuf[0] = REG_TEMP_INT;
    if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 1) != 0) return MAX30105_TEMP_ERROR;
    if (_i2c.read(MAX30105_I2C_ADDR, dataBuf, 2) != 0) return MAX30105_TEMP_ERROR;
    return ((float)dataSigned[0] + ((float)dataSigned[1] * 0.0625));
}

//******************************************************************************
int MAX30105::shutDown()
{
    _modeConfiguration |= MASK_SHDN;
    if(writeReg(REG_MODE_CONFIG, _modeConfiguration) != MAX30105_NO_ERROR) return MAX30105_ERROR;
    return MAX30105_NO_ERROR;        
}

//******************************************************************************
int MAX30105::wakeUp()
{
    _modeConfiguration &= ~MASK_SHDN;
    if(writeReg(REG_MODE_CONFIG, _modeConfiguration) != MAX30105_NO_ERROR) return MAX30105_ERROR;
    return MAX30105_NO_ERROR;        
}

//******************************************************************************
int MAX30105::softReset()
{
    if(writeReg(REG_MODE_CONFIG, MASK_RESET) != MAX30105_NO_ERROR) return MAX30105_ERROR;
    _interruptEnable1 = 0x00;
    _interruptEnable2 = 0x00;
    _fifoConfiguration = 0x00;
    _modeConfiguration = 0x00;
    _spo2Configuration = 0x00;
    _led1PulseAmplitude = 0x00;
    _led2PulseAmplitude = 0x00;
    _led3PulseAmplitude = 0x00;
    _pilotPulseAmplitude = 0x00;
    _multiLedControl1 = 0x00;
    _multiLedControl2 = 0x00;
    _proxIntThreshold = 0x00;
    return MAX30105_NO_ERROR;
}