Maxim Integrated's IoT development kit
Dependencies: MAX30101 MAX30003 MAX113XX_Pixi MAX30205 max32630fthr USBDevice
max30101_app.cpp
- Committer:
- Mahir Ozturk
- Date:
- 2018-07-19
- Revision:
- 16:503f8308e2db
- Parent:
- 13:fba77a5d0fa0
File content as of revision 16:503f8308e2db:
/* * max30101_app.cpp * * Created on: Jun 20, 2018 * Author: Mahir.Ozturk */ #include <mbed.h> #include "max30101_app.h" #include "MAX30101.h" #include "max30101_algo.h" #define MAX30101_IRQ_ASSERTED_ID 1 #define MAX30101_BUFFER_LEN 500 static Thread *thread = 0; //variable for the algorithm uint16_t sampleRate = 100; uint16_t compSpO2 = 1; int16_t ir_ac_comp = 0; int16_t red_ac_comp = 0; int16_t green_ac_comp = 0; int16_t ir_ac_mag = 0; int16_t red_ac_mag = 0; int16_t green_ac_mag = 0; uint16_t HRbpm2 = 0; uint16_t SpO2B = 0; uint16_t DRdy = 0; //declare large variables outside of main uint32_t redData[MAX30101_BUFFER_LEN];//set array to max fifo size uint32_t irData[MAX30101_BUFFER_LEN];//set array to max fifo size uint32_t greenData[MAX30101_BUFFER_LEN];//set array to max fifo size bool max30101_config(MAX30101 &op_sensor) { //Reset Device MAX30101::ModeConfiguration_u modeConfig; modeConfig.all = 0; modeConfig.bits.reset = 1; modeConfig.bits.mode = MAX30101::MultiLedMode; // Sets SPO2 Mode int32_t rc = op_sensor.setModeConfiguration(modeConfig); //enable MAX30101 interrupts MAX30101::InterruptBitField_u ints; if (rc == 0) { ints.all = 0; ints.bits.a_full = 1; // Enable FIFO almost full interrupt ints.bits.ppg_rdy =1; //Enables an interrupt when a new sample is ready rc = op_sensor.enableInterrupts(ints); } //configure FIFO MAX30101::FIFO_Configuration_u fifoConfig; if (rc == 0) { fifoConfig.all = 0; fifoConfig.bits.fifo_a_full = 10; // Max level of 17 samples fifoConfig.bits.sample_average = MAX30101::AveragedSamples_0;// Average 0 samples rc = op_sensor.setFIFOConfiguration(fifoConfig); } MAX30101::SpO2Configuration_u spo2Config; if (rc == 0) { spo2Config.all = 0; // clears register spo2Config.bits.spo2_adc_range = 1; //sets resolution to 4096 nAfs spo2Config.bits.spo2_sr = MAX30101::SR_100_Hz; // SpO2 SR = 100Hz spo2Config.bits.led_pw = MAX30101::PW_3; // 18-bit ADC resolution ~400us rc = op_sensor.setSpO2Configuration(spo2Config); } //Set time slots for LEDS MAX30101::ModeControlReg_u multiLED; if (rc == 0) { //sets timing for control register 1 multiLED.bits.lo_slot=1; multiLED.bits.hi_slot=2; rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg1, multiLED); if (rc == 0) { multiLED.bits.lo_slot=3; multiLED.bits.hi_slot=0; rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg2, multiLED); } } //Set LED drive currents if (rc == 0) { // Heart Rate only, 1 LED channel, Pulse amp. = ~7mA rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED1_PA, 0x24); //To include SPO2, 2 LED channel, Pulse amp. ~7mA if (rc == 0) { rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED2_PA, 0x24); } if (rc == 0) { rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED3_PA, 0x24); } } //Set operating mode modeConfig.all = 0; if (rc == 0) { modeConfig.bits.mode = MAX30101::MultiLedMode; // Sets multiLED mode rc = op_sensor.setModeConfiguration(modeConfig); } return rc; } void max30101wing_pmic_config(I2C & i2c_bus, DigitalOut & pmic_en) { const uint8_t PMIC_ADRS = 0x54; const uint8_t BBB_EXTRA_ADRS = 0x1C; const uint8_t BOOST_VOLTAGE = 0x05; char data_buff[] = {BBB_EXTRA_ADRS, 0x40}; //BBBExtra register address //and data to enable passive //pull down. i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register data_buff[0] = BOOST_VOLTAGE; data_buff[1] = 0x08; //Boost voltage configuration //register followed by data //to set voltage to 4.5V 1f pmic_en = 0; //disables VLED 08 i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register pmic_en = 1; //enables VLED } /* Op Sensor FIFO nearly full callback */ void max30101_intr_callback() { if (thread != 0) { thread->signal_set(MAX30101_IRQ_ASSERTED_ID); } } void max30101_reader_task(struct max30101_reader_task_args *args) { InterruptIn op_sensor_int(args->pinIntr); // Config P3_2 as int. in for op_sensor_int.fall(max30101_intr_callback); // FIFO ready interrupt DigitalOut VLED_EN(args->pinVLED,0); //Enable for VLEDs max30101wing_pmic_config(args->i2cBus, VLED_EN); MAX30101 op_sensor(args->i2cBus); // Create new MAX30101 on i2cBus int rc = max30101_config(op_sensor); // Config sensor, return 0 on success MAX30101::InterruptBitField_u ints; // Read interrupt status to clear rc = op_sensor.getInterruptStatus(ints); // power on interrupt thread = args->self; uint8_t fifoData[MAX30101::MAX_FIFO_BYTES]; uint16_t idx, readBytes; uint16_t HRTemp; uint16_t spo2Temp; uint16_t lastValidHR = 0; uint16_t lastValidSPO2 = 0; int r=0; //counter for redData position int ir=0; //counter for irData position int g =0; //counter for greenData position int c=0; //counter to print values int consecCalcFailCnt = 0; printf("Starting MAX30101 HeartRate / SPO2 Demo Application...\r\n"); printf("Please wait a few seconds while data is being collected.\r\n"); Timer bleNotifyTimer; bleNotifyTimer.start(); while (1) { if (rc == 0) { /* Check if op_sensor interrupt asserted */ thread->signal_wait(MAX30101_IRQ_ASSERTED_ID); /* Read interrupt status to clear interrupt */ rc = op_sensor.getInterruptStatus(ints); /* Confirms proper read prior to executing */ if (rc == 0) { // Read FIFO rc = op_sensor.readFIFO(MAX30101::ThreeLedChannels, fifoData, readBytes); if (rc == 0) { /* Convert read bytes into samples */ for (idx = 0; idx < readBytes; idx+=9) { if (r >= 500 || ir >= 500 || g >= 500) { printf("Overflow! r=%d ir=%d g=%d\r\n", r, ir, g); break; } if (readBytes >= (idx + 8)) { redData[r++] = ((fifoData[idx] << 16) | (fifoData[idx + 1] << 8) | (fifoData[idx + 2])) & 0x03FFFF; irData[ir++] = ((fifoData[idx + 3] << 16) | (fifoData[idx + 4] << 8) | (fifoData[idx + 5])) & 0x03FFFF; greenData[g++] = ((fifoData[idx + 6] << 16) | (fifoData[idx + 7] << 8) | (fifoData[idx + 8])) & 0x03FFFF; } } if ((r >= MAX30101_BUFFER_LEN) && (ir >= MAX30101_BUFFER_LEN) && (g >= MAX30101_BUFFER_LEN)) {/* checks to make sure there are 500 */ /* samples in data buffers */ /* runs the heart rate and SpO2 algorithm */ for (c = 0, HRTemp = 0; c < r; c++) { HRSpO2Func(irData[c], redData[c],greenData[c], c,sampleRate, compSpO2, &ir_ac_comp,&red_ac_comp, &green_ac_comp, &ir_ac_mag,&red_ac_mag, &green_ac_mag, &HRbpm2,&SpO2B,&DRdy); if (DRdy) { HRTemp = HRbpm2; spo2Temp = SpO2B; } } /* If the above algorithm returns a valid heart rate on the last sample, it is printed */ if (DRdy == 1) { printf("Heart Rate = %i\r\n",HRbpm2); printf("SPO2 = %i\r\n",SpO2B); lastValidHR = HRbpm2; lastValidSPO2 = SpO2B; consecCalcFailCnt = 0; } else if (HRTemp != 0) { /* if a valid heart was calculated at all, it is printed */ printf("Heart Rate = %i\r\n",HRTemp); printf("SPO2 = %i\r\n",spo2Temp); lastValidHR = HRTemp; lastValidSPO2 = spo2Temp; consecCalcFailCnt = 0; } else { consecCalcFailCnt++; if (consecCalcFailCnt >= 10) { printf("Calculation failed...waiting for more samples...\r\n"); printf("Please keep your finger on the MAX30101 sensor with minimal movement.\r\n"); consecCalcFailCnt = 0; } } /* dump the first hundred samples after calculation */ for (c = 100; c < 500; c++) { redData[c - 100] = redData[c]; irData[c - 100] = irData[c]; greenData[c - 100] = greenData[c]; } /* reset counters */ r = 400; ir = 400; g = 400; } if (bleNotifyTimer.read_ms() >= (args->notify_period_sec * 1000)) { bleGattAttrWrite(args->gattHeartRate, (uint8_t *)&lastValidHR, sizeof(lastValidHR)); bleGattAttrWrite(args->gattSPO2, (uint8_t *)&lastValidSPO2, sizeof(lastValidSPO2)); bleNotifyTimer.reset(); } } } } else { // If rc != 0, a communication error has occurred printf("Something went wrong, " "check the I2C bus or power connections... \r\n"); return; } } }