int main(void) { setupLEDs(); for(;;){ _delay_ms(500.0); setGreenLED(); clrRedLED(); _delay_ms(500.0); clrGreenLED(); setRedLED(); } }
/**************************************************************************//** * @brief The Heart Rate Monitor loop * It implements the main state machine. *****************************************************************************/ bool HeartRateMonitor_Loop( bool displaySpO2, bool forceStop, bool checkSkinContact ) { static int32_t hrmStatus; int16_t heartRate; int16_t spo2; static HRMSpO2State_t state = HRM_STATE_IDLE; // stores the main state of the state machine HANDLE si114xHandle; int32_t skinDetect = 0; si114xhrm_GetLowLevelHandle(hrmHandle, &si114xHandle); static bool updateDisplay = false; // flag to save when display needs to update if (forceStop && state!=HRM_STATE_IDLE) { // main application sets forceStop to true to force the HRM algo to quit*/ state = HRM_STATE_IDLE; stopHRM (); checkSkinContact = false; } if(state == HRM_STATE_IDLE) { /* * in the idle state we periodically check for skin contact * and if detected start the algorithm */ resetInactiveTimer(); if (checkSkinContact) si114xhrm_DetectSkinContact(hrmHandle, &skinDetect); if (skinDetect) { state = HRM_STATE_NOSIGNAL; #ifdef USB_DEBUG if (USBDebug_IsUSBConfigured()) { configMessage[0] = 0x43; //Configuration message starts with ASCII C USBDebug_ProcessConfigurationMessage(configMessage+1, currentHRMConfig); si114xhrm_OutputDebugMessage(hrmHandle, (int8_t*)configMessage); } #endif // start the algorithm si114xhrm_Run(hrmHandle); } else return false; } // call the main HRM algorithm processing function #ifdef USB_DEBUG if(si114xhrm_Process(hrmHandle, &heartRate, &spo2, &hrmStatus, &hrmData) == SI114xHRM_SUCCESS) { #else if(si114xhrm_Process(hrmHandle, &heartRate, &spo2, &hrmStatus, 0) == SI114xHRM_SUCCESS) { #endif // when STATUS_FRAME_PROCESSED is set new data is available if (hrmStatus&SI114xHRM_STATUS_FRAME_PROCESSED) { hrmStatus &= ~SI114xHRM_STATUS_FRAME_PROCESSED; #ifdef USB_DEBUG debugMessage[0] = 0x44; //Debug message starts with ASCII D sprintf(debugMessage+1, "Fs = %hd, Pi = %hu, Status = %ld, Pulse = %hdbpm, SpO2 = %hd%%", hrmData.Fs, hrmData.spo2IrPerfusionIndex, hrmStatus, heartRate, spo2); si114xhrm_OutputDebugMessage(hrmHandle, (int8_t*)debugMessage); #endif // process error codes heartRateStateMachine(&state,hrmStatus); // if heart rate is valid save the value if (state == HRM_STATE_ACTIVE) displayHeartRateValue = heartRate; // if we want to display SpO2 check the SpO2 status too*/ if (displaySpO2) { spo2StateMachine(&state,hrmStatus); // if spo2 value is valid save the value if (state == HRM_STATE_ACTIVE) displaySpo2Value = spo2; } // if data is invalid start a timeout if (state == HRM_STATE_INVALID) { enableInvalidTimer = true; // when timeout expires clear old data if(invalidTimeout == true) { state = HRM_STATE_IDLE; stopHRM (); resetInvalidTimer(); } } // update the display when we get new data*/ updateDisplay = true; } } if ( (updateDisplay) && (HeartRateMonitor_SamplesPending () == false) ) { HeartRateMonitor_UpdateDisplay(state, displaySpO2); updateDisplay = false; } // this timeout turns off the red led to produce the flash effect if (redLEDTimeout) { redLEDTimeout = false; setRedLED(false); } return ( state!=HRM_STATE_IDLE ); } /**************************************************************************//** * @brief Update the display based on the HRM state *****************************************************************************/ static void HeartRateMonitor_UpdateDisplay(HRMSpO2State_t state, bool displaySpO2) { bool showWait = false; int t; if (displaySpO2) t = displaySpo2Value; else t = displayHeartRateValue; if (bufferOverrunError) { GRAPHICS_DrawError (); } else { switch(state) { case HRM_STATE_IDLE: case HRM_STATE_NOSIGNAL: setRedLED(false); setGreenLED(false); resetInvalidTimer(); break; case HRM_STATE_ACQUIRING: // flash red led setRedLED(true); showWait = true; enableInvalidTimer = true; break; case HRM_STATE_ACTIVE: setGreenLED(true); resetInvalidTimer(); break; case HRM_STATE_INVALID: if (t == 0) { showWait = true; setRedLED(true); setGreenLED(false); } break; } if (displaySpO2) GRAPHICS_ShowSpO2Status(showWait, displaySpo2Value, false); else GRAPHICS_ShowHRMStatus(showWait, displayHeartRateValue, false); } }
/**************************************************************************//** * @brief This function enables the 100us timer for HRM. *****************************************************************************/ static void startTimer () { // Enable clock for TIMER module CMU_ClockEnable(CLK_HRM_TIMER1, true); CMU_ClockEnable(CLK_HRM_TIMER2, true); TIMER_Reset(HRM_TIMER1); TIMER_Reset(HRM_TIMER2); // Select TIMER parameters TIMER_Init_TypeDef timerInit1 = { .enable = true, .debugRun = true, .prescale = timerPrescale1, .clkSel = timerClkSelHFPerClk, .fallAction = timerInputActionNone, .riseAction = timerInputActionNone, .mode = timerModeUp, .dmaClrAct = false, .quadModeX4 = false, .oneShot = false, .sync = false, }; TIMER_Init_TypeDef timerInit2 = { .enable = true, .debugRun = true, .prescale = timerPrescale1, .clkSel = timerClkSelCascade, .fallAction = timerInputActionNone, .riseAction = timerInputActionNone, .mode = timerModeUp, .dmaClrAct = false, .quadModeX4 = false, .oneShot = false, .sync = false, }; // Set TIMER Top value TIMER_TopSet(HRM_TIMER1, CMU_ClockFreqGet(cmuClock_HF)/1/10000); /*overflow every 100us*/ TIMER_TopSet(HRM_TIMER2, 0xffff); /*max 16 bits*/ // Configure TIMER TIMER_Init(HRM_TIMER1, &timerInit1); TIMER_Init(HRM_TIMER2, &timerInit2); } /**************************************************************************//** * @brief Initiate the Heart Rate Monitor *****************************************************************************/ void HeartRateMonitor_Init( Si114xPortConfig_t* i2c, HeartRateMonitor_Config_t configSelect ) { // Setup SysTick Timer for 10msec interrupts. if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 100)) while (1) ; // Setup Timer as 100 usec counter. The HRM API requires a 100usec timestamp. startTimer (); dataStorage.spo2 = &spo2Data; dataStorage.hrm = &hrmDataStorage; hrmHandle = &dataStorage; si114xhrm_Initialize(i2c, 0, &hrmHandle); if (configSelect == BIOMETRIC_EXP) { si114xhrm_Configure(hrmHandle, &biometricEXPHRMConfig); currentHRMConfig = &biometricEXPHRMConfig; } else if (configSelect == SI1143_PS) { si114xhrm_Configure(hrmHandle, &Si1143PsHRMConfig); currentHRMConfig = &Si1143PsHRMConfig; } else if (configSelect == SI1147_PS) { si114xhrm_Configure(hrmHandle, &Si1147PsHRMConfig); currentHRMConfig = &Si1147PsHRMConfig; } //turn off LEDs setRedLED (false); setGreenLED (false); bufferOverrunError = false; displayHeartRateValue = 0; displaySpo2Value = 0; HeartRateMonitor_UpdateDisplay(HRM_STATE_NOSIGNAL, false); } /**************************************************************************//** * @brief Check for samples in irq queue *****************************************************************************/ bool HeartRateMonitor_SamplesPending () { HANDLE si114xHandle; si114xhrm_GetLowLevelHandle(hrmHandle, &si114xHandle); return (Si114xIrqQueueNumentries(si114xHandle)>0); } /**************************************************************************//** * @brief Reset inactive timer values *****************************************************************************/ static void resetInactiveTimer() { enableInactiveTimer = false; inactiveTimeout = false; inactiveTimerCounter = 0; }