Mode1 Optical Validation

Dependencies:   max32630fthr

main.cpp

Committer:
phonemacro
Date:
2021-03-26
Revision:
6:e1b7190d6cb5
Parent:
5:7f5a012747a5
Child:
7:23b067817ab8

File content as of revision 6:e1b7190d6cb5:

/*******************************************************************************
* Copyright (C) 2018 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 "platform/mbed_thread.h"
#include "mbed.h"
/******************************************************************************
* Warning, if using the either
*   MAX32630FTHR+MAXM86161_ADPTER_REVB+MAXM86146EVSYS sensor brd or
*   MAX32630FTHR+MAXM86161_ADPTER_REVB+MAXM86161EVSYS sensor brd,
* The VLED is connected to USB power which is noisy. The VLED should be
* connected to a regulated power supply if you are testing accuracy.
*******************************************************************************
*/
/******************************************************************************
* Tera Term output is set to 115200 baud rate.
* ver: 210325
******************************************************************************/

/*****************************************************************************/
// define one and only one of the following three platforms
//#define MAXM86146_CFG 1  // tested on MAXM86146EVSYS_sensorBrd+MAXM86161_ADAPTER_REVB+MAX32630FTHR
#define MAXREFDES103_CFG  // tested on MAXREFDES103
//#define MAX86161_CFG 1
/*****************************************************************************/

#define ALGO_ONLY 1  // define this if you only want the algo data, comment out if you want raw sensor+algo data


#ifdef MAXREFDES103_CFG
#include "MAX20303.h"
I2C sh_i2c_pmic(P5_7, P6_0);
#endif

#ifdef MAXM86146_CFG
  #define PPG_SZ 36  //maxm86146
#else
  #define PPG_SZ 18  //maxm86161, max86141
#endif
#define ACCEL_SZ 6  // accel
#define SENSOR_SZ (PPG_SZ+ACCEL_SZ)
//#define ALGO_SZ 20  // 24 bytes is the algo normal size for 3x.12.0
#define ALGO_SZ 24  // 24 bytes is the algo normal size for 3x.13.x
#ifdef ALGO_ONLY
  #define TTL_SZ (ALGO_SZ)
#else
  #define TTL_SZ (PPG_SZ+ACCEL_SZ+ALGO_SZ)
#endif

Serial pc(USBTX, USBRX, 115200);
DigitalOut rLED(LED1);
DigitalOut gLED(LED2);
DigitalOut bLED(LED3);
/******************************************************************************
* MAX32630FTHR GPIOs
******************************************************************************/
#define RST_PIN   P5_6
#define MFIO_PIN  P5_4
DigitalOut rst(RST_PIN, PullUp);
DigitalOut mfio(MFIO_PIN, PullUp);
I2C sh_i2c(P3_4, P3_5);

//#define thread_sleep_for(x) wait_ms(x) // for older versions of mbed


const int SH_ADDR = 0xAA;//0x55;
int32_t Time_to_Read_PPG = 0;

#define BLINKING_RATE_MS 1000ms
void blink_timer(void) {
    gLED = !gLED;  /* blink the green LED */
}

void fifo_timer(void) {
    Time_to_Read_PPG = 1;
}

