2

At the moment I try to make a library which uses attachInterrupt(?,?,RISING) to read a sensor. The article of Nick Gammon on Calling an ISR from a class helped me a lot, but his "Glue routines" get pretty ugly with more than 30 potential Interrupt Pins on the ESP32, which all need their own static void. Has anyone got a more elegant idea how to do this "Gluing"?

1 Answers1

4

As a matter of efficiency, I would favor chrisl’s advise to use the platform's low-level interrupts if at all possible. This, however, comes at the cost of portability: you would need an implementation specialized for each platform you want to support. If you don't want to or cannot maintain all this platform-specific code, attachInterrupt() may be a reasonable option.

Then, you will absolutely need all those glue routines: since the interrupt system calls your handlers with no parameters, you will not be able to share handlers between interrupts, and you end up with as many handlers as interrupts you are going to use.

There is, however, an elegant way of creating all these specialized functions without writing them explicitly: you can ask the compiler to write them for you on the basis of a template you provide.

Below is a version of Nick Gammon's example code modified to use a template class. Note that you do not necessarily need a class to use templates: you could use template functions as interrupt handlers if that is appropriate for your use case.

template <uint8_t pin>
class myClass
{
    static volatile bool switchChanged;

public:
    static void begin()
    {
        pinMode(pin, INPUT_PULLUP);
        attachInterrupt(digitalPinToInterrupt(pin),
                        switchPressed, FALLING);
    }

    static void switchPressed()
    {
        switchChanged = true;
    }
};

template <uint8_t pin>
volatile bool myClass<pin>::switchChanged;

myClass<2> foo;
myClass<3> bar;

void setup()
{
    foo.begin();
    bar.begin();
}

void loop(){}

Note also that myClass<2> and myClass<3> are two different classes: you actually have a different class for each pin. This means that foo::switchChanged and bar::switchChanged are two different class members even though both are static. Since you should (in principle) have at most one instance of each pin-specific class, you can make everything within the class static.

The main caveat of this method is that the pin numbers have now to be compile-time constants. The great advantage is that you will have a class created for each interrupt that is actually used: no need for an array of 32 instances on an ESP32 if only a handful of interrupt pins are going to be actually used.

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81