Phantom Interrupts while asleep on AB-01

Hi All,

I am trying to use the small Cubecell board (AB01) for a rain gauge but getting random, phantom counts for some reason.

Hardware

  • Davis tipping bucket rain gauge with two wires, one connected to ground and the other to GPIO0.

Software

  • sketch attached below
  • it uses a combination of the example LoRaWAN and Interrupt sketches.
  • Rain Gauge reed switch is debounced
  • GPIO0 is set as a pullup
  • It counts interrupts while asleep and then wakes up at a set interval to send the count.

Unusual Behaviour

  • Rain gauge will run for days without any issues and then all of a sudden register a few interrupts for no reason (rain gauge is sitting on a bench in a locked office, so no chance of it being bumped), and then register nothing for another few days, and then have a random interrupt count again.

What I have tried

  • I have tried using an external pullup resistor (10K and then 20K - GPIO0 to VDD) but it still happens.
    -also tried several boards, same thing happens

Any ideas would be greatly appreciated.

thanks Paul

/*For a Davis Rain Gauge
 * Red Wire to GPIO0 (interrupt attached)
 * Green wire to Ground
 * interrupt works on falling (pulling to GND)
 * Rain Guage tipping bucket is debounced with 200ms time out
 * Downlink format - send one byte to change send interval = 'byte sent value' X 'txMultiplier'
 */

#include "LoRaWan_APP.h"
#include "Arduino.h"

/*
 * set LoraWan_RGB to Active,the RGB active in loraWan
 * RGB red means sending;
 * RGB purple means joined done;
 * RGB blue means RxWindow1;
 * RGB yellow means RxWindow2;
 * RGB green means received done;
 */

/*the application data transmission duty cycle.  value in [ms].*/
uint32_t appTxDutyCycle = 600000; // Default 10 mins
uint32_t txMultiplier = 300000; 	//Multiplier used for downlink 
#define rainPin GPIO0
int rain = 0;
uint16_t vbat;

/* OTAA para*/
uint8_t devEui[] = {  };
//generic_meshed_testing app
uint8_t appEui[] = {  };
uint8_t appKey[] = {  };

/* ABP para*/ 
uint8_t nwkSKey[] = {  };
uint8_t appSKey[] = {  };
uint32_t devAddr =  ( uint32_t );

/*LoraWan channelsmask, default channels 0-7 - 0xFF00 sets to sub band 2 */
uint16_t userChannelsMask[6]={ 0xFF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};

/*LoraWan region, select in arduino IDE tools*/
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;

/*LoraWan Class, Class A and Class C are supported*/
DeviceClass_t  loraWanClass = LORAWAN_CLASS;

/*OTAA or ABP*/
bool overTheAirActivation = LORAWAN_NETMODE;

/*ADR enable*/
bool loraWanAdr = LORAWAN_ADR;

/* set LORAWAN_Net_Reserve ON, the node could save the network info to flash, when node reset not need to join again */
bool keepNet = LORAWAN_NET_RESERVE;

/* Indicates if the node is sending confirmed or unconfirmed messages */
bool isTxConfirmed = LORAWAN_UPLINKMODE;

/* Application port */
uint8_t appPort = 1;

/* Note, that if NbTrials is set to 1 or 2, the MAC will not decrease
* the datarate, in case the LoRaMAC layer did not receive an acknowledgment
*/
uint8_t confirmedNbTrials = 4;

/* Prepares the payload of the frame */
static void prepareTxFrame( uint8_t port )
{
	uint16_t vbat = getBatteryVoltage();
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.print("Vbat = ");Serial.println(vbat);
  Serial.print("Rain = ");Serial.println(rain);  
    appDataSize = 4;//AppDataSize max value is 64
    appData[0] = highByte(vbat);
    appData[1] = lowByte(vbat);
    appData[2] = highByte(rain);
    appData[3] = lowByte(rain);
}