void read_ppg(void) {
    char cmd[8], i, j, samples;
    char rsp[3000];
    int32_t ppg[12];
    int16_t accel[3];
    int32_t status, opmode, hr, hr_conf, ibi, ibi_conf, act, r, spo2, spo2_conf;
    int32_t spo2_compl, spo2_lo, spo2_mo, spo2_lopi, spo2_unrel, spo2_state, ibi_offset, scd;
    int32_t scnt = 0;
    int32_t ptr = 0;
    int32_t sptr = 0;
    mfio = 0; wait_us(300);
    Time_to_Read_PPG = 0;
#if 0
// 2.1
    cmd[0] = 0x00; cmd[1] = 0x00;
    sh_i2c.write(SH_ADDR, cmd, 2);
    wait_us(100);
    sh_i2c.read(SH_ADDR, rsp, 2);
//    pc.printf("2.1 Status: %x %x\n\r", rsp[0], rsp[1]);
#endif
// 2.2
    cmd[0] = 0x12; cmd[1] = 0x00;
    sh_i2c.write(SH_ADDR, cmd, 2);
    wait_us(100);
    sh_i2c.read(SH_ADDR, rsp, 2);
//    pc.printf("2.2 Status: %x %x\n\r", rsp[0], rsp[1]);
    samples = rsp[1];
//    pc.printf("num samples %d, (num*ttl)+1 %d\n\r",  rsp[1], TTL_SZ*samples+1);
//    pc.printf("num smpls %d \n\r",  samples);
    scnt = rsp[1];
// 2.3
    cmd[0] = 0x12; cmd[1] = 0x01;
    sh_i2c.write(SH_ADDR, cmd, 2);
    wait_us(100);
//    thread_sleep_for(1);
    sh_i2c.read(SH_ADDR, rsp, 1+(TTL_SZ*samples));
        status = rsp[0];

        sptr = 1;
        for (i = 0; i < scnt; i++) {
#ifdef ALGO_ONLY
            ptr = sptr;
#else
            ptr = sptr;
            ppg[0] = (rsp[ptr+0] << 16) | (rsp[ptr+1] << 8) | (rsp[ptr+2]);
            ppg[1] = (rsp[ptr+3] << 16) | (rsp[ptr+4] << 8) | (rsp[ptr+5]);
            ppg[2] = (rsp[ptr+6] << 16) | (rsp[ptr+7] << 8) | (rsp[ptr+8]);
            ppg[3] = (rsp[ptr+9] << 16) | (rsp[ptr+10] << 8) | (rsp[ptr+11]);
            ppg[4] = (rsp[ptr+12] << 16) | (rsp[ptr+13] << 8) | (rsp[ptr+14]);
            ppg[5] = (rsp[ptr+15] << 16) | (rsp[ptr+16] << 8) | (rsp[ptr+17]);
            pc.printf("%d,%d,%d,%d,", ppg[0], ppg[1], ppg[2], ppg[3]);
//            pc.printf("%d,%d,", ppg[4], ppg[5]);
            accel[0] = (rsp[PPG_SZ+0] << 8) | (rsp[PPG_SZ+1]);
            accel[1] = (rsp[PPG_SZ+2] << 8) | (rsp[PPG_SZ+3]);
            accel[2] = (rsp[PPG_SZ+4] << 8) | (rsp[PPG_SZ+5]);
            pc.printf("%d,%d,%d,", accel[0], accel[1], accel[2]);

            ptr = sptr + SENSOR_SZ;
#endif
//            pc.printf("ptr %d ttlsiz %d ", ptr, TTL_SZ);
            opmode = rsp[ptr];
            hr =  (rsp[ptr+1] << 8) + rsp[ptr+2];
            hr_conf = rsp[ptr+3];
            ibi = rsp[ptr+4];

            ibi_conf = (rsp[ptr+5] << 8) + rsp[ptr+6];
            act = rsp[ptr+7];
            r = (rsp[ptr+8] << 8) + rsp[ptr+9];
            spo2_conf = rsp[ptr+10];

            spo2 = (rsp[ptr+11] << 8) + rsp[ptr+12];
            spo2_compl = rsp[ptr+13];
            spo2_lo = rsp[ptr+14];
            spo2_mo = rsp[ptr+15];

            spo2_lopi = rsp[ptr+16];
            spo2_unrel = rsp[ptr+17];
            spo2_state = rsp[ptr+18];
            scd = rsp[ptr+19];

            ibi_offset = rsp[ptr+20];

            sptr += (TTL_SZ);
#if 0
            pc.printf("%d,%d,%d,%d,", opmode, hr, hr_conf, ibi);
            pc.printf("%d,%d,%d,%d,", ibi_conf, act, r, spo2_conf);
            pc.printf("%d,%d,%d,%d,", spo2, spo2_compl, spo2_lo, spo2_mo);
            pc.printf("%d,%d,%d,%d,", spo2_lopi,spo2_unrel, spo2_state, scd);
            pc.printf("%d,", ibi_offset);
#else
            pc.printf("%d,%d,", hr, hr_conf);
            pc.printf("%d,%d,", spo2, spo2_conf);
            pc.printf("%d,", spo2_lo);
            pc.printf("%d,%d,", spo2_unrel, scd);
#endif


            pc.printf("\n\r");
        }
        mfio = 1;
}

#ifdef MAXREFDES103_CFG
void init_max20303_pmic(void) {
    /* Wait for pmic to settle down */
    thread_sleep_for(800);

    //set_time(1544787300);  // Set RTC time to Wed, 28 Oct 2009 11:35:37
    MAX20303 max20303(&sh_i2c);
    /*Set LDO1 to 1.8v*/
    max20303.LDO1Config();

    /*Set LDO2 to 3v*/
    max20303.LDO2Config();

    //max20303.BoostEnable();
    max20303.BuckBoostEnable();

    max20303.led0on(0);
    max20303.led1on(0);
    max20303.led2on(0);

    /* Wait for pmic to settle down */
    thread_sleep_for(200);
   
}
#endif // MAXREFDES103_CFG
int main()
{
    sh_i2c.frequency(400000);
    char cmd[8], i, j;
    char rsp[256];
    int32_t ppg[12];
    int32_t ledcnt = 0;
    rLED = LED_OFF;  gLED = LED_ON;  bLED = LED_OFF;
    Ticker ticker;   // calls a callback repeatedly with a timeout
    //ticker.attach(callback(&blink_timer), BLINKING_RATE_MS);  /* set timer for one second */

    // application
    rst = 0;
    mfio = 1;
    thread_sleep_for(10);
    rst = 1;
    thread_sleep_for(1500);

    mfio = 0; wait_us(300);

#ifdef MAXREFDES103_CFG
    init_max20303_pmic();
#endif
//read operating mode
    cmd[0] = 0x02; cmd[1] = 0x00;
    sh_i2c.write(SH_ADDR, cmd, 2);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 2);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    pc.printf("\n\r 0x02 0x00 Status, Read Operating Mode: %x %x\n\r", rsp[0], rsp[1]);
