coniferconifer / ESP32_pulsesensor

ESP32 Arduino IDE version for pulsesensor Amped
MIT License
2 stars 0 forks source link

Incorrect BPM after modified by adding adding wifi coding #1

Closed goldenhenry closed 5 years ago

goldenhenry commented 5 years ago
#include <WiFi.h>
#include <IOXhop_FirebaseESP32.h>

// Set these to run example.
#define FIREBASE_HOST "xxx"
#define FIREBASE_AUTH "xxx"
#define WIFI_SSID "xxx"
#define WIFI_PASSWORD "xxx"

#define PROCESSING_VISUALIZER 1
#define SERIAL_PLOTTER  2

//  Variables
#define ESP32
int pulsePin = 35;                 // Pulse Sensor purple wire connected to analog pin 34 , ADC6
// Volatile Variables, used in the interrupt service routine!
volatile int BPM;                   // int that holds raw Analog in 0. updated every 2mS
volatile int Signal;                // holds the incoming raw data
volatile int IBI = 600;             // int that holds the time interval between beats! Must be seeded!
volatile boolean Pulse = false;     // "True" when User's live heartbeat is detected. "False" when not a "live beat".
volatile boolean QS = false;        // becomes true when Arduoino finds a beat.
static int outputType = SERIAL_PLOTTER;

volatile int rate[10];                    // array to hold last ten IBI values
volatile unsigned long sampleCounter = 0;          // used to determine pulse timing
volatile unsigned long lastBeatTime = 0;           // used to find IBI
volatile int P = 512;                     // used to find peak in pulse wave, seeded
volatile int T = 512;                     // used to find trough in pulse wave, seeded
volatile int thresh = 530;                // used to find instant moment of heart beat, seeded
volatile int amp = 0;                   // used to hold amplitude of pulse waveform, seeded
volatile boolean firstBeat = true;        // used to seed rate array so we startup with reasonable BPM
volatile boolean secondBeat = false;      // used to seed rate array so we startup with reasonable BPM
int getpr = 0;
int newbpmstatus = 0, oldbpmstatus = 0, bpmalertcountdown = 0;

hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR onTimer() {
  portENTER_CRITICAL_ISR(&timerMux);          // cli();
  portEXIT_CRITICAL_ISR(&timerMux);
  // Give a semaphore that we can check in the loop
  xSemaphoreGiveFromISR(timerSemaphore, NULL);
  // It is safe to use digitalRead/Write here if you want to toggle an output
}// end isr

