Back to All
Project

MDM9206 with Heart Rate Sensor


Skill Level Area of Focus Operating System Platform/Hardware Cloud Services/Platform
Intermediate Healthcare, Sensors RTOS MDM920x LTE for IoT Gizwits Cloud Platform

This project is designed to use a heart rate sensor with the Qualcomm® MDM9206 LTE modem, and when the detected data is higher than the set threshold, the LED light is illuminated.

Objective

The main objective of this project is to connect the heart rate sensor to the ADC interface of the MDM9206 modem provided by the GoKit development board and collect heart rate information. The LED is designed to turn ON when the detected heart rate is higher than the threshold value.

Materials Required / Parts List / Tools


GoKit4

LED

DuPont

Using

Source Code / Source Examples / Application Executable

Build / Assembly Instructions

Parts used

Below are the items used in this project:

  1. Win7 PC
  2. Pulse Sensor, used to collect heart rate information
  3. LED, when the detected heart rate value exceeds the set threshold, the LED lights up
  4. DuPont cable, used to connect other components as wires
  5. Oscilloscope, used to view the detected heart rate waveform in real time

Parts

Parts

How does it work?

The application is designed to upload the data to the Gizwits cloud. Below are the different functions implemented in the project.

Now let's introduce the demo-smart-heart-rate-detector’s workflow.

gagentMain---->sensorInit----->led_init---->Pulsesensor_init.
  demo-Smart-Heart-rate-detector/main/main.c
  void gagentMain(void)
  {
    getFreeHeap();
    sensorInit();
    gizwitsInit();
    timer_init();
    timer_start();
  }

The function named "gagentMain" was called by "GAgent". The main role of GAgent is data forwarding, which is a data interaction bridge between device data, Wit Cloud, and application end (APP). Function "sensorInit" does the sensor initialization:

