Setting up interrupts in a library ... problems with attachInterrupt()

I’m creating a library object (called Easy_Motor) and need to setup some interrupt handlers within the object. I’ve attempted to use attachInterrupt() in the .cpp but I’m getting compiler errors regarding the specified handler method name. Here’s an example of the returned error message:

C:\Documents and Settings\Preferred Customer\My Documents\Arduino\libraries\Easy_Motor\Easy_Motor.cpp:103: error: invalid use of void expression
C:\Documents and Settings\Preferred Customer\My Documents\Arduino\libraries\Easy_Motor\Easy_Motor.cpp:107: error: argument of type ‘void (Easy_Motor::)()’ does not match ‘void (*)()’

Here’s the code that is causing the error(s) (tried both ways shown, same error):

attachInterrupt(0, _switchHOME, FALLING);
attachInterrupt(0, Easy_Motor::_switchHOME, FALLING);

Same error is given regardless of the interrupt number used (I’m using a MEGA, so #'s 0-5 are valid).

The interrupt handler method(s) are private methods of the Easy_Motor class, named _switchHOME() & _switchLIMIT(). Here’s their code:

void Easy_Motor::_switchHOME ()
{
  // Interrupt Handler for HOME switch.
	
  // STOP MOTOR (with BRAKE)!
  digitalWrite(_byMtrA_1pin, 255);  
  digitalWrite(_byMtrA_2pin, 255);	

  // Have already physically STOPPED motor to help eliminate damage.
  // Update the MOTOR object accordingly.
  _MyMtr.speed(255);
  _MyMtr.stop(BRAKE);
}

void Easy_Motor::_switchLIMIT ()
{
  // Interrupt Handler for LIMIT switch.
	
  // STOP MOTOR (with BRAKE)!
  digitalWrite(_byMtrA_1pin, 255);  
  digitalWrite(_byMtrA_2pin, 255);		

  // Have already physically STOPPED motor to help eliminate damage.
  // Update the MOTOR object accordingly.
  _MyMtr.speed(255);
  _MyMtr.stop(BRAKE);	
}

It it possible to use attachInterrupt() within a library .cpp file? If not, how do I setup the interrupts without using the arduino-aware attachInterrupt() macro?

Appreciate any help.

interrupt routines cannot be members of a class - they get called completely without context (only global variables can be accessed from them).

If you want to call to a member function of a class in an interrupt routine you'll need to place an instance of the class in a global variable so the interrupt routine can trampoline via that to your function.

It should work in a library, but you need to do it a bit differently in a library when callign the function from an interrupt:

Just like you had it:

attachInterrupt(0, _switchHOME, FALLING);

But change this:

void Easy_Motor::_switchHOME ()

to this:

void _switchHOME ()

and you can declare it outside your class (globally) in Easy_Motor.h

OK, so ISR routines cannot be methods of a class. I guess that makes some sense since the ISR is called based on resources (i.e. pin state) that are not within the control of the class. But, the Easy_Motor class is defining what needs to be done for the interrupt and it's instantiation really defines the point that the interrupt needs to be made available. This needs to run with as small a memory footprint as possible, so I don't want to create a global version of the Easy_Motor class (not to mention the possible issues if the code uses this improperly). Unless that is the only way to allow any access to Easy_Motor attributes. I wish there was a better way to model this.

I can move the ISR routines to Easy_Motor.h but currently I need to reference some Easy_Motor private class variables (pin definitions, names beginning with _) & the MOTOR object (_MyMtr) from within the ISR. If the ISR becomes a general function within Easy_Motor.h, how can I reference the private class objects & variables?

No matter how you look at it, you are pretty much stuck with globals if using interrupts.

You can do it with static class members and some glue routines. I did an example a little while back:

class Foo
{
  static void isr0 ();
  static void isr1 ();
  
  const byte whichISR_;
  static Foo * instance0_;
  static Foo * instance1_;
  
  void handleInterrupt ();
  
  volatile int counter_;
  
  public:
    Foo (const byte which);
    void begin ();
    
};  // end of class Foo

void Foo::begin ()
  {
  switch (whichISR_)
    {
    case 0: 
      attachInterrupt (0, isr0, FALLING); 
      instance0_ = this;
      break;
    
    case 1: 
      attachInterrupt (1, isr1, FALLING); 
      instance1_ = this;
    break;
    }  
  }  // end of Foo::begin 
  
// constructor
Foo::Foo (const byte whichISR) : whichISR_ (whichISR) 
    {
    counter_ = 0;
    }

// ISR glue routines
void Foo::isr0 ()
  {
  instance0_->handleInterrupt ();  
  }  // end of Foo::isr0

void Foo::isr1 ()
  {
  instance1_->handleInterrupt ();  
  }  // end of Foo::isr1
  
// for use by ISR glue routines
Foo * Foo::instance0_;
Foo * Foo::instance1_;

// class instance to handle an interrupt
void Foo::handleInterrupt ()
  {
  counter_++;
    
  }  // end of Foo::handleInterrupt

// instances of class
Foo firstFoo (0);
Foo secondFoo (1);

void setup()
  {
  firstFoo.begin (); 
  secondFoo.begin (); 
  }  // end of setup

void loop() { }

I basically understand what you’ve done but I’m a little lost on the glue routines. Can you give me a little more info on what they are doing?

They let the ISR call back into the class function (if that is required) by using the saved pointer to the class instance.

I'm trying to implement a version of the above code but I'm missing something. This is somewhat new to me, so I'm having a little trouble comprehending everything. First, I'm not sure I understand these glue lines completely:

// for use by ISR glue routines
Foo * Foo::instance0_;
Foo * Foo::instance1_;

I'll come back to that in a second, let me try to state what I believe I understand. You define instance0_ & instance1_ as static pointers to a Foo object in the class definition:

static Foo * instance0_;
static Foo * instance1_;

And then you set these to the Foo object pointer (this) in the .begin() method:

void Foo::begin ()
  {
  switch (whichISR_)
    {
    case 0: 
      attachInterrupt (0, isr0, FALLING); 
      instance0_ = this;
      break;
    
    case 1: 
      attachInterrupt (1, isr1, FALLING); 
      instance1_ = this;
    break;
    }  
  }  // end of Foo::begin

I think I'm alright with all of that. I believe you are using the static instancex_ to provide a link back to the specific FOO class so it's members can be accessed in the ISR. Am I correct to this point?

You then use these instancex_ references to access the handleInterrupt() method in the ISR methods:

// ISR glue routines
void Foo::isr0 ()
  {
    instance0_->handleInterrupt (); 
  }  // end of Foo::isr0

void Foo::isr1 ()
  {
    instance1_->handleInterrupt ();
  }  // end of Foo::isr1

Now we come to the glue lines I'm confused about:

// for use by ISR glue routines
Foo * Foo::instance0_;
Foo * Foo::instance1_;

What are these doing? I'm guessing these are taking care of something associated with the fact that the class definition of instance0_ & instance1_ are static but it's just not making sense.

Appreciate any help.

Just put the interrupt routine in your sketch with your setup() and your loop().

SeaLyon: Now we come to the glue lines I'm confused about:

// for use by ISR glue routines
Foo * Foo::instance0_;
Foo * Foo::instance1_;

What are these doing? I'm guessing these are taking care of something associated with the fact that the class definition of instance0_ & instance1_ are static but it's just not making sense.

That's right. With class variables (ie. non static) you don't define the variables elsewhere because they belong to each instance of the class (ie. multiple times, quite likely).

With static class variables the class declaration promises that the static variables will actually be instantiated (defined) somewhere (once) and that is what those lines are doing.