Hi Richard,
To call a C++ member function, you need the object to call it on (as I think you understand). This pointer is some state that you need to have stored somewhere. How you do that can be very dependant on what you are trying to achieve, and particularly on how much can be implicitly defined in your code.
A static member function doesn't have a this pointer, as it is not associated with any particular instance, and hence you can call it like any other global/static function.
As a simple example, you could do something like this to allow you to call handlers on two different instances of an object:
#include "mbed.h"
class Foo {
public:
void handler() {}
};
Foo* handlers[2];
extern "C" void WHATEVER_IRQHandler() {
int id = rand() % 2; // determine what to call
handlers[id]->handler();
}
Foo f0;
Foo f1;
int main() {
handlers[0] = &f0;
handlers[1] = &f1;
// setup WHATEVER interrupts
while(1);
}
Obviously, instead of rand(), you'd be reading some IRQ or peripheral registers to determine what to do. Or maybe you only have one class, so you can just call it.
Now, you could then wrap that up all in to a class, so the constructors do the registration. As another example, i've also dynamically setup the vector if they get instanced:
#include "mbed.h"
class Foo {
public:
Foo(int id) {
handlers[id] = this; // register this instance against the id
NVIC_SetVector(WHATEVER, (uint32_t)&irq); // setup, enable etc...
}
void handler() {} // do something specific to this object instance
static void irq() { // work out which object to call
int id = rand() % 2; // determine what handler to call
handlers[id]->handler();
}
static Foo* handlers[2];
};
Foo* Foo::handlers[2] = {0};
Foo f0(0);
Foo f1(1);
int main() {
// setup interrupts etc
}
If you want to have classes that can register other classes, or you want to be able to register different methods, then things can get more complicated! (e.g. the mbed library has to be pretty generic to handle lots of different requirements), but in general, the approaches above are what I expect you'll find fits your model.
Hope this helps,
Simon
In addition to the many fast prototyping benefits I found using mbed, I have really enjoyed the use of C++ to elegantly produce embedded source code - creating layers of abstraction. The TimerEvent and derived classes are especially interesting and impressive.
As I move from prototyping into a production phase, using local tools source code, I'm having a little trouble figuring out the best way to register C++ member functions with the interrupt controller.
Without necessarily needing to see the whole source for the TimerEvent, and Ticker classes, could someone please explain the general process for connecting a hardware interrupt to a member function?
I'm pretty sure I understand the linked list of registered events concept, but I'm not following how the member function
is actually called, and what irq() actually does.It makes sense that a static function is required, but I'm wondering how many layers of abstraction are used when trying to maintain the performance given by the Cortex-M3 NVIC.
I would really appreciate some additional insight into how the interrupt logic implemented in the mbed library works such that I could leverage some our prototype code onto our production platform.
Thanks.