3
votes

Is it possible to use a class method as the Interrupt Service Routine?

I have an ISR written and working in C using a function:

    static void interrupt far ISR(...) {}

I've tried in C++ to create a method (prototype):

    void interrupt far ISR(...);

Then the implementation:

    #pragma interrupt
    void interrupt far MyClass::ISR(...) {
    ...
    }

But I get all sorts of errors when I try to use this with 'setvect':

    setvect(muint16Vector, &ISR);

I'm trying to write a class to service a serial port, the ISR would service the Rx of data from the port. The ISR would then use instance specific members.

I have 3 serial ports, so I would like to create 3 instances of the class.

4
A non-static member function requires to be called on an instance of the class. You can't use it as a non-member function pointer. Either wrap it in a static member function, or use an actual non-member function like you do in C.Some programmer dude
@Someprogrammerdude, I will add a bit more text to describe the problem a little more, thank you.SPlatten
What arguments are passed to the interrupt handler? If one of the arguments is the serial port number you can use an array of objects and use the serial port number argument to index that array and call the actual member function.Some programmer dude
@Someprogrammerdude, none, the interrupt handler does not take any interrupts, the prototype you see is the prototype an ISR uses in the Borland C++ v5 environment.SPlatten
Okay, so how do you know which serial port is the source of the interrupt? Can you get that from a register or something, and use that as an array index?Some programmer dude

4 Answers

1
votes

With the information given in the comments, this is a possible solution:

class SerialPort
{
public:
    // Unrelated functions...

    void isr();  // The serial interrupt handler

    // Other unrelated stuff...
};

std::array<SerialPort, 3> serial_ports;  // Or SerialPort serial_ports[3];

static void serial_isr(int const port_index)
{
    // Common code for all serial ports that for some reason
    // can't be in the class...

    serial_ports[port_index].isr();  // Call actual ISR
}

extern "C" void interrupt serial_isr_1()
{
    // Special code for only this serial port...

    serial_isr(0);
}

extern "C" void interrupt serial_isr_2()
{
    // Special code for only this serial port...

    serial_isr(1);
}

extern "C" void interrupt serial_isr_3()
{
    // Special code for only this serial port...

    serial_isr(2);
}
0
votes

You just need to create a global variable which is the instance to invoke upon:

class Handler {
  void ISR(...) {}
};

static unique_ptr<Handler> g_handler;

#pragma interrupt
extern "C" static void interrupt far ISR(...) {
  if (g_handler)
    g_handler->ISR(...);
}

g_handler = std::make_unique<Handler>();
setvect(muint16Vector, &ISR);
0
votes

The real answer is 'No' it is not possible in C++ to use a method as the ISR handler directly.

You have to resort to standard C functions and then with glue in the ISR function, reference the required object.

It ends up as quite a messy solution.

0
votes

There's an old Dr. Dobbs article that covers this well, along with a good explanation of the issues involved: Implementing Interrupt Service Routines in C++