void sensorInit(void)
  {
    gizLog(LOG_INFO, "Sensor initialization ...\n");
    led_init();
    Pulsesensor_init();
  }
  
  void led_init()
  {
    gizLog(LOG_INFO, "in led init...\n");
    led_gpio_config();
    led_on_off(false, led_red);
  }
  void Pulsesensor_init()
  {
    qapi_Status_t status = QAPI_ERROR;
    const char *Channel_Name_ADC0 = ADC_INPUT_ADC0;
    qapi_Timer_Sleep(2, QAPI_TIMER_UNIT_SEC, true);
    status = adc_open_handle();  
    if(status != QAPI_OK)
      {
      //IOT_DEBUG("Get ADC Handle ERROR!");
      gizLog(LOG_INFO,"adc open handle error...\n");
      return;
      }
    status = adc_get_properties(Channel_Name_ADC0, &Properties_ADC0);
      if(status != QAPI_OK)
      {
      //IOT_DEBUG("Get ADC channel-%s Configuration ERROR!", Channel_Name_ADC1);
      gizLog(LOG_INFO,"Get ADC channel-%s Configuration ERROR...\n", Channel_Name_ADC0);
      return;
      }
  }
  demo-Smart-Heart-rate-detector/driver/timer/timer.c
  qapi_Status_t timer_init(void)      //init 
  {
              qapi_Status_t status = QAPI_OK;
              memset(&timer_def_attr, 0, sizeof(timer_def_attr));
    timer_def_attr.cb_type	= QAPI_TIMER_FUNC1_CB_TYPE;
    timer_def_attr.deferrable = false;
    timer_def_attr.sigs_func_ptr = timer1_handler;
    timer_def_attr.sigs_mask_data = 0x11;
    status = qapi_Timer_Def(&timer_handle, &timer_def_attr);
              return status;
  }
  qapi_Status_t timer_start(void)
  {
      qapi_Status_t status = QAPI_OK;
  
              memset(&timer_set_attr, 0, sizeof(timer_set_attr));
    timer_set_attr.reload = 100;
    timer_set_attr.time = 10;
    timer_set_attr.unit = QAPI_TIMER_UNIT_MSEC;
    status = qapi_Timer_Set(timer_handle, &timer_set_attr);
              return status;
  }
  void timer1_handler(uint32_t data)         // timer callback
  {
    static bool led_red_status = true;
    getHeartRateValue(&heartrate);            //get heartvalue
    if(!heartrate)	                                       //no  value		
    {
      return;
    }
    else if(((heartrate > HEART_RATE_THRESHOLD_HIGH) || (heartrate < HEART_RATE_THRESHOLD_LOW)))	  // value is not vaild
    {
      led_on_off(true, led_red);	      //red on
      //led_on_off(led_red_status, led_red);		
      //led_red_status = !led_red_status;
    }
      else					      // value is vaild
    {
      led_on_off(false,led_red);		//red off
    } 
  }
  
  demo-Smart-Heart-rate-detector/driver/plusensor/plusensor.c
  
  uint8_t getHeartRateValue(uint32_t* heartrate )	//Algorithm implementation for calculating heart rate	
  {
    gizLog(LOG_INFO,"in getHeartRateValue...\n");	
    .......
    memset(&result, 0, sizeof(result));
    status = qapi_ADC_Read_Channel(adc_handle, &Properties_ADC0, &result);   // read the Pulse Sensor
              ........
    sampleCounter += 10;  // keep track of the time in mS with this variable
    Num = sampleCounter - lastBeatTime;    // monitor the time since the last beat to avoid noise
    //  find the peak and trough of the pulse wave
    if(Signal < thresh && Num > (IBI/5)*3)   // avoid dichrotic noise by waiting 3/5 of last IBI
    {  
      if(Signal < T)		// T is the trough	
      {                       
        T = Signal;                      						            // keep track of lowest point in pulse wave 
        gizLog(LOG_INFO,"Find trough, T = %d\n", T);
      }
    }
    if(Signal > thresh && Signal > P)		// thresh condition helps avoid noise
    {          
      P = Signal;                             // P is the peak,keep track of highest point in pulse wave
      gizLog(LOG_INFO,"Find peak, P = %d\n", P);
    }                                        
    //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT		
    // signal surges up in value every time there is a pulse
    if (Num > 600)			
    {                                   // avoid high frequency noise	
      if ( (Signal > thresh) && (Pulse == false) && (Num > (IBI/5)*3) )
      {        
        Pulse = true;        // set the Pulse flag when we think there is a pulse
        IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS
        lastBeatTime = sampleCounter;               // keep track of time for next pulse
        if(secondBeat)	                  // if this is the second beat, if secondBeat == TRUE
        {                        
          secondBeat = false;   // clear secondBeat flag
          for(int i=0; i<=9; i++)
          {             
            rate[i] = IBI;     	// seed the running total to get a realisitic BPM at startup                 
          }
        }
        if(firstBeat)           // if it's the first time we found a beat, if firstBeat == TRUE
        {                         
        firstBeat = false;          // clear firstBeat flag
        secondBeat = true;        // set the second beat flag
        return 0;                          // IBI value is unreliable so discard it
        }   
  
        // keep a running total of the last 10 IBI values
        runningTotal = 0;             // clear the runningTotal variable 
        for(int i=0; i<=8; i++)	
        {                
          rate[i] = rate[i+1];           // shift data in the rate array       		 	
  // and drop the oldest IBI value 
          runningTotal += rate[i];          // add up the 9 oldest IBI values
        }
        rate[9] = IBI;                          		// add the latest IBI to the rate array
        runningTotal += rate[9];               	 // add the latest IBI to runningTotal
        runningTotal /= 10;                     	// average the last 10 IBI values 
        BPM = 60000/runningTotal;        	 // how many beats can fit into a minute? that's BPM!
        *heartrate = BPM;
        gizLog(LOG_INFO,"BPM = %d\n", *heartrate); 
        QS = true;                            					 // set Quantified Self flag 
          // QS FLAG IS NOT CLEARED INSIDE THIS ISR
      }                       
    }
  
    if (Signal < thresh && Pulse == true)
    {   // when the values are going down, the beat is over
      Pulse = false;                         // reset the Pulse flag so we can do it again
      amp = P - T;                           // get amplitude of the pulse wave
      thresh = amp/2 + T;                    // set thresh at 50% of the amplitude
      P = thresh;                            // reset these for next time
      T = thresh;
    }
    if (Num > 2500)
    {                           // if 2.5 seconds go by without a beat
      thresh = 512;                          // set thresh default
      P = 512;                               // set P default
      T = 512;                               // set T default
      lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date        
      firstBeat = true;                      // set these to avoid noise
      secondBeat = false;                    // when we get the heartbeat back
    }
  }

