Unstable rising interrupt (Feather M0 datalogger)

Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
mm7
 
Posts: 18
Joined: Mon Jan 15, 2018 2:37 pm

Unstable rising interrupt (Feather M0 datalogger)

Post by mm7 »

Hi,
I am trying to get button input to navigate little GUI and control the device.
Program should recognize duration of button was pressed. Like short presses "clicks" and long presses.
I have no problems with catching "just a press" interrupts with configuring it to to FALLING mode. Port is INPUT_PULLUP.
This way it reliably detects when button was pressed down, shorting a pin to ground.
However when I try to capture a moment when button was released (with CHANGE mode), it works, but not always reliably.
Sometimes it misses button releases, sometimes it calls multiple interrupts for a single button release. Randomly.
Reading the pin inside the interrupt function (CHANGE mode), to get its state LOW or HIGH, also work unreliably when button is released.

Code: Select all

#include <Arduino.h>

volatile ulong b5d=0, b5u=0;

String output="";

void change5() {
        unsigned long m = millis();
        int r=digitalRead(5);
        output += "change_5:";

        if (r == HIGH) b5u=m;
        else b5d=m;

        if (r == HIGH) {
                ulong x = b5u-b5d;
                output += " down:"+String(b5d)+" up:"+String(b5u)+" dur:"+String(x)+"\n";
        }
        else output += "\n";
}


void setup(){
        Serial.begin(9600);
        delay(2000);

        pinMode(5, INPUT_PULLUP);
        attachInterrupt(digitalPinToInterrupt(5), change5, CHANGE);
}


int i=0;

void loop(){
  noInterrupts(); // String is not volatile, disable interrupts while accessing it
  if (output!=""){
     Serial.print(output);
     output="";
  }
  interrupts();
  i++;
  delay(500);
}
I thought that pins do not have pullup resistors, that makes pin floating unstable, but according to docs they do have pullups.

Please help.

Thanks,
Mark

User avatar
Franklin97355
 
Posts: 23910
Joined: Mon Apr 21, 2008 2:33 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by Franklin97355 »

It may be button bounce. mechanical devices don't operate as fast as electronics and can be read as multiple open/close operations by the processor.

User avatar
bigwheels
 
Posts: 13
Joined: Sun Dec 17, 2017 11:30 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by bigwheels »

You can test if it's a problem with the physical button (e.g. button bounce per franklin's suggection) by sending an output pulse - e.g. using digitalWrite() - from another of the GPIO pins, and hooking that up as an input to pin 5. The output from the other pin will be nice clean voltage profile, so will avoid any problems the button may have. If your code works as expected, then its a problem with the button.

User avatar
mm7
 
Posts: 18
Joined: Mon Jan 15, 2018 2:37 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by mm7 »

looking into schematics of the port (pullup, etc) I do not think that giving voltage directly to the input pin is equivalent of disconnecting the input pin from ground.
In the latter case voltage will appear on the port through pullup resistor. In former case voltage will appear from output pin directly to the port.
If there is some capacitance on the port, then the rising voltage through pullup resistor should be slower.

Anyway, I completely agree that button during disconnection can generate some weird voltage fluctuations, noise and may be micro-sparcles,.
But these buttons are used in many things, including Feather itself, the reset button.
There should be some solution to make such buttons to work properly.

User avatar
bigwheels
 
Posts: 13
Joined: Sun Dec 17, 2017 11:30 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by bigwheels »

Fair point. Might at least help in testing your code to confirm that's all good.

Also, worth checking your pin reference numbers match your wiring e.g. on the MO adalogger, looks like pin #5 that you reference in code is the one marked A4 on the board (as far as I can tell from here: https://cdn-learn.adafruit.com/assets/a ... 1504805241) - odd, I know, but I ran into a similar issue on the nRF52, where the pin marked A5 on the board is accessed using #29 in code.

User avatar
mm7
 
Posts: 18
Joined: Mon Jan 15, 2018 2:37 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by mm7 »

found debounce technic doc https://www.arduino.cc/en/Tutorial/Debounce
trying....

User avatar
bigwheels
 
Posts: 13
Joined: Sun Dec 17, 2017 11:30 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by bigwheels »

nice!!

User avatar
mm7
 