void setup() {
	boardInitMcu();
	Serial.begin(115200);
#if(AT_SUPPORT)
	enableAt();
#endif
	deviceState = DEVICE_STATE_INIT;
	LoRaWAN.ifskipjoin();
  pinMode(rainPin,INPUT_PULLUP);
  attachInterrupt(rainPin,raincounter,FALLING);
}

void loop()
{
	switch( deviceState )
	{
		case DEVICE_STATE_INIT:
		{
#if(AT_SUPPORT)
			getDevParam();
#endif
			printDevParam();
			LoRaWAN.init(loraWanClass,loraWanRegion);
			deviceState = DEVICE_STATE_JOIN;
			break;
		}
		case DEVICE_STATE_JOIN:
		{
			LoRaWAN.join();
			break;
		}
		case DEVICE_STATE_SEND:
		{
			prepareTxFrame( appPort );
			LoRaWAN.send();
			deviceState = DEVICE_STATE_CYCLE;
			break;
		}
		case DEVICE_STATE_CYCLE:
		{
			// Schedule next packet transmission
			txDutyCycleTime = appTxDutyCycle + randr( 0, APP_TX_DUTYCYCLE_RND );
			LoRaWAN.cycle(txDutyCycleTime);
			deviceState = DEVICE_STATE_SLEEP;
			break;
		}
		case DEVICE_STATE_SLEEP:
		{
			LoRaWAN.sleep();
			break;
		}
		default:
		{
			deviceState = DEVICE_STATE_INIT;
			break;
		}
	}
}

void raincounter() {
 //Debounce switch
      static unsigned long last_interrupt_time = 0;
      unsigned long interrupt_time = millis();
     // If interrupts come faster than 200ms, assume it's a bounce and ignore
      if (interrupt_time - last_interrupt_time > 200)
        {
          rain = rain + 1;
        }
      last_interrupt_time = interrupt_time;
 }

//downlink data handle function
void downLinkDataHandle(McpsIndication_t *mcpsIndication)
{
  Serial.printf("+REV DATA:%s,RXSIZE %d,PORT %d\r\n",mcpsIndication->RxSlot?"RXWIN2":"RXWIN1",mcpsIndication->BufferSize,mcpsIndication->Port);
  Serial.print("+REV DATA:");
  for(uint8_t i=0;i<mcpsIndication->BufferSize;i++) {
    Serial.printf("%02X",mcpsIndication->Buffer[i]);
  }
  Serial.println();

  if (mcpsIndication->BufferSize == 1) {
    Serial.println("Check 1 Byte Message");
    appTxDutyCycle = (mcpsIndication->Buffer[0])*txMultiplier;
    Serial.print("Changing TX Interval to: ");Serial.print(appTxDutyCycle/60000);Serial.println(" mins");
  }
}

Do you have a lengthy cable between the switch and you board ?
How long will the switch be closed when it detects a raindrop ?
Some updates have arrived on github, please update your environment !

Cable is only about 15cm.

It closes for about 0.5secs I suppose, it did need debouncing on this board. But it was recording interrupts when it wasn’t moving at all.

I will make sure I have the latest version of the libraries and test again.

Thanks
Paul

A small capacitor (10 nF) can help can help, but 0.5 seconds is a long closure, can you check in raincounter() if the gpio is actually low or high, just to make sure the function is not called in some other way.
28

try to invert the logik!
attachInterrupt(rainPin,raincounter,RISING);

The switch time is purely a guess, most likely a lot less than that - it’s just a typical tipping bucket

try checking gpio state exit and log when spurious trigger detected

Update: after running two cubecells side by side, I noticed that the phantom interrupts are happening at exactly the same times when they do occur.

This has led me to believe that it is environmental - maybe a fluoro light, or some other types of electrical interference.

I placed one of them outside in the middle of a an open paddock - and that one has been stable since, while the original on my desk has continued to record unexplained interrupts.

So even if there is electrical interference, I wouldn’t have thought that would be enough to trigger an event especially with an external pull up resistor

cheers
Paul

1 Like

another update - I changed to a pull_down circuit and looked for a rising interrupt without any other external resistors and it has been stable ever since

1 Like