Interrupt problems with RISING

I’m not able to get interrupts to work as expected. I am using a Due.

I have a microswitch connected to the Due and set pinmode to INPUT_PULLUP. When initialising, to check all is correct, I call digitalRead() for that pin and get a HIGH reading - as expected. I then attach a RISING interrupt. When I press the switch, for some reason the interrupt gets triggered. That shouldn’t happen as the voltage is falling. When I release the switch, the interrupt gets triggered again.

So my observations are:
1- a RISING interrupt shouldn’t be triggered when I press the switch;

2- I also get two interrupts when I press even though I have a 1s delay in my loop (see source below). (Note: I keep my finger on the switch for several seconds);

3- If I instead use a FALLING interrupt, it only gets triggered when I press the switch, not when I release - which is correct. (However, I still get two interrupts when I press.)

4- CHANGE works as expected - though again with 2 interrupts instead of 1;

5- when using a LOW triggered interrupt, I only get one interrupt when I press the switch but then get two when I release. I shouldn’t get any when I release.

6- These anomolies can’t surely be to do with switch bounce, a) because I shouldn’t get a RISING interrupt when I press and b) I have a 1s delay in my loop.

When using a LOW interrupt and keeping the switch pressed for several seconds before releasing, I get the following output:

top is HIGH
top switch down
top is LOW
top switch down
top is HIGH

Thoughts?

My code:

#include <stdlib.h>
#include <Arduino.h>

#define TOP_TRIP_PIN		2

volatile bool	g_top_switch_down;

// Interrupt service routines
void	ISR_top_switch_down()
{
  g_top_switch_down = true;
}

void setup()
{
  Serial.begin( 115200 );
	
  pinMode( TOP_TRIP_PIN, INPUT_PULLUP );

  attachInterrupt( digitalPinToInterrupt( TOP_TRIP_PIN ), ISR_top_switch_down, LOW );

  if( digitalRead( TOP_TRIP_PIN ) == LOW )
    Serial.println( "top is LOW" );
  if( digitalRead( TOP_TRIP_PIN ) == HIGH )
    Serial.println( "top is HIGH" );

  g_top_switch_down = false;
}

void loop()
{
  if( g_top_switch_down )
  {
      detachInterrupt( digitalPinToInterrupt(TOP_TRIP_PIN) );
      g_top_switch_down = false;
      Serial.println( "top switch down" );
      delay(1000); // to remove debounce issues
      if( digitalRead( TOP_TRIP_PIN ) == LOW )
        Serial.println( "top is LOW" );
      if( digitalRead( TOP_TRIP_PIN ) == HIGH )
        Serial.println( "top is HIGH" );
      attachInterrupt( digitalPinToInterrupt( TOP_TRIP_PIN ), ISR_top_switch_down, LOW );
  }
}

Your switch bounces, like most mechanical switches.

http://www.gammon.com.au/forum/?id=11955

There is a software debounce or glitch filtering feature with the DUE. You want to select between glitch or debounce with PIO_DIFSR and PIO_IFDGSR registers, plus a Slow Clock Divider.

Whandall:
Your switch bounces, like most mechanical switches.

Gammon Forum : Electronics : Microprocessors : Switches tutorial

Thanks for the reference and of course my switch bounces, but I don't believe that it is still bouncing after 1 second.

I see no mention of a one second delayed interrupt in your post.

even though I have a 1s delay in my loop

Interrupts don't care about delays.

I imagine the interrupt flag is still set from contact bouncing and the ISR fires when you re-attach the interrupt.

BTW, detaching / re-attaching the interrupt is a poor way to handle the situation. Try something like this:

#include <stdlib.h>
#include <Arduino.h>

#define TOP_TRIP_PIN    2

volatile bool g_top_switch_down;
volatile bool serviceInterrupt = false;

// Interrupt service routines
void  ISR_top_switch_down()
{
  if (serviceInterrupt) {
    g_top_switch_down = true;
  }
}

void setup()
{
  Serial.begin( 115200 );

  pinMode( TOP_TRIP_PIN, INPUT_PULLUP );
  attachInterrupt( digitalPinToInterrupt( TOP_TRIP_PIN ), ISR_top_switch_down, LOW );
  if ( digitalRead( TOP_TRIP_PIN ) == LOW )
    Serial.println( "top is LOW" );
  if ( digitalRead( TOP_TRIP_PIN ) == HIGH )
    Serial.println( "top is HIGH" );

  g_top_switch_down = false;
  serviceInterrupt = true;
}

void loop()
{
  if ( g_top_switch_down )
  {
    serviceInterrupt = false;
    Serial.println( "top switch down" );
    delay(1000); // to remove debounce issues
    if ( digitalRead( TOP_TRIP_PIN ) == LOW )
      Serial.println( "top is LOW" );
    if ( digitalRead( TOP_TRIP_PIN ) == HIGH )
      Serial.println( "top is HIGH" );
    g_top_switch_down = false;
    serviceInterrupt = true;
  }
}

Whandall:
I see no mention of a one second delayed interrupt in your post.

Interrupts don't care about delays.

It's right up there in my point number 2:

"2- I also get two interrupts when I press even though I have a 1s delay in my loop (see source below). (Note: I keep my finger on the switch for several seconds);"

I also posted the source code. It's very short and easy to find the line:

"delay(1000); // to remove debounce issues"

gfvalvo:
I imagine the interrupt flag is still set from contact bouncing and the ISR fires when you re-attach the interrupt.

Thank you @gfvalvo, but you seem to be wrong - at least in the case of LOW triggered interrupts.

I modified my code as per your recommendation. When I press the button I get the message, "top switch down" as expected. I keep the switch down for many seconds, but I don't get the "top is LOW" message. Eventually I release the switch and suddenly the "top is HIGH" appears. Note that I do not get another "top switch down" interrupt message, so it's nothing to do with switch bouncing. Also note that it is read as HIGH, not LOW. Furthermore, there is around a 1s delay between me releasing the switch and the LOW message appearing. It's as if the system is locked just after printing the "top switch down" message.

After much befuddlement I realised that the problem is that by keeping the switch closed for a long time, the system must be firing off thousands of interrupts, blocking my program from progressing. When I add detach the interrupts as before, all is fine.

So really, I need to disable interrupts and / or clear some interrupt flag or have some kind of debounce circuitry or the suggestion by @ard_newbie in one of the posts above.

There is a good explanation about interrupts and how to clear flags that I am just going through now:
http://gammon.com.au/interrupts

Since the button is driven by a human, an interrupt should not be extremely useful. Anyway, there is an example sketch to handle PIO interrupts or PIO polling here (reply #1):

ard_newbie:
Since the button is driven by a human...

Only for testing purposes. I am trying to drive a moving platform and use microswitches to detect when limits have been reached. I need to detect when a switch has been pressed and also when it has been released as the platform moves back away from the end.

Thanks for the reference though. I'll check it out.