Project only runs for about a minute then loses wifi (Solved)

This is the beginning of a garage door opener project. The initial goal is to create a sound and vibration detector which will be used to determine if the opener is currently running. This detector is working for about a minute but then goes from breathing blue to breathing green. This is most advanced project I’ve tried. Am using three sensors. The sound detector sensor is using an IRQ and the other two, vibration sensors, are being polled. Am guessing some kind of badness is occurring because I’m abusing what an IRQ is supposed to do.

/******************************************************************************
 * Based on
 * https://github.com/sparkfun/Sound_Detector
 ******************************************************************************/

#define PIN_ENVELOPE   A1
#define PIN_PIEZOVERT  A3
#define PIN_PIEZOHORIZ A4

#define PIN_GATE       D2

#define PIN_LED        D7

int _irqCnt;
int _gateVal;
int _envelopeVal;

float _vibrateThreshold = 0.75;  //.60 too low
bool _vibration = false;
bool _sound = false;

void soundISR()
{
  _irqCnt++;
  _gateVal = digitalRead(PIN_GATE);

  if (_gateVal == 1)
  {
    _sound = true;
    _envelopeVal = analogRead(PIN_ENVELOPE);
  }
}

void setup()
{
  for (int i = 10; i >= 1; i--)
  {
    Serial.printlnf("%d seconds till start", i);
    delay(1000);
  }

  Serial.begin(9600);

  pinMode(PIN_GATE, INPUT);
  pinMode(PIN_PIEZOVERT, INPUT);
  pinMode(PIN_PIEZOHORIZ, INPUT);

  pinMode(PIN_LED, OUTPUT);

  // any sound over resistor set threshold fires soundISR method
  attachInterrupt(PIN_GATE, soundISR, RISING);
}

void loop()
{
  if (_sound)
  {
    Serial.printlnf
      ("sound irq# %d gate %d, envelope %d", _irqCnt, _gateVal, _envelopeVal);
      _gateVal = 0;
  }

   int piezoVert= analogRead(PIN_PIEZOVERT);
   float piezoV = piezoVert / 1023.0 * 5.0;
   if (piezoV > _vibrateThreshold)
   {
     _vibration = true;
     Serial.printlnf("vert  %f", piezoV);
   }

   int piezoHoriz = analogRead(PIN_PIEZOHORIZ);
   float piezoH = piezoHoriz / 1023.0 * 5.0;
   if (!_vibration && piezoH > _vibrateThreshold)
   {
     _vibration = true;
     Serial.printlnf("horiz %f", piezoH);
   }

   if (_vibration || _sound )
   {
     digitalWrite(PIN_LED, HIGH);
     delay(500);
     digitalWrite(PIN_LED, LOW);
     _vibration = false;
     _sound = false;
   }
}

Console output is proving that the sound and vibration detection is working. But then after about a minute it just stops responding and goes to breathing green and no more events are detected.

C:\Users\joe>particle serial monitor
Opening serial monitor for com port: “COM5”
sound irq# 1 gate 1, envelope 209
sound irq# 4 gate 1, envelope 209
horiz 0.757576
vert 0.796676
horiz 0.757576
vert 2.101662
sound irq# 6 gate 1, envelope 201
vert 1.221896
horiz 0.796676
horiz 0.840665
horiz 0.772238
sound irq# 8 gate 1, envelope 216
vert 5.009775
horiz 0.777126
vert 3.519062
horiz 0.786901
sound irq# 10 gate 1, envelope 232
sound irq# 11 gate 1, envelope 230
horiz 0.762463
sound irq# 13 gate 1, envelope 233
horiz 0.791789
sound irq# 14 gate 1, envelope 234
sound irq# 15 gate 1, envelope 232
vert 2.536657

First, all your variables getting alteredin an ISR should be declared volatile
The ADC resolution on the Photon is 12bit (max. 4095) not 10bit (max. 1023) and the rev voltage is 3.3V not 5V.
Since your ISR is triggered by a RISING edge I don’t see much sense in digitalRead()ing the interrupt pin, you can just take it as being HIGH and to cater for bouncing pins you could set a short blockout periode for the analogRead().

volatile uint32_t usBlockout;
void soundISR()
{
  _irqCnt++;
  _sound = true;
  if(micros()-usBlockout < 2000) return;
  usBlockout = micros();
  _envelopeVal = analogRead(PIN_ENVELOPE);
}