Usage Instructions

  1. Download code from GitHub repository: “https://github.com/ThunderSoft-XA/demo-Smart-Heart-rate-detector
  2. Compile the code and flash the image to GoKit4 development kit.
  3. Connect the heart rate sensor to the ADC1 channel of the GoKit development board.
  4. Connect one pin of the led to the D9 pin of the development board, and the other pin is connected to the Vcc.
  5. Turn on the oscilloscope, adjust to the appropriate gear position, connect the heart rate sensor's pulse signal output pin and GND to the oscilloscope.
  6. Use the USB data cable to connect the PC and GoKit development board.
  7. Touch your finger to the signal acquisition surface of the heart rate sensor.
  8. Open the serial debugging assistant, and you can see the collected data in real time.

When the detected data exceeds the threshold, you can see that the LED is lit.

Opinions expressed in the content posted here are the personal opinions of the original authors, and do not necessarily reflect those of Qualcomm Incorporated or its subsidiaries ("Qualcomm"). The content is provided for informational purposes only and is not meant to be an endorsement or representation by Qualcomm or any other party. This site may also provide links or references to non-Qualcomm sites and resources. Qualcomm makes no representations, warranties, or other commitments whatsoever about any non-Qualcomm sites or third-party resources that may be referenced, accessible from, or linked to this site.

Project Authors
Thunder Software Technology (Shenzhen) Co., Ltd.
Shenzhen
Zhen
Rong
Kou
Jie
Eric

Sign up for the Developer Newsletter.

Get software and hardware tool resources to help optimize your development delivered to your inbox weekly.

Qualcomm relentlessly innovates to deliver intelligent computing everywhere, helping the world tackle some of its most important challenges. Our leading-edge AI, high performance, low-power computing, and unrivaled connectivity deliver proven solutions that transform major industries. At Qualcomm, we are engineering human progress.

Stay connected

Get the latest Qualcomm and industry information delivered to your inbox.

Subscribe
Manage your subscription

© Qualcomm Technologies, Inc. and/or its affiliated companies.

Snapdragon and Qualcomm branded products are products of Qualcomm Technologies, Inc. and/or its subsidiaries. Qualcomm patented technologies are licensed by Qualcomm Incorporated.

Note: Certain services and materials may require you to accept additional terms and conditions before accessing or using those items.

References to "Qualcomm" may mean Qualcomm Incorporated, or subsidiaries or business units within the Qualcomm corporate structure, as applicable.

Qualcomm Incorporated includes our licensing business, QTL, and the vast majority of our patent portfolio. Qualcomm Technologies, Inc., a subsidiary of Qualcomm Incorporated, operates, along with its subsidiaries, substantially all of our engineering, research and development functions, and substantially all of our products and services businesses, including our QCT semiconductor business.

Materials that are as of a specific date, including but not limited to press releases, presentations, blog posts and webcasts, may have been superseded by subsequent events or disclosures.

Nothing in these materials is an offer to sell or license any of the services or materials referenced herein.