class member function as an interrupt service routine

I've spent some time searching and it appears that the methods for doing this have changed over time. For instance, I found several references to a macro ISRN that was supposed to facilitate defining a member function as an interrupt service routine. Does anyone know of any example library (or other class code) that uses a class member as an ISR? The TimerOne library has an example of how a function external to the class can be linked in as an ISR, but I would like to hide this detail within the library

I am interested in implemented a class library that generates random numbers based upon WDT related jitter and need it to have a member function that gets called as an ISR.

Member functions require an instance of the object to call the member upon, so you can't.

It must be static non-member functions you are thinking of, by making it a friend to the class it can internally interact with the class. You first may have to save a reference or pointer to the instance in the cpp file that the callback function can use.

I used this approach for a message handler which had many different objects on the same queue.

I think the ISR has to be a static function; if there is a library providing support to interrupt to an instance method, I imagine it would be implemented by storing the object pointer and method pointer in global variables and having a global function that invoked that method of that object. In other words, just the way you'd do it yourself if you needed to have an object method invoked via an ordinary function.

Yah, the ISR cannot be a member. You can do things like this...

class Stuff
{
private:
  static Stuff* isr_handler;
protected:
  void handle_isr() { .. isr code goes here .. }
public:
  Stuff(): isr_hander(this) {}
  static isr() { if ( isr_handler ) isr_handler->handle_isr(); }
};

Stuff::isr_handler = 0;

Then call Stuff::isr() in the real ISR. This will ensure that the most recently-constructed object gets the interrupt handler, in the "handle_isr()" method.

Caution: Assigning a value to isr_handler may need to be done atomically…

Stuff(): isr_hander(this) {}

Ah yeah, if you use this approach, make sure your objects are all constructed before turning on interrupts. Or turn off/on interrupts around the construction of any Stuff object.

In practice, most Arduino sketches construct their objects globally, so there shouldn’t actually be a problem.

Hello,

I still have problems attaching an Interrupt from within a Class. I guess I am doing some syntactic error or something wrong with the pointer. (Sorry I am a newbee to programming, Classes and OOP.) I am getting the followig error:

In file included from NBS_Lib_V009.ino:33:0:
/tmp/build5142569924928438164.tmp/BS.h: In constructor 'BS::BS()':
/tmp/build5142569924928438164.tmp/BS.h:170:11: error: 'BS* BS::isr_handler' is a static data member; it can only be initialized at its definition
     BS(): isr_handler(this);//{}
           ^
/tmp/build5142569924928438164.tmp/BS.h:170:27: error: expected '{' at end of input
     BS(): isr_handler(this);//{}
                           ^
Fehler beim Kompilieren.

My Headder File: BS.h

class BS{

 private:
   static BS* isr_handler;
   //...and many more

 protected:
   void handle_isr(){ BS::RTCisr();}        // RTCisr() contains the Code for the ISR
   
 public:
   //BS();                                           // my old Construcktor
   BS(): isr_handler(this){}
   static void sisr2() { if(isr_handler) isr_handler->handle_isr(); }
   static void RTCisr(void);                      // psydo ISR called by real isr
   //...and many more

File BS.cpp:

   BS::BS(){                                         // BS Constructor
   //...and many more
    }   
    void BS::RTCisr(void){  //...    }       // psydo ISR called by real isr
    void BS::setupISR(void){
    attachInterrupt(4, isrRTC, RISING);
    }

in Main .ino File:

void isrRTC(){
  BS::sisr2();
}

Thank a lot in advance for any help and hints!! :)

This error "'BS* BS::isr_handler' is a static data member;" is because you are trying to assign it from within your constructor, as the error states, you can only initialise a static member where it is defined.

I usually tackle this ISR issue by creating a singleton (an object which can only have one instance). There are many ways of doing this (Googling 'singleton C++' will bring up many useful tutorials) but this is my preferred option as you dont need to worry about initialisation happening before the ISR is called and it is the simplest in terms of lines of code

BS.h

class BS {
private:
    BS();//private to stop you creating another copy of the singleton by mistake

    //The definitions below stop implicit declarations of copy operations
    //Attempting to use them will throw a compile error
    //stopping you from doing anything silly
    BS(BS const&);// Don't Implement
    BS operator=(BS const&); // Don't implement

protected:
    void RTCisr();
public:
    static BS& instance();
    static void handle_isr();
};

BS.cpp

BS& BS::instance(){
    static BS instance; //this will call your constructor on the first time it is run (once and only once)
    return instance; //return a reference (the & sign) your object instance
}
void BS::RTCisr(){
  //work your magic
}
void BS::handle_isr(){
    BS::instance().RTCisr();// get the singleton instance and call the method.
}

Hope this helps, let us know if you have any problems or if it doesnt compile (sorry I've typed this from memory). BS::instance() can be called from anywhere to get your instance, and BS::handle_isr() is a static function which can be used in your ISR

Due to your Help I got it working!! Great thank you! I think I haven't 100% understood how its working :blush: but it does. :)