AS3935 stops working if I (re-)set spike rejection etc

I have a lightning detector box, and while the as3935 works, I have run into the following issue:

If (in order to change 'sensitivity' on the fly) I change the spike rejection or minimum lightnings values anywhere in the main loop (i.e. after the device is running), it stops detecting altogether. Whichever way I adjust it.

I am checking whether it should be adjusted once a second (depends on a switch position), and if the switch has been changed to HIGH I do:

as3935.writeSpikeRejection(AS3935MI::AS3935_SREJ_2);  // Spike rejection, ...SREJ_2 default
as3935.writeMinLightnings(AS3935MI::AS3935_MNL_1);    // minimum lightnings in 15 min = 1

And when the switch has been changed to LOW, I execute the same code but with values 3 and 5, respectively.

But whatever I do, the detector stops detecting.

Of course I am executing these same commands in the SETUP area of my sketch, just before the loop is activated, and it works fine there...

Any suggestions??

After you issue the command to change can you kill a few milliseconds to allow it to settle?

That's a good idea. I did not think it was necessary because in the setup code there's no pause after setting these parameters, but it cannot hurt to try that. Will do.

Without your code I can only assume you did some othering things that took a bit of time. You might want to make these functions then you know they are absolutely the same. Are you using I2C or SPI, just curious.

I use I2C.

Thanks, let us know how you do. Be sure the pull up resistors are reasonable on the I2C, many modules have them built in and forget to note it.

Will do. Right now I am watching the machine (I took out those lines) as a thunderstorm front is approaching Ottawa right now: will await that first! :slight_smile:

Funny thing: it's very hard to test this detector in real life because well, you need a thunderstorm. I can set off Disturber alerts easily: when I turn one of my ham radios on (just the act of turning it on) it reliably generates a Disturber. But for lightning I need lightning...

Since you asked: code in progress:

// LightningDetector_Boxed.ino
// Based on AS3935MI_LightningDetector_I2C.ino by Gregor Christandl
// (Use AS3935MI library with the lightning sensor connected using I2C)
// Lightning detector without display, using only buzzer and LEDs.
//
// Current code: Michael Willems, michael@willems.ca
// Rev 1.3, 2021-07-24
//
// Connect the AS3935 to the Arduino like this (using short as possible connections):
// Arduino - AS3935
// 5V ------ VCC
// GND ----- GND
// D2 ------ IRQ		Pin supporting external interrupts, e.g. D2 or D3 on an Arduino Uno.
// SDA ----- MOSI   A4 on an Arduino Uno
// SCL ----- SCL    A5 on an Arduino Uno
// 5V ------ SI		  (activates I2C for the AS3935)
// 5V ------ A0		  (sets the AS3935' I2C address to 0x11)   // <--(board does this)
// 5V -----  A1		  (sets the AS3935' I2C address to 0x11)    //<--(board does this)
// 5V ------ EN_VREG !IMPORTANT when using 5V Arduinos (Uno, Mega2560, ...) //<--(board does this)
// other pins left unconnected.


//---------------------------------------------------------------------------------------------------
// INCLUDES AND DEFINITIONS:
//---------------------------------------------------------------------------------------------------

//The  Lighning Detector stuff:
#include <Arduino.h>
#include <Wire.h>
#include <AS3935I2C.h>        // the detector board's library
#define PIN_IRQ 2

//create an AS3935 object using the I2C interface, I2C address 0x11 and IRQ pin 2:
AS3935I2C as3935(AS3935I2C::AS3935I2C_A11, PIN_IRQ);
volatile bool interrupt_ = false;  //this value will be set to true by the AS3935 interrupt service routine.

//The Rest:
unsigned long counter;        // for flashing on-board LED 13 with 1s frequency
unsigned long yellowcounter;  // for brief yellow flash (= disturber/QRM or noise/QRN)
unsigned long bluecounter;    // for brief blue flash (= lightning) - may be replaced by white LED...
byte sw3up = 3;
byte sw3upBefore = 3;
byte lowsens = 3;
int flashactive = 0;
int stormdist = 0;            // Distance to storm as reported by the chip
int heartbeat = 13;           // for LED 13 slow flash to indicate alive
int green = 3;                // "passed tests and operating" LED
int red = 4;                  // error LED
int yellow = 5;               // Disturber LED
int blue = 6;                 // Lightning LED, can also be white ;-)
int pushbutton = 7;           // to reset the blue latch LED
int beeper = 8;
int redbar1 = 9;
int redbar2 = 10;
int redbar3 = 11;
int redbar4 = 12;

