Maxim Integrated's IoT development kit
Dependencies: MAX30101 MAX30003 MAX113XX_Pixi MAX30205 max32630fthr USBDevice
Diff: max30101_app.cpp
- Revision:
- 13:fba77a5d0fa0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/max30101_app.cpp Thu Jun 28 15:47:24 2018 +0300
@@ -0,0 +1,270 @@
+/*
+ * 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;
+ }
+
+ }
+}
+
+