dszds

Committer:
zinnetyazicii53
Date:
Sun Jul 28 08:14:38 2019 +0000
Revision:
0:83277b73a1f8
commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
zinnetyazicii53 0:83277b73a1f8 1 /***************************************************
zinnetyazicii53 0:83277b73a1f8 2 This is a library written for the Maxim MAX30102 Optical Smoke Detector
zinnetyazicii53 0:83277b73a1f8 3 It should also work with the MAX30102. However, the MAX30102 does not have a Green LED.
zinnetyazicii53 0:83277b73a1f8 4
zinnetyazicii53 0:83277b73a1f8 5 These sensors use I2C to communicate, as well as a single (optional)
zinnetyazicii53 0:83277b73a1f8 6 interrupt line that is not currently supported in this driver.
zinnetyazicii53 0:83277b73a1f8 7
zinnetyazicii53 0:83277b73a1f8 8 Written by Peter Jansen and Nathan Seidle (SparkFun)
zinnetyazicii53 0:83277b73a1f8 9 BSD license, all text above must be included in any redistribution.
zinnetyazicii53 0:83277b73a1f8 10 *****************************************************/
zinnetyazicii53 0:83277b73a1f8 11 /*
zinnetyazicii53 0:83277b73a1f8 12 #include "MAX30102.h"
zinnetyazicii53 0:83277b73a1f8 13
zinnetyazicii53 0:83277b73a1f8 14 #ifdef TARGET_MAX32600MBED
zinnetyazicii53 0:83277b73a1f8 15 I2C i2c(I2C1_SDA, I2C1_SCL);
zinnetyazicii53 0:83277b73a1f8 16 #else
zinnetyazicii53 0:83277b73a1f8 17 I2C i2c(I2C_SDA, I2C_SCL);
zinnetyazicii53 0:83277b73a1f8 18 #endif
zinnetyazicii53 0:83277b73a1f8 19
zinnetyazicii53 0:83277b73a1f8 20 // Status Registers
zinnetyazicii53 0:83277b73a1f8 21 #define MAX30102_INTSTAT1 0x00;
zinnetyazicii53 0:83277b73a1f8 22 #define MAX30102_INTSTAT2 0x01;
zinnetyazicii53 0:83277b73a1f8 23 #define MAX30102_INTENABLE1 0x02;
zinnetyazicii53 0:83277b73a1f8 24 #define MAX30102_INTENABLE2 0x03;
zinnetyazicii53 0:83277b73a1f8 25
zinnetyazicii53 0:83277b73a1f8 26 // FIFO Registers
zinnetyazicii53 0:83277b73a1f8 27 #define MAX30102_FIFOWRITEPTR 0x04;
zinnetyazicii53 0:83277b73a1f8 28 #define MAX30102_FIFOOVERFLOW 0x05;
zinnetyazicii53 0:83277b73a1f8 29 #define MAX30102_FIFOREADPTR 0x06;
zinnetyazicii53 0:83277b73a1f8 30 #define MAX30102_FIFODATA 0x07;
zinnetyazicii53 0:83277b73a1f8 31
zinnetyazicii53 0:83277b73a1f8 32 // Configuration Registers
zinnetyazicii53 0:83277b73a1f8 33 #define MAX30102_FIFOCONFIG 0x08;
zinnetyazicii53 0:83277b73a1f8 34 #define MAX30102_MODECONFIG 0x09;
zinnetyazicii53 0:83277b73a1f8 35 #define MAX30102_PARTICLECONFIG 0x0A; // Note, sometimes listed as "SPO2" config in datasheet (pg. 11)
zinnetyazicii53 0:83277b73a1f8 36 #define MAX30102_LED1_PULSEAMP 0x0C;
zinnetyazicii53 0:83277b73a1f8 37 #define MAX30102_LED2_PULSEAMP 0x0D;
zinnetyazicii53 0:83277b73a1f8 38 #define MAX30102_LED3_PULSEAMP 0x0E;
zinnetyazicii53 0:83277b73a1f8 39 #define MAX30102_LED_PROX_AMP 0x10;
zinnetyazicii53 0:83277b73a1f8 40 #define MAX30102_MULTILEDCONFIG1 0x11;
zinnetyazicii53 0:83277b73a1f8 41 #define MAX30102_MULTILEDCONFIG2 0x12;
zinnetyazicii53 0:83277b73a1f8 42
zinnetyazicii53 0:83277b73a1f8 43 // Die Temperature Registers
zinnetyazicii53 0:83277b73a1f8 44 #define MAX30102_DIETEMPINT 0x1F;
zinnetyazicii53 0:83277b73a1f8 45 #define MAX30102_DIETEMPFRAC 0x20;
zinnetyazicii53 0:83277b73a1f8 46 #define MAX30102_DIETEMPCONFIG 0x21;
zinnetyazicii53 0:83277b73a1f8 47
zinnetyazicii53 0:83277b73a1f8 48 // Proximity Function Registers
zinnetyazicii53 0:83277b73a1f8 49 #define MAX30102_PROXINTTHRESH 0x30;
zinnetyazicii53 0:83277b73a1f8 50
zinnetyazicii53 0:83277b73a1f8 51 // Part ID Registers
zinnetyazicii53 0:83277b73a1f8 52 #define MAX30102_REVISIONID 0xFE;
zinnetyazicii53 0:83277b73a1f8 53 #define MAX30102_PARTID 0xFF; // Should always be 0x15. Identical to MAX30102.
zinnetyazicii53 0:83277b73a1f8 54
zinnetyazicii53 0:83277b73a1f8 55 // MAX30102 Commands
zinnetyazicii53 0:83277b73a1f8 56 // Interrupt configuration (pg 13, 14)
zinnetyazicii53 0:83277b73a1f8 57 #define MAX30102_INT_A_FULL_MASK (byte)~0b10000000;
zinnetyazicii53 0:83277b73a1f8 58 #define MAX30102_INT_A_FULL_ENABLE 0x80;
zinnetyazicii53 0:83277b73a1f8 59 #define MAX30102_INT_A_FULL_DISABLE 0x00;
zinnetyazicii53 0:83277b73a1f8 60
zinnetyazicii53 0:83277b73a1f8 61 #define MAX30102_INT_DATA_RDY_MASK (byte)~0b01000000;
zinnetyazicii53 0:83277b73a1f8 62 #define MAX30102_INT_DATA_RDY_ENABLE 0x40;
zinnetyazicii53 0:83277b73a1f8 63 #define MAX30102_INT_DATA_RDY_DISABLE 0x00;
zinnetyazicii53 0:83277b73a1f8 64
zinnetyazicii53 0:83277b73a1f8 65 #define MAX30102_INT_ALC_OVF_MASK (byte)~0b00100000;
zinnetyazicii53 0:83277b73a1f8 66 #define MAX30102_INT_ALC_OVF_ENABLE 0x20;
zinnetyazicii53 0:83277b73a1f8 67 #define MAX30102_INT_ALC_OVF_DISABLE 0x00;
zinnetyazicii53 0:83277b73a1f8 68
zinnetyazicii53 0:83277b73a1f8 69 #define MAX30102_INT_PROX_INT_MASK (byte)~0b00010000;
zinnetyazicii53 0:83277b73a1f8 70 #define MAX30102_INT_PROX_INT_ENABLE 0x10;
zinnetyazicii53 0:83277b73a1f8 71 #define MAX30102_INT_PROX_INT_DISABLE 0x00;
zinnetyazicii53 0:83277b73a1f8 72
zinnetyazicii53 0:83277b73a1f8 73 #define MAX30102_INT_DIE_TEMP_RDY_MASK (byte)~0b00000010;
zinnetyazicii53 0:83277b73a1f8 74 #define MAX30102_INT_DIE_TEMP_RDY_ENABLE 0x02;
zinnetyazicii53 0:83277b73a1f8 75 #define MAX30102_INT_DIE_TEMP_RDY_DISABLE 0x00;
zinnetyazicii53 0:83277b73a1f8 76
zinnetyazicii53 0:83277b73a1f8 77 #define MAX30102_SAMPLEAVG_MASK (byte)~0b11100000;
zinnetyazicii53 0:83277b73a1f8 78 #define MAX30102_SAMPLEAVG_1 0x00;
zinnetyazicii53 0:83277b73a1f8 79 #define MAX30102_SAMPLEAVG_2 0x20;
zinnetyazicii53 0:83277b73a1f8 80 #define MAX30102_SAMPLEAVG_4 0x40;
zinnetyazicii53 0:83277b73a1f8 81 #define MAX30102_SAMPLEAVG_8 0x60;
zinnetyazicii53 0:83277b73a1f8 82 #define MAX30102_SAMPLEAVG_16 0x80;
zinnetyazicii53 0:83277b73a1f8 83 #define MAX30102_SAMPLEAVG_32 0xA0;
zinnetyazicii53 0:83277b73a1f8 84
zinnetyazicii53 0:83277b73a1f8 85 #define MAX30102_ROLLOVER_MASK 0xEF;
zinnetyazicii53 0:83277b73a1f8 86 #define MAX30102_ROLLOVER_ENABLE 0x10;
zinnetyazicii53 0:83277b73a1f8 87 #define MAX30102_ROLLOVER_DISABLE 0x00;
zinnetyazicii53 0:83277b73a1f8 88
zinnetyazicii53 0:83277b73a1f8 89 #define MAX30102_A_FULL_MASK 0xF0;
zinnetyazicii53 0:83277b73a1f8 90
zinnetyazicii53 0:83277b73a1f8 91 // Mode configuration commands (page 19)
zinnetyazicii53 0:83277b73a1f8 92 #define MAX30102_SHUTDOWN_MASK 0x7F;
zinnetyazicii53 0:83277b73a1f8 93 #define MAX30102_SHUTDOWN 0x80;
zinnetyazicii53 0:83277b73a1f8 94 #define MAX30102_WAKEUP 0x00;
zinnetyazicii53 0:83277b73a1f8 95
zinnetyazicii53 0:83277b73a1f8 96 #define MAX30102_RESET_MASK 0xBF;
zinnetyazicii53 0:83277b73a1f8 97 #define MAX30102_RESET 0x40;
zinnetyazicii53 0:83277b73a1f8 98
zinnetyazicii53 0:83277b73a1f8 99 #define MAX30102_MODE_MASK 0xF8;
zinnetyazicii53 0:83277b73a1f8 100 #define MAX30102_MODE_REDONLY 0x02;
zinnetyazicii53 0:83277b73a1f8 101 #define MAX30102_MODE_REDIRONLY 0x03;
zinnetyazicii53 0:83277b73a1f8 102 #define MAX30102_MODE_MULTILED 0x07;
zinnetyazicii53 0:83277b73a1f8 103
zinnetyazicii53 0:83277b73a1f8 104 // Particle sensing configuration commands (pgs 19-20)
zinnetyazicii53 0:83277b73a1f8 105 #define MAX30102_ADCRANGE_MASK 0x9F;
zinnetyazicii53 0:83277b73a1f8 106 #define MAX30102_ADCRANGE_2048 0x00;
zinnetyazicii53 0:83277b73a1f8 107 #define MAX30102_ADCRANGE_4096 0x20;
zinnetyazicii53 0:83277b73a1f8 108 #define MAX30102_ADCRANGE_8192 0x40;
zinnetyazicii53 0:83277b73a1f8 109 #define MAX30102_ADCRANGE_16384 0x60;
zinnetyazicii53 0:83277b73a1f8 110
zinnetyazicii53 0:83277b73a1f8 111 #define MAX30102_SAMPLERATE_MASK 0xE3;
zinnetyazicii53 0:83277b73a1f8 112 #define MAX30102_SAMPLERATE_50 0x00;
zinnetyazicii53 0:83277b73a1f8 113 #define MAX30102_SAMPLERATE_100 0x04;
zinnetyazicii53 0:83277b73a1f8 114 #define MAX30102_SAMPLERATE_200 0x08;
zinnetyazicii53 0:83277b73a1f8 115 #define MAX30102_SAMPLERATE_400 0x0C;
zinnetyazicii53 0:83277b73a1f8 116 #define MAX30102_SAMPLERATE_800 0x10;
zinnetyazicii53 0:83277b73a1f8 117 #define MAX30102_SAMPLERATE_1000 0x14;
zinnetyazicii53 0:83277b73a1f8 118 #define MAX30102_SAMPLERATE_1600 0x18;
zinnetyazicii53 0:83277b73a1f8 119 #define MAX30102_SAMPLERATE_3200 0x1C;
zinnetyazicii53 0:83277b73a1f8 120
zinnetyazicii53 0:83277b73a1f8 121 #define MAX30102_PULSEWIDTH_MASK 0xFC;
zinnetyazicii53 0:83277b73a1f8 122 #define MAX30102_PULSEWIDTH_69 0x00;
zinnetyazicii53 0:83277b73a1f8 123 #define MAX30102_PULSEWIDTH_118 0x01;
zinnetyazicii53 0:83277b73a1f8 124 #define MAX30102_PULSEWIDTH_215 0x02;
zinnetyazicii53 0:83277b73a1f8 125 #define MAX30102_PULSEWIDTH_411 0x03;
zinnetyazicii53 0:83277b73a1f8 126
zinnetyazicii53 0:83277b73a1f8 127 //Multi-LED Mode configuration (pg 22)
zinnetyazicii53 0:83277b73a1f8 128 #define MAX30102_SLOT1_MASK 0xF8;
zinnetyazicii53 0:83277b73a1f8 129 #define MAX30102_SLOT2_MASK 0x8F;
zinnetyazicii53 0:83277b73a1f8 130 #define MAX30102_SLOT3_MASK 0xF8;
zinnetyazicii53 0:83277b73a1f8 131 #define MAX30102_SLOT4_MASK 0x8F;
zinnetyazicii53 0:83277b73a1f8 132
zinnetyazicii53 0:83277b73a1f8 133 #define SLOT_NONE 0x00;
zinnetyazicii53 0:83277b73a1f8 134 #define SLOT_RED_LED 0x01;
zinnetyazicii53 0:83277b73a1f8 135 #define SLOT_IR_LED 0x02;
zinnetyazicii53 0:83277b73a1f8 136 #define SLOT_GREEN_LED 0x03;
zinnetyazicii53 0:83277b73a1f8 137 #define SLOT_NONE_PILOT 0x04;
zinnetyazicii53 0:83277b73a1f8 138 #define SLOT_RED_PILOT 0x05;
zinnetyazicii53 0:83277b73a1f8 139 #define SLOT_IR_PILOT 0x06;
zinnetyazicii53 0:83277b73a1f8 140 #define SLOT_GREEN_PILOT 0x07;
zinnetyazicii53 0:83277b73a1f8 141
zinnetyazicii53 0:83277b73a1f8 142
zinnetyazicii53 0:83277b73a1f8 143 #define MAX_30105_EXPECTEDPARTID 0x15;
zinnetyazicii53 0:83277b73a1f8 144
zinnetyazicii53 0:83277b73a1f8 145 bool begin(TwoWire &wirePort, uint32_t i2cSpeed, uint8_t i2caddr) {//??
zinnetyazicii53 0:83277b73a1f8 146
zinnetyazicii53 0:83277b73a1f8 147 _i2cPort = &wirePort; //Grab which port the user wants us to use
zinnetyazicii53 0:83277b73a1f8 148
zinnetyazicii53 0:83277b73a1f8 149 _i2cPort->begin();
zinnetyazicii53 0:83277b73a1f8 150 _i2cPort->setClock(i2cSpeed);
zinnetyazicii53 0:83277b73a1f8 151
zinnetyazicii53 0:83277b73a1f8 152 _i2caddr = i2caddr;
zinnetyazicii53 0:83277b73a1f8 153
zinnetyazicii53 0:83277b73a1f8 154 // Step 1: Initial Communication and Verification
zinnetyazicii53 0:83277b73a1f8 155 // Check that a MAX30102 is connected
zinnetyazicii53 0:83277b73a1f8 156 if (readPartID() != MAX_30105_EXPECTEDPARTID) {
zinnetyazicii53 0:83277b73a1f8 157 // Error -- Part ID read from MAX30102 does not match expected part ID.
zinnetyazicii53 0:83277b73a1f8 158 // This may mean there is a physical connectivity problem (broken wire, unpowered, etc).
zinnetyazicii53 0:83277b73a1f8 159 return false;
zinnetyazicii53 0:83277b73a1f8 160 }
zinnetyazicii53 0:83277b73a1f8 161
zinnetyazicii53 0:83277b73a1f8 162 // Populate revision ID
zinnetyazicii53 0:83277b73a1f8 163 readRevisionID();
zinnetyazicii53 0:83277b73a1f8 164
zinnetyazicii53 0:83277b73a1f8 165 return true;
zinnetyazicii53 0:83277b73a1f8 166 }
zinnetyazicii53 0:83277b73a1f8 167
zinnetyazicii53 0:83277b73a1f8 168 //
zinnetyazicii53 0:83277b73a1f8 169 // Configuration
zinnetyazicii53 0:83277b73a1f8 170 //
zinnetyazicii53 0:83277b73a1f8 171
zinnetyazicii53 0:83277b73a1f8 172 //Begin Interrupt configuration
zinnetyazicii53 0:83277b73a1f8 173 uint8_t MAX30102::getINT1(void) {
zinnetyazicii53 0:83277b73a1f8 174 return (readRegister8(_i2caddr, MAX30102_INTSTAT1));
zinnetyazicii53 0:83277b73a1f8 175 }
zinnetyazicii53 0:83277b73a1f8 176 uint8_t getINT2(void) {
zinnetyazicii53 0:83277b73a1f8 177 return (readRegister8(_i2caddr, MAX30102_INTSTAT2));
zinnetyazicii53 0:83277b73a1f8 178 }
zinnetyazicii53 0:83277b73a1f8 179
zinnetyazicii53 0:83277b73a1f8 180 void enableAFULL(void) {
zinnetyazicii53 0:83277b73a1f8 181 bitMask(MAX30102_INTENABLE1, MAX30102_INT_A_FULL_MASK, MAX30102_INT_A_FULL_ENABLE);
zinnetyazicii53 0:83277b73a1f8 182 }
zinnetyazicii53 0:83277b73a1f8 183 void disableAFULL(void) {
zinnetyazicii53 0:83277b73a1f8 184 bitMask(MAX30102_INTENABLE1, MAX30102_INT_A_FULL_MASK, MAX30102_INT_A_FULL_DISABLE);
zinnetyazicii53 0:83277b73a1f8 185 }
zinnetyazicii53 0:83277b73a1f8 186
zinnetyazicii53 0:83277b73a1f8 187 void enableDATARDY(void) {
zinnetyazicii53 0:83277b73a1f8 188 bitMask(MAX30102_INTENABLE1, MAX30102_INT_DATA_RDY_MASK, MAX30102_INT_DATA_RDY_ENABLE);
zinnetyazicii53 0:83277b73a1f8 189 }
zinnetyazicii53 0:83277b73a1f8 190 void disableDATARDY(void) {
zinnetyazicii53 0:83277b73a1f8 191 bitMask(MAX30102_INTENABLE1, MAX30102_INT_DATA_RDY_MASK, MAX30102_INT_DATA_RDY_DISABLE);
zinnetyazicii53 0:83277b73a1f8 192 }
zinnetyazicii53 0:83277b73a1f8 193
zinnetyazicii53 0:83277b73a1f8 194 void enableALCOVF(void) {
zinnetyazicii53 0:83277b73a1f8 195 bitMask(MAX30102_INTENABLE1, MAX30102_INT_ALC_OVF_MASK, MAX30102_INT_ALC_OVF_ENABLE);
zinnetyazicii53 0:83277b73a1f8 196 }
zinnetyazicii53 0:83277b73a1f8 197 void disableALCOVF(void) {
zinnetyazicii53 0:83277b73a1f8 198 bitMask(MAX30102_INTENABLE1, MAX30102_INT_ALC_OVF_MASK, MAX30102_INT_ALC_OVF_DISABLE);
zinnetyazicii53 0:83277b73a1f8 199 }
zinnetyazicii53 0:83277b73a1f8 200
zinnetyazicii53 0:83277b73a1f8 201 void enablePROXINT(void) {
zinnetyazicii53 0:83277b73a1f8 202 bitMask(MAX30102_INTENABLE1, MAX30102_INT_PROX_INT_MASK, MAX30102_INT_PROX_INT_ENABLE);
zinnetyazicii53 0:83277b73a1f8 203 }
zinnetyazicii53 0:83277b73a1f8 204 void disablePROXINT(void) {
zinnetyazicii53 0:83277b73a1f8 205 bitMask(MAX30102_INTENABLE1, MAX30102_INT_PROX_INT_MASK, MAX30102_INT_PROX_INT_DISABLE);
zinnetyazicii53 0:83277b73a1f8 206 }
zinnetyazicii53 0:83277b73a1f8 207
zinnetyazicii53 0:83277b73a1f8 208 void enableDIETEMPRDY(void) {
zinnetyazicii53 0:83277b73a1f8 209 bitMask(MAX30102_INTENABLE2, MAX30102_INT_DIE_TEMP_RDY_MASK, MAX30102_INT_DIE_TEMP_RDY_ENABLE);
zinnetyazicii53 0:83277b73a1f8 210 }
zinnetyazicii53 0:83277b73a1f8 211 void disableDIETEMPRDY(void) {
zinnetyazicii53 0:83277b73a1f8 212 bitMask(MAX30102_INTENABLE2, MAX30102_INT_DIE_TEMP_RDY_MASK, MAX30102_INT_DIE_TEMP_RDY_DISABLE);
zinnetyazicii53 0:83277b73a1f8 213 }
zinnetyazicii53 0:83277b73a1f8 214
zinnetyazicii53 0:83277b73a1f8 215 //End Interrupt configuration
zinnetyazicii53 0:83277b73a1f8 216
zinnetyazicii53 0:83277b73a1f8 217 void softReset(void) {
zinnetyazicii53 0:83277b73a1f8 218 bitMask(MAX30102_MODECONFIG, MAX30102_RESET_MASK, MAX30102_RESET);
zinnetyazicii53 0:83277b73a1f8 219
zinnetyazicii53 0:83277b73a1f8 220 // Poll for bit to clear, reset is then complete
zinnetyazicii53 0:83277b73a1f8 221 // Timeout after 100ms
zinnetyazicii53 0:83277b73a1f8 222 unsigned long startTime = millis();
zinnetyazicii53 0:83277b73a1f8 223 while (millis() - startTime < 100)
zinnetyazicii53 0:83277b73a1f8 224 {
zinnetyazicii53 0:83277b73a1f8 225 uint8_t response = readRegister8(_i2caddr, MAX30102_MODECONFIG);
zinnetyazicii53 0:83277b73a1f8 226 if ((response & MAX30102_RESET) == 0) break; //We're done!
zinnetyazicii53 0:83277b73a1f8 227 delay(1); //Let's not over burden the I2C bus
zinnetyazicii53 0:83277b73a1f8 228 }
zinnetyazicii53 0:83277b73a1f8 229 }
zinnetyazicii53 0:83277b73a1f8 230
zinnetyazicii53 0:83277b73a1f8 231 void shutDown(void) {
zinnetyazicii53 0:83277b73a1f8 232 // Put IC into low power mode (datasheet pg. 19)
zinnetyazicii53 0:83277b73a1f8 233 // During shutdown the IC will continue to respond to I2C commands but will
zinnetyazicii53 0:83277b73a1f8 234 // not update with or take new readings (such as temperature)
zinnetyazicii53 0:83277b73a1f8 235 bitMask(MAX30102_MODECONFIG, MAX30102_SHUTDOWN_MASK, MAX30102_SHUTDOWN);
zinnetyazicii53 0:83277b73a1f8 236 }
zinnetyazicii53 0:83277b73a1f8 237
zinnetyazicii53 0:83277b73a1f8 238 void wakeUp(void) {
zinnetyazicii53 0:83277b73a1f8 239 // Pull IC out of low power mode (datasheet pg. 19)
zinnetyazicii53 0:83277b73a1f8 240 bitMask(MAX30102_MODECONFIG, MAX30102_SHUTDOWN_MASK, MAX30102_WAKEUP);
zinnetyazicii53 0:83277b73a1f8 241 }
zinnetyazicii53 0:83277b73a1f8 242
zinnetyazicii53 0:83277b73a1f8 243 void setLEDMode(uint8_t mode) {
zinnetyazicii53 0:83277b73a1f8 244 // Set which LEDs are used for sampling -- Red only, RED+IR only, or custom.
zinnetyazicii53 0:83277b73a1f8 245 // See datasheet, page 19
zinnetyazicii53 0:83277b73a1f8 246 bitMask(MAX30102_MODECONFIG, MAX30102_MODE_MASK, mode);
zinnetyazicii53 0:83277b73a1f8 247 }
zinnetyazicii53 0:83277b73a1f8 248
zinnetyazicii53 0:83277b73a1f8 249 void setADCRange(uint8_t adcRange) {
zinnetyazicii53 0:83277b73a1f8 250 // adcRange: one of MAX30102_ADCRANGE_2048, _4096, _8192, _16384
zinnetyazicii53 0:83277b73a1f8 251 bitMask(MAX30102_PARTICLECONFIG, MAX30102_ADCRANGE_MASK, adcRange);
zinnetyazicii53 0:83277b73a1f8 252 }
zinnetyazicii53 0:83277b73a1f8 253
zinnetyazicii53 0:83277b73a1f8 254 void setSampleRate(uint8_t sampleRate) {
zinnetyazicii53 0:83277b73a1f8 255 // sampleRate: one of MAX30102_SAMPLERATE_50, _100, _200, _400, _800, _1000, _1600, _3200
zinnetyazicii53 0:83277b73a1f8 256 bitMask(MAX30102_PARTICLECONFIG, MAX30102_SAMPLERATE_MASK, sampleRate);
zinnetyazicii53 0:83277b73a1f8 257 }
zinnetyazicii53 0:83277b73a1f8 258
zinnetyazicii53 0:83277b73a1f8 259 void setPulseWidth(uint8_t pulseWidth) {
zinnetyazicii53 0:83277b73a1f8 260 // pulseWidth: one of MAX30102_PULSEWIDTH_69, _188, _215, _411
zinnetyazicii53 0:83277b73a1f8 261 bitMask(MAX30102_PARTICLECONFIG, MAX30102_PULSEWIDTH_MASK, pulseWidth);
zinnetyazicii53 0:83277b73a1f8 262 }
zinnetyazicii53 0:83277b73a1f8 263
zinnetyazicii53 0:83277b73a1f8 264 // NOTE: Amplitude values: 0x00 = 0mA, 0x7F = 25.4mA, 0xFF = 50mA (typical)
zinnetyazicii53 0:83277b73a1f8 265 // See datasheet, page 21
zinnetyazicii53 0:83277b73a1f8 266 void setPulseAmplitudeRed(uint8_t amplitude) {
zinnetyazicii53 0:83277b73a1f8 267 writeRegister8(_i2caddr, MAX30102_LED1_PULSEAMP, amplitude);
zinnetyazicii53 0:83277b73a1f8 268 }
zinnetyazicii53 0:83277b73a1f8 269
zinnetyazicii53 0:83277b73a1f8 270 void setPulseAmplitudeIR(uint8_t amplitude) {
zinnetyazicii53 0:83277b73a1f8 271 writeRegister8(_i2caddr, MAX30102_LED2_PULSEAMP, amplitude);
zinnetyazicii53 0:83277b73a1f8 272 }
zinnetyazicii53 0:83277b73a1f8 273
zinnetyazicii53 0:83277b73a1f8 274 void setPulseAmplitudeGreen(uint8_t amplitude) {
zinnetyazicii53 0:83277b73a1f8 275 writeRegister8(_i2caddr, MAX30102_LED3_PULSEAMP, amplitude);
zinnetyazicii53 0:83277b73a1f8 276 }
zinnetyazicii53 0:83277b73a1f8 277
zinnetyazicii53 0:83277b73a1f8 278 void setPulseAmplitudeProximity(uint8_t amplitude) {
zinnetyazicii53 0:83277b73a1f8 279 writeRegister8(_i2caddr, MAX30102_LED_PROX_AMP, amplitude);
zinnetyazicii53 0:83277b73a1f8 280 }
zinnetyazicii53 0:83277b73a1f8 281
zinnetyazicii53 0:83277b73a1f8 282 void setProximityThreshold(uint8_t threshMSB) {
zinnetyazicii53 0:83277b73a1f8 283 // Set the IR ADC count that will trigger the beginning of particle-sensing mode.
zinnetyazicii53 0:83277b73a1f8 284 // The threshMSB signifies only the 8 most significant-bits of the ADC count.
zinnetyazicii53 0:83277b73a1f8 285 // See datasheet, page 24.
zinnetyazicii53 0:83277b73a1f8 286 writeRegister8(_i2caddr, MAX30102_PROXINTTHRESH, threshMSB);
zinnetyazicii53 0:83277b73a1f8 287 }
zinnetyazicii53 0:83277b73a1f8 288
zinnetyazicii53 0:83277b73a1f8 289 //Given a slot number assign a thing to it
zinnetyazicii53 0:83277b73a1f8 290 //Devices are SLOT_RED_LED or SLOT_RED_PILOT (proximity)
zinnetyazicii53 0:83277b73a1f8 291 //Assigning a SLOT_RED_LED will pulse LED
zinnetyazicii53 0:83277b73a1f8 292 //Assigning a SLOT_RED_PILOT will ??
zinnetyazicii53 0:83277b73a1f8 293 void enableSlot(uint8_t slotNumber, uint8_t device) {
zinnetyazicii53 0:83277b73a1f8 294
zinnetyazicii53 0:83277b73a1f8 295 uint8_t originalContents;
zinnetyazicii53 0:83277b73a1f8 296
zinnetyazicii53 0:83277b73a1f8 297 switch (slotNumber) {
zinnetyazicii53 0:83277b73a1f8 298 case (1):
zinnetyazicii53 0:83277b73a1f8 299 bitMask(MAX30102_MULTILEDCONFIG1, MAX30102_SLOT1_MASK, device);
zinnetyazicii53 0:83277b73a1f8 300 break;
zinnetyazicii53 0:83277b73a1f8 301 case (2):
zinnetyazicii53 0:83277b73a1f8 302 bitMask(MAX30102_MULTILEDCONFIG1, MAX30102_SLOT2_MASK, device << 4);
zinnetyazicii53 0:83277b73a1f8 303 break;
zinnetyazicii53 0:83277b73a1f8 304 case (3):
zinnetyazicii53 0:83277b73a1f8 305 bitMask(MAX30102_MULTILEDCONFIG2, MAX30102_SLOT3_MASK, device);
zinnetyazicii53 0:83277b73a1f8 306 break;
zinnetyazicii53 0:83277b73a1f8 307 case (4):
zinnetyazicii53 0:83277b73a1f8 308 bitMask(MAX30102_MULTILEDCONFIG2, MAX30102_SLOT4_MASK, device << 4);
zinnetyazicii53 0:83277b73a1f8 309 break;
zinnetyazicii53 0:83277b73a1f8 310 default:
zinnetyazicii53 0:83277b73a1f8 311 //Shouldn't be here!
zinnetyazicii53 0:83277b73a1f8 312 break;
zinnetyazicii53 0:83277b73a1f8 313 }
zinnetyazicii53 0:83277b73a1f8 314 }
zinnetyazicii53 0:83277b73a1f8 315
zinnetyazicii53 0:83277b73a1f8 316 //Clears all slot assignments
zinnetyazicii53 0:83277b73a1f8 317 void disableSlots(void) {
zinnetyazicii53 0:83277b73a1f8 318 writeRegister8(_i2caddr, MAX30102_MULTILEDCONFIG1, 0);
zinnetyazicii53 0:83277b73a1f8 319 writeRegister8(_i2caddr, MAX30102_MULTILEDCONFIG2, 0);
zinnetyazicii53 0:83277b73a1f8 320 }
zinnetyazicii53 0:83277b73a1f8 321
zinnetyazicii53 0:83277b73a1f8 322 //
zinnetyazicii53 0:83277b73a1f8 323 // FIFO Configuration
zinnetyazicii53 0:83277b73a1f8 324 //
zinnetyazicii53 0:83277b73a1f8 325
zinnetyazicii53 0:83277b73a1f8 326 //Set sample average (Table 3, Page 18)
zinnetyazicii53 0:83277b73a1f8 327 void setFIFOAverage(uint8_t numberOfSamples) {
zinnetyazicii53 0:83277b73a1f8 328 bitMask(MAX30102_FIFOCONFIG, MAX30102_SAMPLEAVG_MASK, numberOfSamples);
zinnetyazicii53 0:83277b73a1f8 329 }
zinnetyazicii53 0:83277b73a1f8 330
zinnetyazicii53 0:83277b73a1f8 331 //Resets all points to start in a known state
zinnetyazicii53 0:83277b73a1f8 332 //Page 15 recommends clearing FIFO before beginning a read
zinnetyazicii53 0:83277b73a1f8 333 void clearFIFO(void) {
zinnetyazicii53 0:83277b73a1f8 334 writeRegister8(_i2caddr, MAX30102_FIFOWRITEPTR, 0);
zinnetyazicii53 0:83277b73a1f8 335 writeRegister8(_i2caddr, MAX30102_FIFOOVERFLOW, 0);
zinnetyazicii53 0:83277b73a1f8 336 writeRegister8(_i2caddr, MAX30102_FIFOREADPTR, 0);
zinnetyazicii53 0:83277b73a1f8 337 }
zinnetyazicii53 0:83277b73a1f8 338
zinnetyazicii53 0:83277b73a1f8 339 //Enable roll over if FIFO over flows
zinnetyazicii53 0:83277b73a1f8 340 void enableFIFORollover(void) {
zinnetyazicii53 0:83277b73a1f8 341 bitMask(MAX30102_FIFOCONFIG, MAX30102_ROLLOVER_MASK, MAX30102_ROLLOVER_ENABLE);
zinnetyazicii53 0:83277b73a1f8 342 }
zinnetyazicii53 0:83277b73a1f8 343
zinnetyazicii53 0:83277b73a1f8 344 //Disable roll over if FIFO over flows
zinnetyazicii53 0:83277b73a1f8 345 void disableFIFORollover(void) {
zinnetyazicii53 0:83277b73a1f8 346 bitMask(MAX30102_FIFOCONFIG, MAX30102_ROLLOVER_MASK, MAX30102_ROLLOVER_DISABLE);
zinnetyazicii53 0:83277b73a1f8 347 }
zinnetyazicii53 0:83277b73a1f8 348
zinnetyazicii53 0:83277b73a1f8 349 //Set number of samples to trigger the almost full interrupt (Page 18)
zinnetyazicii53 0:83277b73a1f8 350 //Power on default is 32 samples
zinnetyazicii53 0:83277b73a1f8 351 //Note it is reverse: 0x00 is 32 samples, 0x0F is 17 samples
zinnetyazicii53 0:83277b73a1f8 352 void setFIFOAlmostFull(uint8_t numberOfSamples) {
zinnetyazicii53 0:83277b73a1f8 353 bitMask(MAX30102_FIFOCONFIG, MAX30102_A_FULL_MASK, numberOfSamples);
zinnetyazicii53 0:83277b73a1f8 354 }
zinnetyazicii53 0:83277b73a1f8 355
zinnetyazicii53 0:83277b73a1f8 356 //Read the FIFO Write Pointer
zinnetyazicii53 0:83277b73a1f8 357 uint8_t getWritePointer(void) {
zinnetyazicii53 0:83277b73a1f8 358 return (readRegister8(_i2caddr, MAX30102_FIFOWRITEPTR));
zinnetyazicii53 0:83277b73a1f8 359 }
zinnetyazicii53 0:83277b73a1f8 360
zinnetyazicii53 0:83277b73a1f8 361 //Read the FIFO Read Pointer
zinnetyazicii53 0:83277b73a1f8 362 uint8_t getReadPointer(void) {
zinnetyazicii53 0:83277b73a1f8 363 return (readRegister8(_i2caddr, MAX30102_FIFOREADPTR));
zinnetyazicii53 0:83277b73a1f8 364 }
zinnetyazicii53 0:83277b73a1f8 365
zinnetyazicii53 0:83277b73a1f8 366
zinnetyazicii53 0:83277b73a1f8 367 // Die Temperature
zinnetyazicii53 0:83277b73a1f8 368 // Returns temp in C
zinnetyazicii53 0:83277b73a1f8 369 float readTemperature() {
zinnetyazicii53 0:83277b73a1f8 370
zinnetyazicii53 0:83277b73a1f8 371 //DIE_TEMP_RDY interrupt must be enabled
zinnetyazicii53 0:83277b73a1f8 372 //See issue 19: https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/issues/19
zinnetyazicii53 0:83277b73a1f8 373
zinnetyazicii53 0:83277b73a1f8 374 // Step 1: Config die temperature register to take 1 temperature sample
zinnetyazicii53 0:83277b73a1f8 375 writeRegister8(_i2caddr, MAX30102_DIETEMPCONFIG, 0x01);
zinnetyazicii53 0:83277b73a1f8 376
zinnetyazicii53 0:83277b73a1f8 377 // Poll for bit to clear, reading is then complete
zinnetyazicii53 0:83277b73a1f8 378 // Timeout after 100ms
zinnetyazicii53 0:83277b73a1f8 379 unsigned long startTime = millis();
zinnetyazicii53 0:83277b73a1f8 380 while (millis() - startTime < 100)
zinnetyazicii53 0:83277b73a1f8 381 {
zinnetyazicii53 0:83277b73a1f8 382 //uint8_t response = readRegister8(_i2caddr, MAX30102_DIETEMPCONFIG); //Original way
zinnetyazicii53 0:83277b73a1f8 383 //if ((response & 0x01) == 0) break; //We're done!
zinnetyazicii53 0:83277b73a1f8 384
zinnetyazicii53 0:83277b73a1f8 385 //Check to see if DIE_TEMP_RDY interrupt is set
zinnetyazicii53 0:83277b73a1f8 386 uint8_t response = readRegister8(_i2caddr, MAX30102_INTSTAT2);
zinnetyazicii53 0:83277b73a1f8 387 if ((response & MAX30102_INT_DIE_TEMP_RDY_ENABLE) > 0) break; //We're done!
zinnetyazicii53 0:83277b73a1f8 388 delay(1); //Let's not over burden the I2C bus
zinnetyazicii53 0:83277b73a1f8 389 }
zinnetyazicii53 0:83277b73a1f8 390 //TODO How do we want to fail? With what type of error?
zinnetyazicii53 0:83277b73a1f8 391 //? if(millis() - startTime >= 100) return(-999.0);
zinnetyazicii53 0:83277b73a1f8 392
zinnetyazicii53 0:83277b73a1f8 393 // Step 2: Read die temperature register (integer)
zinnetyazicii53 0:83277b73a1f8 394 int8_t tempInt = readRegister8(_i2caddr, MAX30102_DIETEMPINT);
zinnetyazicii53 0:83277b73a1f8 395 uint8_t tempFrac = readRegister8(_i2caddr, MAX30102_DIETEMPFRAC); //Causes the clearing of the DIE_TEMP_RDY interrupt
zinnetyazicii53 0:83277b73a1f8 396
zinnetyazicii53 0:83277b73a1f8 397 // Step 3: Calculate temperature (datasheet pg. 23)
zinnetyazicii53 0:83277b73a1f8 398 return (float)tempInt + ((float)tempFrac * 0.0625);
zinnetyazicii53 0:83277b73a1f8 399 }
zinnetyazicii53 0:83277b73a1f8 400
zinnetyazicii53 0:83277b73a1f8 401 // Returns die temp in F
zinnetyazicii53 0:83277b73a1f8 402 float readTemperatureF() {
zinnetyazicii53 0:83277b73a1f8 403 float temp = readTemperature();
zinnetyazicii53 0:83277b73a1f8 404
zinnetyazicii53 0:83277b73a1f8 405 if (temp != -999.0) temp = temp * 1.8 + 32.0;
zinnetyazicii53 0:83277b73a1f8 406
zinnetyazicii53 0:83277b73a1f8 407 return (temp);
zinnetyazicii53 0:83277b73a1f8 408 }
zinnetyazicii53 0:83277b73a1f8 409
zinnetyazicii53 0:83277b73a1f8 410 // Set the PROX_INT_THRESHold
zinnetyazicii53 0:83277b73a1f8 411 void setPROXINTTHRESH(uint8_t val) {
zinnetyazicii53 0:83277b73a1f8 412 writeRegister8(_i2caddr, MAX30102_PROXINTTHRESH, val);
zinnetyazicii53 0:83277b73a1f8 413 }
zinnetyazicii53 0:83277b73a1f8 414
zinnetyazicii53 0:83277b73a1f8 415
zinnetyazicii53 0:83277b73a1f8 416 //
zinnetyazicii53 0:83277b73a1f8 417 // Device ID and Revision
zinnetyazicii53 0:83277b73a1f8 418 //
zinnetyazicii53 0:83277b73a1f8 419 uint8_t readPartID() {
zinnetyazicii53 0:83277b73a1f8 420 return readRegister8(_i2caddr, MAX30102_PARTID);
zinnetyazicii53 0:83277b73a1f8 421 }
zinnetyazicii53 0:83277b73a1f8 422
zinnetyazicii53 0:83277b73a1f8 423 void readRevisionID() {
zinnetyazicii53 0:83277b73a1f8 424 revisionID = readRegister8(_i2caddr, MAX30102_REVISIONID);
zinnetyazicii53 0:83277b73a1f8 425 }
zinnetyazicii53 0:83277b73a1f8 426
zinnetyazicii53 0:83277b73a1f8 427 uint8_t getRevisionID() {
zinnetyazicii53 0:83277b73a1f8 428 return revisionID;
zinnetyazicii53 0:83277b73a1f8 429 }
zinnetyazicii53 0:83277b73a1f8 430
zinnetyazicii53 0:83277b73a1f8 431
zinnetyazicii53 0:83277b73a1f8 432 //Setup the sensor
zinnetyazicii53 0:83277b73a1f8 433 //The MAX30102 has many settings. By default we select:
zinnetyazicii53 0:83277b73a1f8 434 // Sample Average = 4
zinnetyazicii53 0:83277b73a1f8 435 // Mode = MultiLED
zinnetyazicii53 0:83277b73a1f8 436 // ADC Range = 16384 (62.5pA per LSB)
zinnetyazicii53 0:83277b73a1f8 437 // Sample rate = 50
zinnetyazicii53 0:83277b73a1f8 438 //Use the default setup if you are just getting started with the MAX30102 sensor
zinnetyazicii53 0:83277b73a1f8 439 void setup(byte powerLevel, byte sampleAverage, byte ledMode, int sampleRate, int pulseWidth, int adcRange) {
zinnetyazicii53 0:83277b73a1f8 440 softReset(); //Reset all configuration, threshold, and data registers to POR values
zinnetyazicii53 0:83277b73a1f8 441
zinnetyazicii53 0:83277b73a1f8 442 //FIFO Configuration
zinnetyazicii53 0:83277b73a1f8 443 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 444 //The chip will average multiple samples of same type together if you wish
zinnetyazicii53 0:83277b73a1f8 445 if (sampleAverage == 1) setFIFOAverage(MAX30102_SAMPLEAVG_1); //No averaging per FIFO record
zinnetyazicii53 0:83277b73a1f8 446 else if (sampleAverage == 2) setFIFOAverage(MAX30102_SAMPLEAVG_2);
zinnetyazicii53 0:83277b73a1f8 447 else if (sampleAverage == 4) setFIFOAverage(MAX30102_SAMPLEAVG_4);
zinnetyazicii53 0:83277b73a1f8 448 else if (sampleAverage == 8) setFIFOAverage(MAX30102_SAMPLEAVG_8);
zinnetyazicii53 0:83277b73a1f8 449 else if (sampleAverage == 16) setFIFOAverage(MAX30102_SAMPLEAVG_16);
zinnetyazicii53 0:83277b73a1f8 450 else if (sampleAverage == 32) setFIFOAverage(MAX30102_SAMPLEAVG_32);
zinnetyazicii53 0:83277b73a1f8 451 else setFIFOAverage(MAX30102_SAMPLEAVG_4);
zinnetyazicii53 0:83277b73a1f8 452
zinnetyazicii53 0:83277b73a1f8 453 //setFIFOAlmostFull(2); //Set to 30 samples to trigger an 'Almost Full' interrupt
zinnetyazicii53 0:83277b73a1f8 454 enableFIFORollover(); //Allow FIFO to wrap/roll over
zinnetyazicii53 0:83277b73a1f8 455 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 456
zinnetyazicii53 0:83277b73a1f8 457 //Mode Configuration
zinnetyazicii53 0:83277b73a1f8 458 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 459 if (ledMode == 3) setLEDMode(MAX30102_MODE_MULTILED); //Watch all three LED channels
zinnetyazicii53 0:83277b73a1f8 460 else if (ledMode == 2) setLEDMode(MAX30102_MODE_REDIRONLY); //Red and IR
zinnetyazicii53 0:83277b73a1f8 461 else setLEDMode(MAX30102_MODE_REDONLY); //Red only
zinnetyazicii53 0:83277b73a1f8 462 activeLEDs = ledMode; //Used to control how many bytes to read from FIFO buffer
zinnetyazicii53 0:83277b73a1f8 463 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 464
zinnetyazicii53 0:83277b73a1f8 465 //Particle Sensing Configuration
zinnetyazicii53 0:83277b73a1f8 466 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 467 if(adcRange < 4096) setADCRange(MAX30102_ADCRANGE_2048); //7.81pA per LSB
zinnetyazicii53 0:83277b73a1f8 468 else if(adcRange < 8192) setADCRange(MAX30102_ADCRANGE_4096); //15.63pA per LSB
zinnetyazicii53 0:83277b73a1f8 469 else if(adcRange < 16384) setADCRange(MAX30102_ADCRANGE_8192); //31.25pA per LSB
zinnetyazicii53 0:83277b73a1f8 470 else if(adcRange == 16384) setADCRange(MAX30102_ADCRANGE_16384); //62.5pA per LSB
zinnetyazicii53 0:83277b73a1f8 471 else setADCRange(MAX30102_ADCRANGE_2048);
zinnetyazicii53 0:83277b73a1f8 472
zinnetyazicii53 0:83277b73a1f8 473 if (sampleRate < 100) setSampleRate(MAX30102_SAMPLERATE_50); //Take 50 samples per second
zinnetyazicii53 0:83277b73a1f8 474 else if (sampleRate < 200) setSampleRate(MAX30102_SAMPLERATE_100);
zinnetyazicii53 0:83277b73a1f8 475 else if (sampleRate < 400) setSampleRate(MAX30102_SAMPLERATE_200);
zinnetyazicii53 0:83277b73a1f8 476 else if (sampleRate < 800) setSampleRate(MAX30102_SAMPLERATE_400);
zinnetyazicii53 0:83277b73a1f8 477 else if (sampleRate < 1000) setSampleRate(MAX30102_SAMPLERATE_800);
zinnetyazicii53 0:83277b73a1f8 478 else if (sampleRate < 1600) setSampleRate(MAX30102_SAMPLERATE_1000);
zinnetyazicii53 0:83277b73a1f8 479 else if (sampleRate < 3200) setSampleRate(MAX30102_SAMPLERATE_1600);
zinnetyazicii53 0:83277b73a1f8 480 else if (sampleRate == 3200) setSampleRate(MAX30102_SAMPLERATE_3200);
zinnetyazicii53 0:83277b73a1f8 481 else setSampleRate(MAX30102_SAMPLERATE_50);
zinnetyazicii53 0:83277b73a1f8 482
zinnetyazicii53 0:83277b73a1f8 483 //The longer the pulse width the longer range of detection you'll have
zinnetyazicii53 0:83277b73a1f8 484 //At 69us and 0.4mA it's about 2 inches
zinnetyazicii53 0:83277b73a1f8 485 //At 411us and 0.4mA it's about 6 inches
zinnetyazicii53 0:83277b73a1f8 486 if (pulseWidth < 118) setPulseWidth(MAX30102_PULSEWIDTH_69); //Page 26, Gets us 15 bit resolution
zinnetyazicii53 0:83277b73a1f8 487 else if (pulseWidth < 215) setPulseWidth(MAX30102_PULSEWIDTH_118); //16 bit resolution
zinnetyazicii53 0:83277b73a1f8 488 else if (pulseWidth < 411) setPulseWidth(MAX30102_PULSEWIDTH_215); //17 bit resolution
zinnetyazicii53 0:83277b73a1f8 489 else if (pulseWidth == 411) setPulseWidth(MAX30102_PULSEWIDTH_411); //18 bit resolution
zinnetyazicii53 0:83277b73a1f8 490 else setPulseWidth(MAX30102_PULSEWIDTH_69);
zinnetyazicii53 0:83277b73a1f8 491 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 492
zinnetyazicii53 0:83277b73a1f8 493 //LED Pulse Amplitude Configuration
zinnetyazicii53 0:83277b73a1f8 494 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 495 //Default is 0x1F which gets us 6.4mA
zinnetyazicii53 0:83277b73a1f8 496 //powerLevel = 0x02, 0.4mA - Presence detection of ~4 inch
zinnetyazicii53 0:83277b73a1f8 497 //powerLevel = 0x1F, 6.4mA - Presence detection of ~8 inch
zinnetyazicii53 0:83277b73a1f8 498 //powerLevel = 0x7F, 25.4mA - Presence detection of ~8 inch
zinnetyazicii53 0:83277b73a1f8 499 //powerLevel = 0xFF, 50.0mA - Presence detection of ~12 inch
zinnetyazicii53 0:83277b73a1f8 500
zinnetyazicii53 0:83277b73a1f8 501 setPulseAmplitudeRed(powerLevel);
zinnetyazicii53 0:83277b73a1f8 502 setPulseAmplitudeIR(powerLevel);
zinnetyazicii53 0:83277b73a1f8 503 setPulseAmplitudeGreen(powerLevel);
zinnetyazicii53 0:83277b73a1f8 504 setPulseAmplitudeProximity(powerLevel);
zinnetyazicii53 0:83277b73a1f8 505 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 506
zinnetyazicii53 0:83277b73a1f8 507 //Multi-LED Mode Configuration, Enable the reading of the three LEDs
zinnetyazicii53 0:83277b73a1f8 508 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 509 enableSlot(1, SLOT_RED_LED);
zinnetyazicii53 0:83277b73a1f8 510 if (ledMode > 1) enableSlot(2, SLOT_IR_LED);
zinnetyazicii53 0:83277b73a1f8 511 if (ledMode > 2) enableSlot(3, SLOT_GREEN_LED);
zinnetyazicii53 0:83277b73a1f8 512 //enableSlot(1, SLOT_RED_PILOT);
zinnetyazicii53 0:83277b73a1f8 513 //enableSlot(2, SLOT_IR_PILOT);
zinnetyazicii53 0:83277b73a1f8 514 //enableSlot(3, SLOT_GREEN_PILOT);
zinnetyazicii53 0:83277b73a1f8 515 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
zinnetyazicii53 0:83277b73a1f8 516
zinnetyazicii53 0:83277b73a1f8 517 clearFIFO(); //Reset the FIFO before we begin checking the sensor
zinnetyazicii53 0:83277b73a1f8 518 }
zinnetyazicii53 0:83277b73a1f8 519
zinnetyazicii53 0:83277b73a1f8 520 //
zinnetyazicii53 0:83277b73a1f8 521 // Data Collection
zinnetyazicii53 0:83277b73a1f8 522 //
zinnetyazicii53 0:83277b73a1f8 523
zinnetyazicii53 0:83277b73a1f8 524 //Tell caller how many samples are available
zinnetyazicii53 0:83277b73a1f8 525 uint8_t available(void)
zinnetyazicii53 0:83277b73a1f8 526 {
zinnetyazicii53 0:83277b73a1f8 527 int8_t numberOfSamples = sense.head - sense.tail;
zinnetyazicii53 0:83277b73a1f8 528 if (numberOfSamples < 0) numberOfSamples += STORAGE_SIZE;
zinnetyazicii53 0:83277b73a1f8 529
zinnetyazicii53 0:83277b73a1f8 530 return (numberOfSamples);
zinnetyazicii53 0:83277b73a1f8 531 }
zinnetyazicii53 0:83277b73a1f8 532
zinnetyazicii53 0:83277b73a1f8 533 //Report the most recent red value
zinnetyazicii53 0:83277b73a1f8 534 uint32_t getRed(void)
zinnetyazicii53 0:83277b73a1f8 535 {
zinnetyazicii53 0:83277b73a1f8 536 //Check the sensor for new data for 250ms
zinnetyazicii53 0:83277b73a1f8 537 if(safeCheck(250))
zinnetyazicii53 0:83277b73a1f8 538 return (sense.red[sense.head]);
zinnetyazicii53 0:83277b73a1f8 539 else
zinnetyazicii53 0:83277b73a1f8 540 return(0); //Sensor failed to find new data
zinnetyazicii53 0:83277b73a1f8 541 }
zinnetyazicii53 0:83277b73a1f8 542
zinnetyazicii53 0:83277b73a1f8 543 //Report the most recent IR value
zinnetyazicii53 0:83277b73a1f8 544 uint32_t getIR(void)
zinnetyazicii53 0:83277b73a1f8 545 {
zinnetyazicii53 0:83277b73a1f8 546 //Check the sensor for new data for 250ms
zinnetyazicii53 0:83277b73a1f8 547 if(safeCheck(250))
zinnetyazicii53 0:83277b73a1f8 548 return (sense.IR[sense.head]);
zinnetyazicii53 0:83277b73a1f8 549 else
zinnetyazicii53 0:83277b73a1f8 550 return(0); //Sensor failed to find new data
zinnetyazicii53 0:83277b73a1f8 551 }
zinnetyazicii53 0:83277b73a1f8 552
zinnetyazicii53 0:83277b73a1f8 553 //Report the most recent Green value
zinnetyazicii53 0:83277b73a1f8 554 uint32_t getGreen(void)
zinnetyazicii53 0:83277b73a1f8 555 {
zinnetyazicii53 0:83277b73a1f8 556 //Check the sensor for new data for 250ms
zinnetyazicii53 0:83277b73a1f8 557 if(safeCheck(250))
zinnetyazicii53 0:83277b73a1f8 558 return (sense.green[sense.head]);
zinnetyazicii53 0:83277b73a1f8 559 else
zinnetyazicii53 0:83277b73a1f8 560 return(0); //Sensor failed to find new data
zinnetyazicii53 0:83277b73a1f8 561 }
zinnetyazicii53 0:83277b73a1f8 562
zinnetyazicii53 0:83277b73a1f8 563 //Report the next Red value in the FIFO
zinnetyazicii53 0:83277b73a1f8 564 uint32_t getFIFORed(void)
zinnetyazicii53 0:83277b73a1f8 565 {
zinnetyazicii53 0:83277b73a1f8 566 return (sense.red[sense.tail]);
zinnetyazicii53 0:83277b73a1f8 567 }
zinnetyazicii53 0:83277b73a1f8 568
zinnetyazicii53 0:83277b73a1f8 569 //Report the next IR value in the FIFO
zinnetyazicii53 0:83277b73a1f8 570 uint32_t getFIFOIR(void)
zinnetyazicii53 0:83277b73a1f8 571 {
zinnetyazicii53 0:83277b73a1f8 572 return (sense.IR[sense.tail]);
zinnetyazicii53 0:83277b73a1f8 573 }
zinnetyazicii53 0:83277b73a1f8 574
zinnetyazicii53 0:83277b73a1f8 575 //Report the next Green value in the FIFO
zinnetyazicii53 0:83277b73a1f8 576 uint32_t getFIFOGreen(void)
zinnetyazicii53 0:83277b73a1f8 577 {
zinnetyazicii53 0:83277b73a1f8 578 return (sense.green[sense.tail]);
zinnetyazicii53 0:83277b73a1f8 579 }
zinnetyazicii53 0:83277b73a1f8 580
zinnetyazicii53 0:83277b73a1f8 581 //Advance the tail
zinnetyazicii53 0:83277b73a1f8 582 void nextSample(void)
zinnetyazicii53 0:83277b73a1f8 583 {
zinnetyazicii53 0:83277b73a1f8 584 if(available()) //Only advance the tail if new data is available
zinnetyazicii53 0:83277b73a1f8 585 {
zinnetyazicii53 0:83277b73a1f8 586 sense.tail++;
zinnetyazicii53 0:83277b73a1f8 587 sense.tail %= STORAGE_SIZE; //Wrap condition
zinnetyazicii53 0:83277b73a1f8 588 }
zinnetyazicii53 0:83277b73a1f8 589 }
zinnetyazicii53 0:83277b73a1f8 590
zinnetyazicii53 0:83277b73a1f8 591 //Polls the sensor for new data
zinnetyazicii53 0:83277b73a1f8 592 //Call regularly
zinnetyazicii53 0:83277b73a1f8 593 //If new data is available, it updates the head and tail in the main struct
zinnetyazicii53 0:83277b73a1f8 594 //Returns number of new samples obtained
zinnetyazicii53 0:83277b73a1f8 595 uint16_t check(void)
zinnetyazicii53 0:83277b73a1f8 596 {
zinnetyazicii53 0:83277b73a1f8 597 //Read register FIDO_DATA in (3-byte * number of active LED) chunks
zinnetyazicii53 0:83277b73a1f8 598 //Until FIFO_RD_PTR = FIFO_WR_PTR
zinnetyazicii53 0:83277b73a1f8 599
zinnetyazicii53 0:83277b73a1f8 600 byte readPointer = getReadPointer();
zinnetyazicii53 0:83277b73a1f8 601 byte writePointer = getWritePointer();
zinnetyazicii53 0:83277b73a1f8 602
zinnetyazicii53 0:83277b73a1f8 603 int numberOfSamples = 0;
zinnetyazicii53 0:83277b73a1f8 604
zinnetyazicii53 0:83277b73a1f8 605 //Do we have new data?
zinnetyazicii53 0:83277b73a1f8 606 if (readPointer != writePointer)
zinnetyazicii53 0:83277b73a1f8 607 {
zinnetyazicii53 0:83277b73a1f8 608 //Calculate the number of readings we need to get from sensor
zinnetyazicii53 0:83277b73a1f8 609 numberOfSamples = writePointer - readPointer;
zinnetyazicii53 0:83277b73a1f8 610 if (numberOfSamples < 0) numberOfSamples += 32; //Wrap condition
zinnetyazicii53 0:83277b73a1f8 611
zinnetyazicii53 0:83277b73a1f8 612 //We now have the number of readings, now calc bytes to read
zinnetyazicii53 0:83277b73a1f8 613 //For this example we are just doing Red and IR (3 bytes each)
zinnetyazicii53 0:83277b73a1f8 614 int bytesLeftToRead = numberOfSamples * activeLEDs * 3;
zinnetyazicii53 0:83277b73a1f8 615
zinnetyazicii53 0:83277b73a1f8 616 //Get ready to read a burst of data from the FIFO register
zinnetyazicii53 0:83277b73a1f8 617 _i2cPort->beginTransmission(MAX30102_ADDRESS);
zinnetyazicii53 0:83277b73a1f8 618 _i2cPort->write(MAX30102_FIFODATA);
zinnetyazicii53 0:83277b73a1f8 619 _i2cPort->endTransmission();
zinnetyazicii53 0:83277b73a1f8 620
zinnetyazicii53 0:83277b73a1f8 621 //We may need to read as many as 288 bytes so we read in blocks no larger than I2C_BUFFER_LENGTH
zinnetyazicii53 0:83277b73a1f8 622 //I2C_BUFFER_LENGTH changes based on the platform. 64 bytes for SAMD21, 32 bytes for Uno.
zinnetyazicii53 0:83277b73a1f8 623 //Wire.requestFrom() is limited to BUFFER_LENGTH which is 32 on the Uno
zinnetyazicii53 0:83277b73a1f8 624 while (bytesLeftToRead > 0)
zinnetyazicii53 0:83277b73a1f8 625 {
zinnetyazicii53 0:83277b73a1f8 626 int toGet = bytesLeftToRead;
zinnetyazicii53 0:83277b73a1f8 627 if (toGet > I2C_BUFFER_LENGTH)
zinnetyazicii53 0:83277b73a1f8 628 {
zinnetyazicii53 0:83277b73a1f8 629 //If toGet is 32 this is bad because we read 6 bytes (Red+IR * 3 = 6) at a time
zinnetyazicii53 0:83277b73a1f8 630 //32 % 6 = 2 left over. We don't want to request 32 bytes, we want to request 30.
zinnetyazicii53 0:83277b73a1f8 631 //32 % 9 (Red+IR+GREEN) = 5 left over. We want to request 27.
zinnetyazicii53 0:83277b73a1f8 632
zinnetyazicii53 0:83277b73a1f8 633 toGet = I2C_BUFFER_LENGTH - (I2C_BUFFER_LENGTH % (activeLEDs * 3)); //Trim toGet to be a multiple of the samples we need to read
zinnetyazicii53 0:83277b73a1f8 634 }
zinnetyazicii53 0:83277b73a1f8 635
zinnetyazicii53 0:83277b73a1f8 636 bytesLeftToRead -= toGet;
zinnetyazicii53 0:83277b73a1f8 637
zinnetyazicii53 0:83277b73a1f8 638 //Request toGet number of bytes from sensor
zinnetyazicii53 0:83277b73a1f8 639 _i2cPort->requestFrom(MAX30102_ADDRESS, toGet);
zinnetyazicii53 0:83277b73a1f8 640
zinnetyazicii53 0:83277b73a1f8 641 while (toGet > 0)
zinnetyazicii53 0:83277b73a1f8 642 {
zinnetyazicii53 0:83277b73a1f8 643 sense.head++; //Advance the head of the storage struct
zinnetyazicii53 0:83277b73a1f8 644 sense.head %= STORAGE_SIZE; //Wrap condition
zinnetyazicii53 0:83277b73a1f8 645
zinnetyazicii53 0:83277b73a1f8 646 byte temp[sizeof(uint32_t)]; //Array of 4 bytes that we will convert into long
zinnetyazicii53 0:83277b73a1f8 647 uint32_t tempLong;
zinnetyazicii53 0:83277b73a1f8 648
zinnetyazicii53 0:83277b73a1f8 649 //Burst read three bytes - RED
zinnetyazicii53 0:83277b73a1f8 650 temp[3] = 0;
zinnetyazicii53 0:83277b73a1f8 651 temp[2] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 652 temp[1] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 653 temp[0] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 654
zinnetyazicii53 0:83277b73a1f8 655 //Convert array to long
zinnetyazicii53 0:83277b73a1f8 656 memcpy(&tempLong, temp, sizeof(tempLong));
zinnetyazicii53 0:83277b73a1f8 657
zinnetyazicii53 0:83277b73a1f8 658 tempLong &= 0x3FFFF; //Zero out all but 18 bits
zinnetyazicii53 0:83277b73a1f8 659
zinnetyazicii53 0:83277b73a1f8 660 sense.red[sense.head] = tempLong; //Store this reading into the sense array
zinnetyazicii53 0:83277b73a1f8 661
zinnetyazicii53 0:83277b73a1f8 662 if (activeLEDs > 1)
zinnetyazicii53 0:83277b73a1f8 663 {
zinnetyazicii53 0:83277b73a1f8 664 //Burst read three more bytes - IR
zinnetyazicii53 0:83277b73a1f8 665 temp[3] = 0;
zinnetyazicii53 0:83277b73a1f8 666 temp[2] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 667 temp[1] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 668 temp[0] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 669
zinnetyazicii53 0:83277b73a1f8 670 //Convert array to long
zinnetyazicii53 0:83277b73a1f8 671 memcpy(&tempLong, temp, sizeof(tempLong));
zinnetyazicii53 0:83277b73a1f8 672
zinnetyazicii53 0:83277b73a1f8 673 tempLong &= 0x3FFFF; //Zero out all but 18 bits
zinnetyazicii53 0:83277b73a1f8 674
zinnetyazicii53 0:83277b73a1f8 675 sense.IR[sense.head] = tempLong;
zinnetyazicii53 0:83277b73a1f8 676 }
zinnetyazicii53 0:83277b73a1f8 677
zinnetyazicii53 0:83277b73a1f8 678 if (activeLEDs > 2)
zinnetyazicii53 0:83277b73a1f8 679 {
zinnetyazicii53 0:83277b73a1f8 680 //Burst read three more bytes - Green
zinnetyazicii53 0:83277b73a1f8 681 temp[3] = 0;
zinnetyazicii53 0:83277b73a1f8 682 temp[2] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 683 temp[1] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 684 temp[0] = _i2cPort->read();
zinnetyazicii53 0:83277b73a1f8 685
zinnetyazicii53 0:83277b73a1f8 686 //Convert array to long
zinnetyazicii53 0:83277b73a1f8 687 memcpy(&tempLong, temp, sizeof(tempLong));
zinnetyazicii53 0:83277b73a1f8 688
zinnetyazicii53 0:83277b73a1f8 689 tempLong &= 0x3FFFF; //Zero out all but 18 bits
zinnetyazicii53 0:83277b73a1f8 690
zinnetyazicii53 0:83277b73a1f8 691 sense.green[sense.head] = tempLong;
zinnetyazicii53 0:83277b73a1f8 692 }
zinnetyazicii53 0:83277b73a1f8 693
zinnetyazicii53 0:83277b73a1f8 694 toGet -= activeLEDs * 3;
zinnetyazicii53 0:83277b73a1f8 695 }
zinnetyazicii53 0:83277b73a1f8 696
zinnetyazicii53 0:83277b73a1f8 697 } //End while (bytesLeftToRead > 0)
zinnetyazicii53 0:83277b73a1f8 698
zinnetyazicii53 0:83277b73a1f8 699 } //End readPtr != writePtr
zinnetyazicii53 0:83277b73a1f8 700
zinnetyazicii53 0:83277b73a1f8 701 return (numberOfSamples); //Let the world know how much new data we found
zinnetyazicii53 0:83277b73a1f8 702 }
zinnetyazicii53 0:83277b73a1f8 703
zinnetyazicii53 0:83277b73a1f8 704 //Check for new data but give up after a certain amount of time
zinnetyazicii53 0:83277b73a1f8 705 //Returns true if new data was found
zinnetyazicii53 0:83277b73a1f8 706 //Returns false if new data was not found
zinnetyazicii53 0:83277b73a1f8 707 bool safeCheck(uint8_t maxTimeToCheck)
zinnetyazicii53 0:83277b73a1f8 708 {
zinnetyazicii53 0:83277b73a1f8 709 uint32_t markTime = millis();
zinnetyazicii53 0:83277b73a1f8 710
zinnetyazicii53 0:83277b73a1f8 711 while(1)
zinnetyazicii53 0:83277b73a1f8 712 {
zinnetyazicii53 0:83277b73a1f8 713 if(millis() - markTime > maxTimeToCheck) return(false);
zinnetyazicii53 0:83277b73a1f8 714
zinnetyazicii53 0:83277b73a1f8 715 if(check() == true) //We found new data!
zinnetyazicii53 0:83277b73a1f8 716 return(true);
zinnetyazicii53 0:83277b73a1f8 717
zinnetyazicii53 0:83277b73a1f8 718 delay(1);
zinnetyazicii53 0:83277b73a1f8 719 }
zinnetyazicii53 0:83277b73a1f8 720 }
zinnetyazicii53 0:83277b73a1f8 721
zinnetyazicii53 0:83277b73a1f8 722 //Given a register, read it, mask it, and then set the thing
zinnetyazicii53 0:83277b73a1f8 723 void bitMask(uint8_t reg, uint8_t mask, uint8_t thing)
zinnetyazicii53 0:83277b73a1f8 724 {
zinnetyazicii53 0:83277b73a1f8 725 // Grab current register context
zinnetyazicii53 0:83277b73a1f8 726 uint8_t originalContents = readRegister8(_i2caddr, reg);
zinnetyazicii53 0:83277b73a1f8 727
zinnetyazicii53 0:83277b73a1f8 728 // Zero-out the portions of the register we're interested in
zinnetyazicii53 0:83277b73a1f8 729 originalContents = originalContents & mask;
zinnetyazicii53 0:83277b73a1f8 730
zinnetyazicii53 0:83277b73a1f8 731 // Change contents
zinnetyazicii53 0:83277b73a1f8 732 writeRegister8(_i2caddr, reg, originalContents | thing);
zinnetyazicii53 0:83277b73a1f8 733 }
zinnetyazicii53 0:83277b73a1f8 734
zinnetyazicii53 0:83277b73a1f8 735 //
zinnetyazicii53 0:83277b73a1f8 736 // Low-level I2C Communication
zinnetyazicii53 0:83277b73a1f8 737 //
zinnetyazicii53 0:83277b73a1f8 738 uint8_t readRegister8(uint8_t address, uint8_t reg) {
zinnetyazicii53 0:83277b73a1f8 739 _i2cPort->beginTransmission(address);
zinnetyazicii53 0:83277b73a1f8 740 _i2cPort->write(reg);
zinnetyazicii53 0:83277b73a1f8 741 _i2cPort->endTransmission(false);
zinnetyazicii53 0:83277b73a1f8 742
zinnetyazicii53 0:83277b73a1f8 743 _i2cPort->requestFrom((uint8_t)address, (uint8_t)1); // Request 1 byte
zinnetyazicii53 0:83277b73a1f8 744 if (_i2cPort->available())
zinnetyazicii53 0:83277b73a1f8 745 {
zinnetyazicii53 0:83277b73a1f8 746 return(_i2cPort->read());
zinnetyazicii53 0:83277b73a1f8 747 }
zinnetyazicii53 0:83277b73a1f8 748
zinnetyazicii53 0:83277b73a1f8 749 return (0); //Fail
zinnetyazicii53 0:83277b73a1f8 750
zinnetyazicii53 0:83277b73a1f8 751 }
zinnetyazicii53 0:83277b73a1f8 752
zinnetyazicii53 0:83277b73a1f8 753 void writeRegister8(uint8_t address, uint8_t reg, uint8_t value) {
zinnetyazicii53 0:83277b73a1f8 754 _i2cPort->beginTransmission(address);
zinnetyazicii53 0:83277b73a1f8 755 _i2cPort->write(reg);
zinnetyazicii53 0:83277b73a1f8 756 _i2cPort->write(value);
zinnetyazicii53 0:83277b73a1f8 757 _i2cPort->endTransmission();
zinnetyazicii53 0:83277b73a1f8 758 }
zinnetyazicii53 0:83277b73a1f8 759 */