void(* resetFunc) (void) = 0; // Reset function, to reset after a week (recalibrate, [& avoid millis rollover])

//---------------------------------------------------------------------------------------------------
// SETUP (RUNS ONCE):
//---------------------------------------------------------------------------------------------------

void setup() {
	Serial.begin(9600);
  pinMode (heartbeat, OUTPUT);
  pinMode (red,OUTPUT);
  pinMode (green,OUTPUT);
  pinMode (yellow,OUTPUT);
  pinMode (blue,OUTPUT);
  pinMode (pushbutton, INPUT_PULLUP);
  pinMode (beeper, OUTPUT);
  pinMode (redbar1,OUTPUT);
  pinMode (redbar2,OUTPUT);
  pinMode (redbar3,OUTPUT);
  pinMode (redbar4,OUTPUT);
  pinMode (A1, INPUT);  //switch 1: on/off
  pinMode (A2, INPUT);  //switch 2: enable beep
  pinMode (A3, INPUT);  //switch 3: spare

  digitalWrite (green, HIGH);
  digitalWrite (red, HIGH);
  digitalWrite (yellow, HIGH);
  digitalWrite (blue, HIGH);
  digitalWrite (redbar1, HIGH);
  digitalWrite (redbar2, HIGH);
  digitalWrite (redbar3, HIGH);
  digitalWrite (redbar4, HIGH);
  delay(1000);
  digitalWrite (green, LOW);
  digitalWrite (red, HIGH);   // Red LED stays on, to indicate initializing phase.
  digitalWrite (yellow, LOW);
  digitalWrite (blue, LOW);
  digitalWrite (redbar1, LOW);
  digitalWrite (redbar2, LOW);
  digitalWrite (redbar3, LOW);
  digitalWrite (redbar4, LOW);

	while (!Serial);          //wait for serial connection to open (only for testing)

	//set the IRQ pin as an input pin. Do not use INPUT_PULLUP.
	pinMode(PIN_IRQ, INPUT);
	Wire.begin();

  // Now we check that the detector is on, connected and functioning:
  
	// begin() checks Interface and I2C Address passed to the constructor & resets AS3935 to defaults.
	if (!as3935.begin())
	{
		Serial.println("begin() failed. Check I2C address passed to the AS3935I2C constructor. ");
    flashred(1);    // flash red LED once
		while (1);
	}
 
	//check I2C connection:
	if (!as3935.checkConnection())
	{
		Serial.println("checkConnection() failed. Check I2C connection and I2C Address. ");
    flashred(2);    // flash red LED 2x: I2C Failed
		while (1);
	}
	else {
  	Serial.println("I2C connection check passed. ");
  }

	//check the IRQ pin connection:
	if (!as3935.checkIRQ())
	{
		Serial.println("checkIRQ() failed. check if the correct IRQ pin was passed to the AS3935I2C constructor. ");
    flashred(3);    // flash red LED 3x: IRQ failed.
		while (1);
	}
	else {
		Serial.println("IRQ pin connection check passed. ");
  }

	//calibrate the resonance frequency. failing the resonance frequency could indicate an issue 
	//of the sensor. resonance frequency calibration will take about 1.7 seconds to complete.
	int32_t frequency = 0;
	if (!as3935.calibrateResonanceFrequency(frequency))
	{
		Serial.print("Resonance Frequency Calibration failed: is "); 
		Serial.print(frequency);
		Serial.println(" Hz, should be 482500 Hz - 517500 Hz");
    flashred(4);      // flash red LED 4x: Calibrating resonance freq. failed.
		while (1);
	}
	else {
		Serial.println("Resonance Frequency Calibration passed. ");
  }

	Serial.print("Resonance Frequency is "); Serial.print(frequency); Serial.println(" Hz");

	//calibrate the RCO.
	if (!as3935.calibrateRCO())
	{
		Serial.println("RCO Calibration failed. ");
    flashred(5);        // flash red LED 5x: Calibrating RCO failed.
		while (1);
	}
	else{
		Serial.println("RCO Calibration passed. ");    
  }

	//set the analog front end to 'indoors'
	as3935.writeAFE(AS3935MI::AS3935_INDOORS);

	//set default value for noise floor threshold
	as3935.writeNoiseFloorThreshold(AS3935MI::AS3935_NFL_2);    // Noise Floor, ...NFL_2 Default

	//set the default Watchdog Threshold
	as3935.writeWatchdogThreshold(AS3935MI::AS3935_WDTH_2);     // Watchdog Threshold, ...WDTH_2 default

	//set the default Spike Rejection 
	as3935.writeSpikeRejection(AS3935MI::AS3935_SREJ_2);        // Spike rejection, ...SREJ_2 default

	//write default value for minimum lightnings (1)
	as3935.writeMinLightnings(AS3935MI::AS3935_MNL_1);

	//mask disturbers or not
	as3935.writeMaskDisturbers(false);

	//the AS3935 will pull the interrupt pin HIGH when an event is registered and will keep it 
	//pulled high until the event register is read.
	attachInterrupt(digitalPinToInterrupt(PIN_IRQ), AS3935ISR, RISING);

	Serial.println("Initialization complete, waiting for events...");
  digitalWrite(red,LOW);   // turn off red "initializing" LED
  digitalWrite(green,HIGH);   // turn on green LED to indicate passed test; operating now.
  counter = millis();
  
  digitalWrite (beeper, HIGH);
  delay(5);
  digitalWrite (beeper, LOW);
  delay(500);  //now we're all set to start.
}

