Greg Steiert / MAX30105

Dependents:   Temp_Prox_Demo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MAX30105.cpp Source File

MAX30105.cpp

00001 /** \file max30105.cpp ******************************************************
00002 *
00003 * Project: MAXREFDES117#
00004 * Filename: max30105.cpp
00005 * Description: This module is an embedded controller driver for the MAX30105
00006 *
00007 * ------------------------------------------------------------------------- */
00008 /*******************************************************************************
00009 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
00010 *
00011 * Permission is hereby granted, free of charge, to any person obtaining a
00012 * copy of this software and associated documentation files (the "Software"),
00013 * to deal in the Software without restriction, including without limitation
00014 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00015 * and/or sell copies of the Software, and to permit persons to whom the
00016 * Software is furnished to do so, subject to the following conditions:
00017 *
00018 * The above copyright notice and this permission notice shall be included
00019 * in all copies or substantial portions of the Software.
00020 *
00021 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00022 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00023 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00024 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00025 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00026 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00027 * OTHER DEALINGS IN THE SOFTWARE.
00028 *
00029 * Except as contained in this notice, the name of Maxim Integrated
00030 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00031 * Products, Inc. Branding Policy.
00032 *
00033 * The mere transfer of this software does not imply any licenses
00034 * of trade secrets, proprietary technology, copyrights, patents,
00035 * trademarks, maskwork rights, or any other form of intellectual
00036 * property whatsoever. Maxim Integrated Products, Inc. retains all
00037 * ownership rights.
00038 *******************************************************************************
00039 */
00040 #include "mbed.h"
00041 #include "MAX30105.h"
00042 
00043 //******************************************************************************
00044 MAX30105::MAX30105(I2C &i2c): _i2c(i2c)
00045 {
00046 }
00047 
00048 //******************************************************************************
00049 MAX30105::~MAX30105()
00050 {
00051 }
00052 
00053 //******************************************************************************
00054 int MAX30105::writeReg(registers_t reg,  char value)
00055 {
00056     char cmdData[2] = { (char)reg, value };
00057 
00058     if (_i2c.write(MAX30105_I2C_ADDR, cmdData, sizeof(cmdData)) != 0) {
00059         return MAX30105_ERROR;
00060     }
00061 
00062     return MAX30105_NO_ERROR;
00063 }
00064 
00065 //******************************************************************************
00066 int MAX30105::readReg(registers_t reg, char *value)
00067 {
00068     char cmdData[1] = { (char)reg };
00069 
00070     if (_i2c.write(MAX30105_I2C_ADDR, cmdData, sizeof(cmdData)) != 0) {
00071         return MAX30105_ERROR;
00072     }
00073 
00074     if (_i2c.read(MAX30105_I2C_ADDR, value, 1) != 0) {
00075         return MAX30105_ERROR;
00076     }
00077 
00078     return MAX30105_NO_ERROR;
00079 }
00080 
00081 //******************************************************************************
00082 int MAX30105::setSingleLED(smp_ave_t smpAve,
00083                     bool fifoRollOver,
00084                     fifo_a_full_t fifoAFull,
00085                     adc_rge_t adcRange,
00086                     smp_rt_t smpRate,
00087                     led_pw_t ledPW,
00088                     char led1PA) {
00089     char dataBuf[4];                    
00090     _fifoConfiguration = (smpAve & MASK_SMP_AVE) | (fifoAFull & MASK_FIFO_A_FULL);
00091     if(fifoRollOver) _fifoConfiguration |= MASK_FIFO_ROLLOVER_EN;
00092     _modeConfiguration = (_modeConfiguration & MASK_SHDN) | MODE_1LED;
00093     _spo2Configuration = (adcRange & MASK_ADC_RGE) | (smpRate & MASK_SMP_RT) | (ledPW & MASK_LED_PW);
00094     _led1PulseAmplitude = led1PA;
00095     dataBuf[0] = REG_LED1_PA;
00096     dataBuf[1] = _led1PulseAmplitude;
00097     if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 2) != 0) return MAX30105_ERROR;
00098     dataBuf[0] = REG_FIFO_CONFIG;
00099     dataBuf[1] = _fifoConfiguration;
00100     dataBuf[2] = _modeConfiguration;
00101     dataBuf[3] = _spo2Configuration;
00102     if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
00103     
00104     return MAX30105_NO_ERROR;
00105 }
00106 
00107 //******************************************************************************
00108 int MAX30105::setDualLED(smp_ave_t smpAve,
00109                     bool fifoRollOver,
00110                     fifo_a_full_t fifoAFull,
00111                     adc_rge_t adcRange,
00112                     smp_rt_t smpRate,
00113                     led_pw_t ledPW,
00114                     char led1PA,
00115                     char led2PA) {
00116     char dataBuf[4];                    
00117     _fifoConfiguration = (smpAve & MASK_SMP_AVE) | (fifoAFull & MASK_FIFO_A_FULL);
00118     if(fifoRollOver) _fifoConfiguration |= MASK_FIFO_ROLLOVER_EN;
00119     _modeConfiguration = (_modeConfiguration & MASK_SHDN) | MODE_2LED;
00120     _spo2Configuration = (adcRange & MASK_ADC_RGE) | (smpRate & MASK_SMP_RT) | (ledPW & MASK_LED_PW);
00121     _led1PulseAmplitude = led1PA;
00122     _led2PulseAmplitude = led2PA;
00123     dataBuf[0] = REG_LED1_PA;
00124     dataBuf[1] = _led1PulseAmplitude;
00125     dataBuf[2] = _led2PulseAmplitude;
00126     if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 3) != 0) return MAX30105_ERROR;
00127     dataBuf[0] = REG_FIFO_CONFIG;
00128     dataBuf[1] = _fifoConfiguration;
00129     dataBuf[2] = _modeConfiguration;
00130     dataBuf[3] = _spo2Configuration;
00131     if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
00132     
00133     return MAX30105_NO_ERROR;
00134 }
00135 
00136 //******************************************************************************
00137 int MAX30105::setMultiLED(smp_ave_t smpAve,
00138                     bool fifoRollOver,
00139                     fifo_a_full_t fifoAFull,
00140                     adc_rge_t adcRange,
00141                     smp_rt_t smpRate,
00142                     led_pw_t ledPW,
00143                     char led1PA,
00144                     char led2PA,
00145                     char led3PA,
00146                     char pilotPA,
00147                     slot_t slot1,
00148                     slot_t slot2,
00149                     slot_t slot3,
00150                     slot_t slot4) {
00151     char dataBuf[4];                    
00152     _fifoConfiguration = (smpAve & MASK_SMP_AVE) | (fifoAFull & MASK_FIFO_A_FULL);
00153     if(fifoRollOver) _fifoConfiguration |= MASK_FIFO_ROLLOVER_EN;
00154     _modeConfiguration = (_modeConfiguration & MASK_SHDN) | MODE_MULTI;
00155     _spo2Configuration = (adcRange & MASK_ADC_RGE) | (smpRate & MASK_SMP_RT) | (ledPW & MASK_LED_PW);
00156     _led1PulseAmplitude = led1PA;
00157     _led2PulseAmplitude = led2PA;
00158     _led3PulseAmplitude = led3PA;
00159     _pilotPulseAmplitude = pilotPA;
00160     _multiLedControl1 = (slot2 << 4) | slot1;
00161     _multiLedControl2 = (slot4 << 4) | slot3;
00162     dataBuf[0] = REG_PILOT_PA;
00163     dataBuf[1] = _pilotPulseAmplitude;
00164     dataBuf[2] = _multiLedControl1;
00165     dataBuf[3] = _multiLedControl2;
00166     if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
00167     dataBuf[0] = REG_LED1_PA;
00168     dataBuf[1] = _led1PulseAmplitude;
00169     dataBuf[2] = _led2PulseAmplitude;
00170     dataBuf[3] = _led3PulseAmplitude;
00171     if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
00172     dataBuf[0] = REG_FIFO_CONFIG;
00173     dataBuf[1] = _fifoConfiguration;
00174     dataBuf[2] = _modeConfiguration;
00175     dataBuf[3] = _spo2Configuration;
00176     if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 4) != 0) return MAX30105_ERROR;
00177     
00178     return MAX30105_NO_ERROR;
00179 }
00180 
00181 //******************************************************************************
00182 int MAX30105::init()
00183 {
00184     if(writeReg(REG_INTR_ENABLE_1,0xc0) != MAX30105_NO_ERROR) // INTR setting
00185         return MAX30105_ERROR;
00186     if(writeReg(REG_INTR_ENABLE_2,0x00) != MAX30105_NO_ERROR)
00187         return MAX30105_ERROR;
00188     if(writeReg(REG_FIFO_WR_PTR,0x00) != MAX30105_NO_ERROR)  //FIFO_WR_PTR[4:0]
00189         return MAX30105_ERROR;
00190     if(writeReg(REG_OVF_COUNTER,0x00) != MAX30105_NO_ERROR)  //OVF_COUNTER[4:0]
00191         return MAX30105_ERROR;
00192     if(writeReg(REG_FIFO_RD_PTR,0x00) != MAX30105_NO_ERROR)  //FIFO_RD_PTR[4:0]
00193         return MAX30105_ERROR;
00194     if(writeReg(REG_FIFO_CONFIG,0x0f) != MAX30105_NO_ERROR)  //sample avg = 1, fifo rollover=false, fifo almost full = 17
00195         return MAX30105_ERROR;
00196     if(writeReg(REG_MODE_CONFIG,0x03) != MAX30105_NO_ERROR)   //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
00197         return MAX30105_ERROR;
00198     if(writeReg(REG_SPO2_CONFIG,0x27) != MAX30105_NO_ERROR)  // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
00199         return MAX30105_ERROR;
00200     if(writeReg(REG_LED1_PA,0x24) != MAX30105_NO_ERROR)   //Choose value for ~ 7mA for LED1
00201         return MAX30105_ERROR;
00202     if(writeReg(REG_LED2_PA,0x24) != MAX30105_NO_ERROR)   // Choose value for ~ 7mA for LED2
00203         return MAX30105_ERROR;
00204     if(writeReg(REG_PILOT_PA,0x7f) != MAX30105_NO_ERROR)   // Choose value for ~ 25mA for Pilot LED
00205         return MAX30105_ERROR;
00206     return MAX30105_NO_ERROR;
00207 }
00208 
00209 int MAX30105::readFIFO(uint32_t *redLED, uint32_t *irLED)
00210 {
00211     uint32_t un_temp;
00212 //    char uch_temp;
00213     *redLED=0;
00214     *irLED=0;
00215     char ach_i2c_data[6];
00216 
00217     //read and clear status register
00218     //readReg(REG_INTR_STATUS_1, &uch_temp);
00219     //readReg(REG_INTR_STATUS_2, &uch_temp);
00220 
00221     ach_i2c_data[0]=REG_FIFO_DATA;
00222     if(_i2c.write(MAX30105_I2C_ADDR, ach_i2c_data, 1, true)!=0)
00223         return MAX30105_ERROR;
00224     if(_i2c.read(MAX30105_I2C_ADDR, ach_i2c_data, 6, false)!=0) {
00225         return MAX30105_ERROR;
00226     }
00227     un_temp=(unsigned char) ach_i2c_data[0];
00228     un_temp<<=16;
00229     *redLED+=un_temp;
00230     un_temp=(unsigned char) ach_i2c_data[1];
00231     un_temp<<=8;
00232     *redLED+=un_temp;
00233     un_temp=(unsigned char) ach_i2c_data[2];
00234     *redLED+=un_temp;
00235 
00236     un_temp=(unsigned char) ach_i2c_data[3];
00237     un_temp<<=16;
00238     *irLED+=un_temp;
00239     un_temp=(unsigned char) ach_i2c_data[4];
00240     un_temp<<=8;
00241     *irLED+=un_temp;
00242     un_temp=(unsigned char) ach_i2c_data[5];
00243     *irLED+=un_temp;
00244     *redLED&=0x03FFFF;  //Mask MSB [23:18]
00245     *irLED&=0x03FFFF;  //Mask MSB [23:18]
00246 
00247 
00248     return MAX30105_NO_ERROR;
00249 }
00250 
00251 
00252 //******************************************************************************
00253 int MAX30105::getIntr1()
00254 {
00255     char * intStatus;
00256     if(readReg(REG_INTR_STATUS_1, intStatus) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
00257     return (int)*intStatus;
00258 }
00259 
00260 //******************************************************************************
00261 int MAX30105::getIntr2()
00262 {
00263     char * intStatus;
00264     if(readReg(REG_INTR_STATUS_2, intStatus) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
00265     return (int)*intStatus;
00266 }
00267 
00268 //******************************************************************************
00269 int MAX30105::enableIntr(char intrBits)
00270 {
00271     char intr1 = intrBits & (INTR_A_FULL|INTR_DATA_RDY|INTR_ALC_OVF|INTR_PROX);
00272     char intr2 = intrBits & INTR_TEMP_RDY;
00273     _interruptEnable1 |= intr1;
00274     if(writeReg(REG_INTR_ENABLE_1, _interruptEnable1) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;    
00275     _interruptEnable2 |= intr2;
00276     if(writeReg(REG_INTR_ENABLE_2, _interruptEnable2) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;    
00277     return MAX30105_NO_ERROR;
00278 }
00279 
00280 //******************************************************************************
00281 int MAX30105::disableIntr(char intrBits)
00282 {
00283     char intr1 = intrBits & (INTR_A_FULL|INTR_DATA_RDY|INTR_ALC_OVF|INTR_PROX);
00284     char intr2 = intrBits & INTR_TEMP_RDY;
00285     _interruptEnable1 &= ~intr1;
00286     if(writeReg(REG_INTR_ENABLE_1, _interruptEnable1) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;    
00287     _interruptEnable2 &= ~intr2;
00288     if(writeReg(REG_INTR_ENABLE_2, _interruptEnable2) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;    
00289     return MAX30105_NO_ERROR;
00290 }
00291 
00292 //******************************************************************************
00293 int MAX30105::setProx(char proxAmp, char proxThresh)
00294 {
00295     if(writeReg(REG_PILOT_PA, proxAmp) != MAX30105_NO_ERROR) return MAX30105_ERROR;
00296     if(writeReg(REG_PROX_INTR_THRESH, proxThresh) != MAX30105_NO_ERROR) return MAX30105_ERROR;
00297     return MAX30105_NO_ERROR;        
00298 }
00299 
00300 
00301 //******************************************************************************
00302 float MAX30105::readTemperature()
00303 {
00304     char dataBuf[2];
00305     int8_t * dataSigned = reinterpret_cast<int8_t *>(dataBuf);
00306 
00307     if(writeReg(REG_TEMP_CONFIG, 0x01) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
00308     wait_ms(30);
00309     if(readReg(REG_TEMP_CONFIG, dataBuf) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
00310     while (dataBuf[0]) {
00311 //        Thread::wait(1);
00312         wait_ms(1);
00313         if(readReg(REG_TEMP_CONFIG, dataBuf) != MAX30105_NO_ERROR) return MAX30105_TEMP_ERROR;
00314     }
00315     dataBuf[0] = REG_TEMP_INT;
00316     if (_i2c.write(MAX30105_I2C_ADDR, dataBuf, 1) != 0) return MAX30105_TEMP_ERROR;
00317     if (_i2c.read(MAX30105_I2C_ADDR, dataBuf, 2) != 0) return MAX30105_TEMP_ERROR;
00318     return ((float)dataSigned[0] + ((float)dataSigned[1] * 0.0625));
00319 }
00320 
00321 //******************************************************************************
00322 int MAX30105::shutDown()
00323 {
00324     _modeConfiguration |= MASK_SHDN;
00325     if(writeReg(REG_MODE_CONFIG, _modeConfiguration) != MAX30105_NO_ERROR) return MAX30105_ERROR;
00326     return MAX30105_NO_ERROR;        
00327 }
00328 
00329 //******************************************************************************
00330 int MAX30105::wakeUp()
00331 {
00332     _modeConfiguration &= ~MASK_SHDN;
00333     if(writeReg(REG_MODE_CONFIG, _modeConfiguration) != MAX30105_NO_ERROR) return MAX30105_ERROR;
00334     return MAX30105_NO_ERROR;        
00335 }
00336 
00337 //******************************************************************************
00338 int MAX30105::softReset()
00339 {
00340     if(writeReg(REG_MODE_CONFIG, MASK_RESET) != MAX30105_NO_ERROR) return MAX30105_ERROR;
00341     _interruptEnable1 = 0x00;
00342     _interruptEnable2 = 0x00;
00343     _fifoConfiguration = 0x00;
00344     _modeConfiguration = 0x00;
00345     _spo2Configuration = 0x00;
00346     _led1PulseAmplitude = 0x00;
00347     _led2PulseAmplitude = 0x00;
00348     _led3PulseAmplitude = 0x00;
00349     _pilotPulseAmplitude = 0x00;
00350     _multiLedControl1 = 0x00;
00351     _multiLedControl2 = 0x00;
00352     _proxIntThreshold = 0x00;
00353     return MAX30105_NO_ERROR;
00354 }