Is analogRead() reentrant? I don’t think it is, and you’re calling it from both soundISR and from loop. I’m not sure if this will work, but it’s worth a try to see if it makes a difference:

   noInterrupts();
   int piezoVert= analogRead(PIN_PIEZOVERT);
   int piezoHoriz = analogRead(PIN_PIEZOHORIZ);
   interrupts();
3 Likes

Thanks for the quick responses. I’m not sure I understand that is meant by “reentrant”. Is is something to do with threads? Also not sure where the analogReads belong - should they be in the loop() and not the IRQ?

The question about reentrancy was more of a question for the experts here.

The thing is that it is safe to call analogRead() from an interrupt service routine. But I don’t think it protects itself from being called from both an interrupt service routine and from loop. Essentially, if you happen to be sampling from loop at the time the ISR fires, the ISR analogRead will interrupt the already in progress loop analogRead and I suspect something bad will happen.

My modification postpones the handling of the interrupt until the main loop analogRead operations are complete.

4 Likes

Thanks to your ideas it’s working now. Thank you! :smiley:

It’s passing my “stress test” where I make a bunch of noises while knocking the board it’s side and top. That kicks off the sound and vibration events in a more or less random manner.

The anlalogRead of the ‘GATE’ pin, which equates to the sound amplitude, is only happening in the loop now. Previously that read was also occurring in the IRQ.

I put the same delay time in the IRQ and the loop() with the idea that this would stop further polling of the the vibration pins once a sound detection occurs. I’m thinking that limiting the analogReads to only what is necessary will help somehow. That delay is set to 500ms which gives a nicer response time.

The voltage for the piezo electric vibration detectors were also adjusted to be the 3.3 V value instead of 5.0.

Next is to add two reed switches to determine if the garage door is open or closed.

     * Based on
     * https://github.com/sparkfun/Sound_Detector
     ******************************************************************************/
    
    #define PIN_ENVELOPE   A1
    #define PIN_PIEZOVERT  A3
    #define PIN_PIEZOHORIZ A4
    
    #define PIN_GATE       D2
    
    #define PIN_LED        D7
    
    volatile int _irqCnt;
    volatile int _envelopeVal;
    
    // setting to a value just above the noise level
    float _vibrateThreshold = 0.125;
    
    bool _vibration = false;
    bool _sound = false;
    
    volatile uint32_t usBlockout;
    void soundISR()
    {
      _irqCnt++;
    
      if(micros()-usBlockout < 500) return;
      _sound = true;
      usBlockout = micros();
    }
    
    float voltage(int analogValueIn)
    {
      return analogValueIn / 4095.0 * 3.3;
    }
    
    void setup()
    {
      for (int i = 5; i >= 1; i--)
      {
        Serial.printlnf("%d seconds till start", i);
        delay(1000);
      }
    
      Serial.begin(9600);
    
      pinMode(PIN_GATE, INPUT);
      pinMode(PIN_PIEZOVERT, INPUT);
      pinMode(PIN_PIEZOHORIZ, INPUT);
    
      pinMode(PIN_LED, OUTPUT);
    
      // any sound over resistor set threshold fires soundISR method
      attachInterrupt(PIN_GATE, soundISR, RISING);
    }
    
    void loop()
    {
      if (_sound)
      {
        _envelopeVal = analogRead(PIN_ENVELOPE);
        Serial.printlnf
          ("sound irq# %d, envelope %d", _irqCnt, _envelopeVal);
      }
    
       float piezoVert= voltage(analogRead(PIN_PIEZOVERT));
       if (piezoVert > _vibrateThreshold)
       {
         _vibration = true;
         Serial.printlnf("vert  %f", piezoVert);
       }
    
       float piezoHoriz = voltage(analogRead(PIN_PIEZOHORIZ));
       if (!_vibration && piezoHoriz > _vibrateThreshold)
       {
         _vibration = true;
         Serial.printlnf("horiz %f", piezoHoriz);
       }
    
       if (_vibration || _sound )
       {
         digitalWrite(PIN_LED, HIGH);
         delay(500);
         digitalWrite(PIN_LED, LOW);
         _vibration = false;
         _sound = false;
       }
    
    }
1 Like

Thanks @rickkas7 @ScruffR for the help!