//---------------------------------------------------------------------------------------------------
// LOOP (LOOPS CONTINUOUSLY):
//---------------------------------------------------------------------------------------------------
void loop() {
  //
  // we stay in this loop until an interrupt happens.
  //
  if (millis() > 604800000) {    //reset after a week: recalibrate filter [& avoid millis rollover]
    resetFunc();  
  }
  
  if (digitalRead(A1) == HIGH) {   //if switch 1 is high, we are asleep, so: exit. We loop like this until 
    digitalWrite (green, LOW);
    return;
  }
  else {
    digitalWrite (green, HIGH);
  }

  if ((millis() - counter) > 1000) {      // we do our "once a second" stuff
    counter = millis();
    digitalWrite (heartbeat,!(digitalRead(heartbeat))); //flash on board LED on/off slowly (running check):
    //
    // Now we check if sw3 has changed position: 
    // If so, change sensitivity accordingly ("up" = high)
    //
    // check sw3 position:
    if (digitalRead(A3) == HIGH) {
      sw3up = 0;
    }
    else {
      sw3up = 1;
    }
    // now check if it is time to check if sw3 has changed:
    if (sw3up != sw3upBefore) {
      //do whatever, the state has changed
      if (sw3up == 1) {
        //make it sensitive
        digitalWrite (blue, HIGH);
        delay (100);
        digitalWrite (blue, LOW);
        lowsens=0; //right now, does not do anything...
    //    as3935.writeSpikeRejection(AS3935MI::AS3935_SREJ_2);  // Spike rejection, ...SREJ_2 default
    //    as3935.writeMinLightnings(AS3935MI::AS3935_MNL_1);    // minimum lightnings in 15 min = 1
      }
      else {
        //make it less sensitive
        digitalWrite (red, HIGH);
        delay (100);
        digitalWrite (red, LOW);
        lowsens=1; //right now, does not do anything...
    //    as3935.writeSpikeRejection(AS3935MI::AS3935_SREJ_3);  // Spike rejection, ...SREJ_2 default
    //    as3935.writeMinLightnings(AS3935MI::AS3935_MNL_5);    // minimum lightnings in 15 min = 5      
      }
      //now reset the switch 3 watchdog:
      if (digitalRead(A3) == HIGH) {
        sw3up = 0;
        sw3upBefore = 0;
      }
      else {
        sw3up = 1;
        sw3upBefore = 1;
      }  
    } //ok, we have set sensitivity if needed (if switch changed).   
  }
  if ((millis() - yellowcounter) > 50) {      // if yellow LED is on, turn it off after 50ms
    digitalWrite (yellow,LOW);
  }
  // "check for pushbutton and if it is pushed, turn off blue"
  if ((millis() - bluecounter) > 50) {        // if buzzer is on, turn it off after 50ms
    digitalWrite(beeper, LOW); //turn off buzzer
  }
  if (digitalRead(pushbutton) == LOW) {
    digitalWrite (blue,LOW);
  }

  if (interrupt_) {
		//the Arduino should wait at least 2ms after the IRQ pin has been pulled high
		delay(2);
	  //reset the interrupt variable:
		interrupt_ = false;
		//query the interrupt source from the AS3935:
		uint8_t event = as3935.readInterruptSource();
    if (event == AS3935MI::AS3935_INT_NH){
      // NOISE/QRN
      yellowcounter = millis();
      digitalWrite(yellow,HIGH);
      Serial.print("QRN INTERRUPT: ");
      Serial.print(event);
      Serial.print(" at ");
      Serial.println (millis());
    }
    else if (event == AS3935MI::AS3935_INT_D) {
      // DISTURBER/QRM
      yellowcounter = millis();
      digitalWrite(yellow,HIGH);
      Serial.print("QRM INTERRUPT: ");
      Serial.print(event);
      Serial.print(" at ");
      Serial.println (millis());
    }
    else if (event == AS3935MI::AS3935_INT_L) {
      //LIGHTNING DETECTED
      stormdist = (as3935.readStormDistance());
      // Now let's display the bar to indicate distance (more LEDs is closer):
      if (stormdist <11) {
        displaybar (4);             // close by, flash 4 bar LEDS
      }
      else if (stormdist < 21) {
        displaybar (3);             // kinda close, flash 3 bar LEDs
      }
      else if (stormdist < 31) {
        displaybar (2);             // not that clase; flash 2 bar LEDs
      } 
      else {
        displaybar (1);             // not close, so flash 1 bar LED 
      }
      digitalWrite(blue,HIGH);      // turn on blue LED (until button pressed)
      Serial.print("LIGHTNING INTERRUPT! ");
      Serial.print(stormdist);
			Serial.print("km away, at ");
      Serial.println (millis());
    }
    else {
      //UNKNOWN EVENT
      yellowcounter = millis();
      digitalWrite(yellow,HIGH);
      Serial.print("UNKNOWN INTERRUPT: ");
      Serial.println(event);
    }
  }
}