Posts: 18
Joined: Mon Jan 15, 2018 2:37 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by mm7 »

Fond the solution!
1. need to switching modes inside interrupt funcs.
2. in Rising func need to debounce.

Code: Select all

#include <Arduino.h>

volatile ulong b5dt=0, b5ut=0;

extern void falling5();
extern void rising5();

String outp = "";

void falling5() {
  noInterrupts();
  b5dt=micros();
  b5ut=0;
  outp += "d ... ";
  interrupts();
  attachInterrupt(5, rising5, RISING);
}

void rising5() {
  noInterrupts();
  if (b5ut != 0) b5dt=micros();
  b5ut=micros();
  ulong x = (b5ut-b5dt)/1000;
  b5dt=0;
  outp += "U " + String(x)+"\n";
  interrupts();
  // debouncing - loop until at least 8 high reads appears
  int r=0;
  for (int i=0; i<32 && r<8 ; i++) {
	r += digitalRead(5);
  }
  attachInterrupt(5, falling5, FALLING);
}


void setup(){
	Serial.begin(9600);
	pinMode(5, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(5), falling5, FALLING);
}

int i5=0;

void loop(){

  noInterrupts(); // this is to protect String output, that is not volatile
  if (outp!=""){
		Serial.print(outp);
		outp="";
  }
  interrupts();

  i5++;
  delay(500);
}
this one works most stable.

User avatar
mm7
 
Posts: 18
Joined: Mon Jan 15, 2018 2:37 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by mm7 »

No luck again.
Sometimes callbacks got switched. rising5 for FALLING and falling5 for RISING.
Probably because of attaching in callbacks. callback table is not volatile.
noInterrupts does not help.

User avatar
mm7
 
Posts: 18
Joined: Mon Jan 15, 2018 2:37 pm

Re: Unstable rising interrupt (Feather M0 datalogger)

Post by mm7 »

finally found solution. In CHANGE callback just read the pin until N readings in a row are same.
If they are zeros - button is pressed.
In my case 1024 readings works super reliably and it does not take much time in callback 0.5-1.5 ms.
Reads are done in dense loop. May be it would be nice to put 50 uSec sleeps and run till 20 reads are same.
May be it would be less power consumption. But I do not know how to make sleeps inside callback. If someone knows please reply.

Anyway, for my device buttons will not be pressed too often, so this should work.

Code: Select all

#include <Arduino.h>
#include <limits.h>

void blink(){
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(50);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(100);
}



volatile ulong b5d=0, b5u=0;

String output = "";
volatile int inChange5 = 0;
volatile ulong us0=0;
volatile byte b5state=HIGH; // normal state
volatile ulong b5duration=0;

void change_5() {
  inChange5++;
  output += "change_5:" +String(inChange5);

  ulong us = micros();

  /* Debouncing. read until N readings in a row are same.
   * For my micro buttons and Feather M0, 1024 is good value
   */
  int N=1024;
  int b=0;
  int r;
  b = digitalRead(5);;
  int i=0, ii=0;
  while (i<N) {
    r = digitalRead(5);
    if (r == b) i++; else {i=0; b=r;}
    ii++;
  }

  unsigned long m2 = micros() - us;
  output += " reads:" + String(ii);
  output += " uSec:"+String(m2);

  if (us < us0) { // micros overrun
    us += ULONG_MAX - us0;
    us0 = 0;
  }

  if (b == HIGH) {
    b5state=HIGH; b5u=us; us0=us;
  }
  else
    if (b5state==LOW) { // repetitive downs, we take time of the first one
      b5d=us0;
    }
    else {
      b5state=LOW;
      b5d=us;
      us0=us;
      b5u=0;
    }


  if (b5state==HIGH) {
    b5duration = b5u-b5d;
    output += " UP d:"+String(b5d)+" u:"+String(b5u)+" duaration:"+String(b5duration)+" uSec\n";
  }
  else output += " dn d:"+String(b5d)+"\n";
  Serial.print(output); output="";
  inChange5--;
}

void setup(){
  Serial.begin(9600);
  delay(2000);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(5, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(5), change_5,   CHANGE);
}

void loop(){
  blink();
  delay(500);
}

Locked
Please be positive and constructive with your questions and comments.

Return to “Feather - Adafruit's lightweight platform”