void getPulse()
{
  Signal = analogRead(pulsePin) / 4;          // read the Pulse Sensor, bits of ESP32 ADC ch is 4 times larger
  sampleCounter += 2;                         // keep track of the time in mS with this variable
  int N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise

  //  find the peak and trough of the pulse wave
  if (Signal < thresh && N > (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
    }
  }

  if (Signal > thresh && Signal > P) {        // thresh condition helps avoid noise
    P = Signal;                             // P is the peak
  }                                        // keep track of highest point in pulse wave

  //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  // signal surges up in value every time there is a pulse
  if (N > 250) {                                  // avoid high frequency noise
    if ( (Signal > thresh) && (Pulse == false) && (N > (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++) {       // seed the running total to get a realisitic BPM at startup
          rate[i] = IBI;
        }
      }

      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
        sei();                               // enable interrupts again
        return;                              // IBI value is unreliable so discard it
      }

      // keep a running total of the last 10 IBI values
      word runningTotal = 0;                  // clear the runningTotal variable

      for (int i = 0; i <= 8; i++) {          // shift data in the rate array
        rate[i] = rate[i + 1];                // 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!
      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 (N > 2500) {                          // if 2.5 seconds go by without a beat
    thresh = 530;                          // 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
    QS = false;
    BPM = 0;
    IBI = 600;                  // 600ms per beat = 100 Beats Per Minute (BPM)
    Pulse = false;
    amp = 100;                  // beat amplitude 1/10 of input range.

  }
}

void interruptSetup() { // CHECK OUT THE Timer_Interrupt_Notes TAB FOR MORE ON INTERRUPTS
  timerSemaphore = xSemaphoreCreateBinary();
  timer = timerBegin(0, 80, true);    // Use 1st timer of 4 (counted from zero).Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more info).
  timerAttachInterrupt(timer, &onTimer, true);// Attach onTimer function to our timer.
  timerAlarmWrite(timer, 2000, true);// Set alarm to call onTimer function every second (value in microseconds). Repeat the alarm (third parameter)
  timerAlarmEnable(timer);// Start an alarm
}

void setup() {
  Serial.begin(115200);             // we agree to talk fast!
  interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

//  Where the Magic Happens
void loop() {
  if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE)
  {
    getPulse();
  }
  if (BPM != 0 && BPM >= 60 && BPM <= 100)
  {
    newbpmstatus = 1;
  }
  else
  {
    newbpmstatus = 0;
  }
  if (newbpmstatus == oldbpmstatus) //comparing last bpm status
  {
    if (newbpmstatus == 0) //check if thestatus is bad or not
    {
      bpmalertcountdown++;//countdown to alert
    }
    else
    {
      bpmalertcountdown = 0; //recount
    }
    if (bpmalertcountdown == 100)
    {
      Serial.print("GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
      bpmalertcountdown = 0;
    }
  }
  oldbpmstatus = newbpmstatus;
  Serial.print(BPM);
  Serial.print(",");
  Serial.print(IBI);
  Serial.print(",");
  Serial.println(Signal);
  if (QS == true) {    // A Heartbeat Was Found
    // BPM and IBI have been Determined
    // Quantified Self "QS" true when arduino finds a heartbeat
    QS = false;                      // reset the Quantified Self flag for next time
  }
  delay(20);                             //  take a break
}

I had tried the code. It was working perfectly before I add the wifi coding. After I add the wifi coding I had error on my ESP32 and keep rebooting. The error messages:


Guru Meditation Error: Core  1 panic'ed (Cache disabled but cached memory region accessed)
Register dump:
PC      : 0x400812d1  PS      : 0x00060034  A0      : 0x800810af  A1      : 0x3ffc0b70  
A2      : 0x00000023  A3      : 0x000000c0  A4      : 0x8008244d  A5      : 0x3ffd0960  
A6      : 0x00000000  A7      : 0x00000001  A8      : 0x3f40226c  A9      : 0x000000c0  
A10     : 0xbad00bad  A11     : 0x00000018  A12     : 0x80082a7e  A13     : 0x3ffd0940  
A14     : 0x00000001  A15     : 0x3ffc3afc  SAR     : 0x00000014  EXCCAUSE: 0x00000007  
EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000  

Backtrace: 0x400812d1:0x3ffc0b70 0x400810ac:0x3ffc0b90 0x40081225:0x3ffc0bb0 0x40080ec1:0x3ffc0bd0 0x4008163d:0x3ffc0bf0 0x40081b19:0x3ffc0c10 0x4000bfed:0x00000000
Rebooting...
ets Jun  8 2016 00:22:57 
rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:956
load:0x40078000,len:0
load:0x40078000,len:13076
entry 0x40078a58

I did research and someone mentioned that the analogread cannot put inside the interrupt function. I followed the idea and the esp32 running well again. However, it is not getting correct pulse rate now, the BPM is always more than 100 and even get to 200++. I am not good at coding. I hope I can get help. Pls kindly inform me if there is any insufficient information to be given.

chermdev commented 5 years ago

I have the same problem, any solution?

Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1)
Core 1 register dump:
PC : 0x40084b86 PS : 0x00060034 A0 : 0x80084d86 A1 : 0x3ffb1680
A2 : 0x3ffd207c A3 : 0x3ffd242c A4 : 0x00000020 A5 : 0x3ffd20ec
A6 : 0x00000001 A7 : 0x00000002 A8 : 0x3ffb63d0 A9 : 0x3ffb6388
A10 : 0x3ffc7388 A11 : 0x3ffd24a0 A12 : 0x3ffd23d0 A13 : 0x3ffd2470
A14 : 0x3ffd2421 A15 : 0x3ffd2471 SAR : 0x0000001f EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0x00000000

Backtrace: 0x40084b86:0x3ffb1680 0x40084d83:0x3ffb16a0 0x40084fe1:0x3ffb16c0 0x400f29ca:0x3ffb16e0 0x400fd623:0x3ffb1700 0x401024cf:0x3ffb1720 0x40102671:0x3ffb17a0 0x4010281f:0x3ffb1800 0x40102ca5:0x3ffb1980 0x40102eaa:0x3ffb19a0 0x40102ecf:0x3ffb19d0 0x401003e5:0x3ffb19f0 0x401005a4:0x3ffb1a10 0x40109555:0x3ffb1a30 0x40109b48:0x3ffb1a60 0x400f9a81:0x3ffb1a80 0x400f9ac1:0x3ffb1aa0 0x400d52a9:0x3ffb1ac0 0x400d4da5:0x3ffb1d30 0x400d4e65:0x3ffb1d60 0x400d47da:0x3ffb1d80 0x400d4839:0x3ffb1db0 0x400d48fb:0x3ffb1df0 0x400d252a:0x3ffb1e10 0x400d26f1:0x3ffb1ee0 0x400d2756:0x3ffb1f30 0x400d1e86:0x3ffb1f60 0x400d1ff3:0x3ffb1f90 0x400d77b1:0x3ffb1fb0 0x4008f429:0x3ffb1fd0

Core 0 register dump:
PC : 0x40163052 PS : 0x00060a34 A0 : 0x800dd011 A1 : 0x3ffbc2c0
A2 : 0x00000000 A3 : 0x00000001 A4 : 0x00000000 A5 : 0x00000001
A6 : 0x00060820 A7 : 0x00000000 A8 : 0x800decbe A9 : 0x3ffbc290
A10 : 0x00000000 A11 : 0x00000001 A12 : 0x8008f63c A13 : 0x3ffb77b0
A14 : 0x00000000 A15 : 0x3ffbbfc0 SAR : 0x00000000 EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000

Backtrace: 0x40163052:0x3ffbc2c0 0x400dd00e:0x3ffbc2e0 0x40091301:0x3ffbc300 0x4008f429:0x3ffbc320

Rebooting...
ets Jun 8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:10208
load:0x40080400,len:6460
entry 0x400806a4
goldenhenry commented 5 years ago

@CharlyEH do you have your code? I solved my problem by taking out analogread in the interrupt function.

goldenhenry commented 5 years ago

@CharlyEH Problem solved by taking out timer interrupt function and call with

void IRAM_ATTR getpulse()