//---------------------------------------------------------------------------------------------------
// FUNCTIONS:
//---------------------------------------------------------------------------------------------------

//-----------------------------------------------
// ISR (interrupt service routine). this function 
// is called each time the AS3935 reports
// an event by pulling the IRQ pin high.
//-----------------------------------------------
#if defined(ESP32)
ICACHE_RAM_ATTR void AS3935ISR()
{
  interrupt_ = true;
}
#elif defined(ESP8266)
ICACHE_RAM_ATTR void AS3935ISR()
{
  interrupt_ = true;
}
#else               //we're using an Arduino Uno, etc
void AS3935ISR()
{
  interrupt_ = true;
}
#endif


//-----------------------------------------------
//Flash the red LED "a" times, and repeat 10 
// times, to indicate error condition:
//-----------------------------------------------
void flashred (int a) {
  for (int r=0; r<10; r++) {
    for (int i=0; i<a; i++) {
      digitalWrite(red, HIGH);
      delay(250);
      digitalWrite(red, LOW);
      delay(250);
    }
    delay(2000); 
  }
}

//-----------------------------------------------
//display the bar graph (1-4)
//-----------------------------------------------
void displaybar (int a) {
  digitalWrite (redbar1, LOW);
  digitalWrite (redbar2, LOW);
  digitalWrite (redbar3, LOW);
  digitalWrite (redbar4, LOW);
  if (a<1) {
    a=1;
  }
  if (a>4) {
    a=4;
  }
  if (a==1) {
    digitalWrite (redbar1, HIGH);    
  }
  else if (a==2) {
    digitalWrite (redbar1, HIGH);
    delay (4);
    digitalWrite (redbar2, HIGH);
  }
  else if (a==3) {
    digitalWrite (redbar1, HIGH);
    delay(4);
    digitalWrite (redbar2, HIGH);
    delay(4);
    digitalWrite (redbar3, HIGH);
  }
  else if (a==4) {
    digitalWrite (redbar1, HIGH);
    delay(4);
    digitalWrite (redbar2, HIGH);
    delay(4);
    digitalWrite (redbar3, HIGH);
    delay(4);
    digitalWrite (redbar4, HIGH);
  }
  if (digitalRead(A2)==LOW) {
    digitalWrite (beeper, HIGH);
    delay(100);
    digitalWrite (beeper, LOW);
  }
  delay(380);
  digitalWrite (redbar4, LOW);
  delay(140);
  digitalWrite (redbar3, LOW);
  delay(200);
  digitalWrite (redbar2, LOW);
  delay(260);
  digitalWrite (redbar1, LOW);
}