3

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.

SPlatten
  • 5,334
  • 11
  • 57
  • 128
  • 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 Dec 16 '16 at 12:18
  • @Someprogrammerdude, I will add a bit more text to describe the problem a little more, thank you. – SPlatten Dec 16 '16 at 12:23
  • 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 Dec 16 '16 at 12:55
  • @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 Dec 16 '16 at 15:57
  • 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 Dec 16 '16 at 16:09
  • Each serial port is attached to its own IRQ. – SPlatten Dec 16 '16 at 16:11
  • Why would you declare an ISR in "far" memory? Typically all interrupt vector tables have the smallest possible address width, because that gives the smallest ISR call overhead. Therefore, almost every such system requires ISRs to be allocated in the `near` segment, and declaring them in the `far` segment would typically cause the whole program to go bananas. This could very well be the cause of your errors. Which system is this? – Lundin Jan 12 '17 at 08:52
  • The ISR is part of a much larger application running in RedHat Linux. The cause of the errors is simply that you cannot use a class method in an ISR. – SPlatten Jan 12 '17 at 08:55

4 Answers4

1

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);
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

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);
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • How would the ISR know which handler to call? – SPlatten Dec 16 '16 at 12:29
  • @SPlatten: What do you mean? I posted the complete code. It knows because you set a global variable. – John Zwinck Dec 16 '16 at 12:49
  • there are 3 instances of the object, how does the ISR know which object is relevant? – SPlatten Dec 16 '16 at 18:22
  • @SPlatten: It will call whichever object you most recently assigned to the global pointer. What else can it do, speaking purely theoretically? You're asking the impossible now. – John Zwinck Dec 17 '16 at 02:06
  • I will never work then as the interrupt will be out of sync with whatever object is assigned to the handler. There needs to be a lookup when the interrupt occurs. I have an idea in mind which I will try out on Monday and post the results. – SPlatten Dec 17 '16 at 08:15
0

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.

SPlatten
  • 5,334
  • 11
  • 57
  • 128
0

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++

Gordon Brandly
  • 352
  • 4
  • 15