Quickest way to detect pin change

Dear community,

I have an application where I need to detect very very quickly a pin going to LOW state. I know that the standard way to do it would be to use the hardware interrupts, but I noticed that it is adding a 4µs overhead that is not compatible with my application.

Do you think that the code below is the fastest way to detect a change or is there a quicker way than this?

I'm basically speding all my time checking the pin 2 value, I use the following library to go faster that the standard DigitalRead
http://www.codeproject.com/Articles/732646/Fast-digital-I-O-for-Arduino

the code:

#include "arduino2.h"

void setup() {

pinMode(2, INPUT);
noInterrupts();
}

void loop() {
// put your main code here, to run repeatedly:
while (1)
{
if (!digitalRead2f(DP2)) //detect pin2 change
{
//do something if pin2 is LOW
}

}
}

The fastest way to read a pin is with PINx where x is the Atmel Port letter - B, C D etc. No library will do better.

But reading a pin quickly is not the same as quickly detecting a change because you can only use a read to detect a change if you have a loop that continuously reads the port. The loop overhead will be far far greater than the interrupt overhead.

If your project really needs the precision you mention maybe you need a much faster microcontroller

If you explain what you want to achieve people here may be able to help.

...R

Do you think that the code below is the fastest way to detect a change

No. Polling the pin using digitalRead() is way slower than a hardware interrupt.

or is there a quicker way than this?

Direct port manipulation is faster, though not at all portable.
http://playground.arduino.cc/Learning/PortManipulation

But reading a pin quickly is not the same as quickly detecting a change because you can only use a read to detect a change if you have a loop that continuously reads the port. The loop overhead will be far far greater than the interrupt overhead.

In my application once I detected a LOW state I can stop the pin change detection

No. Polling the pin using digitalRead() is way slower than a hardware interrupt.

but is a PORTD check in a while(1) quicker than a hardware interrupt ? (I do understand that all my processing ressource will be blocked in that operation, but here I don't mind)

but is a PORTD check in a while(1) quicker than a hardware interrupt ?

Since you've already timed the hardware interrupt, somehow, do be sure to get back to us when you measure this.

Since you've already timed the hardware interrupt, somehow, do be sure to get back to us when you measure this.

I will!

I think I would try this:

while ((PIND & 0b00000100) == 0b00000100){ // read PORTD & look at bit 2
// hang out waiting for bit to go low
}
// bit went low - now do something else

Executive summary:
-The hardware interrupt is slower than dedicating 100% of CPU time to check the status of a pin.
-The library used does not add any overhead

detailed results below:

With the hardware interrupt fashion, takes 3.47µs (time between the LOW state on pin 2 and the ouput going to HIGH on pin 5

void setup() {

  pinMode(2, INPUT);
  pinMode(5, OUTPUT);
  
  attachInterrupt(0, inter, FALLING);
}


void inter (void)
{
      PORTD |= 1 << 5; //fast digitalwrite HIGH on output 5
      PORTD &= ~(1 << 5); //fast digitalwrite LOW on output 5 
}

void loop() {
  // do nothing else than waiting for interrupts

}

this one takes 300 - 350ns, so no overhead from this library

#include "arduino2.h"

void setup() {

  pinMode(2, INPUT);
  pinMode(5, INPUT);
  noInterrupts();
}

void loop() {
  // put your main code here, to run repeatedly:
  while (1)
  {
    if (!digitalRead2f(DP2)) //detect pin2 change
    {
      //do something if pin2 is LOW
      PORTD |= 1 << 5; //fast digitalwrite HIGH on output 5
      PORTD &= ~(1 << 5); //fast digitalwrite LOW on output 5 
    }

  }
}

this one takes 300 - 350ns as well

void setup() {

  pinMode(2, INPUT);
  pinMode(5, OUTPUT);
  noInterrupts();
}

void loop() {
  // put your main code here, to run repeatedly:
  while ((PIND & 0b00000100) == 0b00000100){ // read PORTD & look at bit 2
    // hang out waiting for bit to go low
  }
  //do something if pin2 is LOW
  PORTD |= 1 << 5; //fast digitalwrite HIGH on output 5
  PORTD &= ~(1 << 5); //fast digitalwrite LOW on output 5 



}
1 Like

Very Interesting @roscodemars. Thank You.

I had incorrectly assumed that a loop would be slower than an interrupt but, now that I think about it, the interrupt needs to do some housekeeping which the loop does not need.

And I had correctly figured that the library would not be faster than direct port manipulation. But I am surprised that it is as fast as it is so I may take to using it if it makes code more portable.

No doubt you are well aware that using an interrupt allows the Arduino to get on with other stuff while waiting for the event.

...R