//1.11 rd ver
    cmd[0] = 0xFF; cmd[1] = 0x03;
    sh_i2c.write(SH_ADDR, cmd, 2);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 4);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("Ver: %d %d %d %d\n\r", rsp[0], rsp[1], rsp[2], rsp[3]);

// 1.3 sensor and algo data
    cmd[0] = 0x10; cmd[1] = 0x00;
#ifdef ALGO_ONLY
    cmd[2] = 0x02;  // algo data
    pc.printf("algo only \n\r");
#else
    cmd[2] = 0x03;  // sensor + algo data
    pc.printf("sens+algo \n\r");
#endif
    sh_i2c.write(SH_ADDR, cmd, 3);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("1.3 Status: %x\n\r", rsp[0]);
// 1.7 cont hr, spo2
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x0A; cmd[3] = 0x00;
    sh_i2c.write(SH_ADDR, cmd, 4);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("1.7 Status: %x\n\r", rsp[0]);
// 1.8 AEC enable (default)
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x0B; cmd[3] = 0x01;
    sh_i2c.write(SH_ADDR, cmd, 4);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("1.8 Status: %x\n\r", rsp[0]);
// 1.9 auto PD (default
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x12; cmd[3] = 0x01;
    sh_i2c.write(SH_ADDR, cmd, 4);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("1.9 Status: %x\n\r", rsp[0]);
// 1.10 SCD (default)
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x0C; cmd[3] = 0x01;
    sh_i2c.write(SH_ADDR, cmd, 4);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("1.7 Status: %x\n\r", rsp[0]);
#ifdef MAXM86146_CFG
//1.20 Sec 4.1  map leds to slots for MAXM86146
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x19; cmd[3] = 0x13; cmd[4] = 0x56; cmd[5] = 0x00;
    sh_i2c.write(SH_ADDR, cmd, 6);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("map leds to slots%x\n\r", rsp[0]);
//1.21  map HR inputs to slots
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x17; cmd[3] = 0x00; cmd[4] = 0x11;
    sh_i2c.write(SH_ADDR, cmd, 5);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("map HR to slots/PDs %x\n\r", rsp[0]);
//1.22  map SpO2 inputs to slots
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x18; cmd[3] = 0x30; cmd[4] = 0x20;
    sh_i2c.write(SH_ADDR, cmd, 5);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("map SpO2 to slots/PDs %x\n\r", rsp[0]);
#if 0
//1.20 Sec 4.1  map leds to slots for MAXM86146
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x19; cmd[3] = 0x15; cmd[4] = 0x60; cmd[5] = 0x00;
    sh_i2c.write(SH_ADDR, cmd, 6);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("map leds to slots%x\n\r", rsp[0]);
//1.21  map HR inputs to slots
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x17; cmd[3] = 0x00; cmd[4] = 0x01;
    sh_i2c.write(SH_ADDR, cmd, 5);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("map HR to slots/PDs %x\n\r", rsp[0]);
//1.22  map SpO2 inputs to slots
    cmd[0] = 0x50; cmd[1] = 0x07; cmd[2] = 0x18; cmd[3] = 0x20; cmd[4] = 0x10;
    sh_i2c.write(SH_ADDR, cmd, 5);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 1);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("map SpO2 to slots/PDs %x\n\r", rsp[0]);
#endif
#endif // MAXM86146_CFG

// 1.3 Enable HR, SpO2 algo
    cmd[0] = 0x52; cmd[1] = 0x07; cmd[2] = 0x01;
    sh_i2c.write(SH_ADDR, cmd, 3);
    thread_sleep_for(465);
    sh_i2c.read(SH_ADDR, rsp, 1);
    pc.printf("1.14 status: %x\n\r", rsp[0]);
    mfio = 1;

#if 1
//1.31 rd AFE part id
    cmd[0] = 0x41; cmd[1] = 0x00; cmd[2] = 0xFF;
    sh_i2c.write(SH_ADDR, cmd, 3);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 2);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("1.31 part id afe %x %x\n\r", rsp[0], rsp[1]);
//1.32 rd accel who
    cmd[0] = 0x41; cmd[1] = 0x04; cmd[2] = 0x0F;
    sh_i2c.write(SH_ADDR, cmd, 3);
    mfio = 1; thread_sleep_for(2); mfio = 0; wait_us(300);
    sh_i2c.read(SH_ADDR, rsp, 2);
    mfio = 1; mfio = 0; wait_us(300);
    pc.printf("1.32 who accel %x %x\n\r", rsp[0], rsp[1]);
#endif

#if defined(MAXREFDES103_CFG) || defined(MAXM86161_CFG)
    Timer tmr1;
    while (1) {
        tmr1.start();
        if (tmr1.read_ms() > 40) {
            read_ppg();
            if (ledcnt++ % 50)
                gLED = !gLED;
        }
    }
#else
    ticker.attach(callback(&fifo_timer), 0.040f);
    while (1) {
        if (Time_to_Read_PPG) {
            read_ppg();
            if (ledcnt++ % 50)
                gLED = !gLED;
        }
    }
#endif
}