Working solution for interrupts inside C++ classes

bubulindo
Thu Sep 01, 2016 8:18 am
Hello,

I’m sure this has been gone through before, but I cannot find an elegant solution for what I want to do.
I’m looking into making a library to use timers as quadrature encoder readers and one of the intended functionality for me would be to count the number of interrupts (and based on the direction of the count add or subtract this number).

My problem is that I cannot find a nice way of doing this. If I create a function, I cannot access the variable inside the class.

If I define a method as static, I cannot find a way of reusing the code for the different timers… or so it seems to me.

Any ideas?


RogerClark
Thu Sep 01, 2016 10:10 am
I recall looking at the same problem ages ago

And I don’t think there is solution, as its not possible to get a pointer to a function in C++ which you can use as an ISR

There was a thread about it on Arduino.cc but it must have been at least a year ago, so it may be hard to find.

You could try PM’ing someone like @Rick Kimball, he knows a knows a lot of clever coding stuff, but I doubt there is an elegant solution


edogaldo
Thu Sep 01, 2016 10:53 am
bubulindo wrote:If I create a function, I cannot access the variable inside the class.

bubulindo
Thu Sep 01, 2016 11:19 am
If you declare the variable in the public section, you’ll then need to have the object instantiated before you can use that variable in a function.

Slammer
Thu Sep 08, 2016 3:44 pm
Another option is to use interrupt vectors in RAM.
I dont know if this is supported by stm32duino but it can be done.
Normally the interrupt vectors are located in the first bytes of Flash starting at 0x0800000 (or 0x08002000 if bootloader is used) and there are 59 vectors taking 236 bytes (this number is different across STM32 family).
The trick is to copy these vectors to RAM, changing a bit the link script it is possible to make the RAM segment to start at 0x20000100 instead of 0x20000000 (change the line that defines the ORIGIN and LENGTH of RAM segment), this leaves 256 bytes of free RAM memory.
Now in the beginning of your program it is very easy to copy the normal interrupt vectors from the FLASH to RAM and then change the pointer of interrupt vector table at 0x20000000.
I dont know how the libmaple names the system’s control registers (it must be something similar, maybe SCB_BASE->VTOR) but with the ST’s official naming this can be done with the following code :
#define NVIC_RAM_VECTOR_ADDRESS (0x20000000)
#define NVIC_NUM_VECTORS 59

uint32_t *vectors = (uint32_t *)SCB->VTOR;
uint32_t i;

uint32_t *old_vectors = vectors;
vectors = (uint32_t*)NVIC_RAM_VECTOR_ADDRESS;
for (i=0; i<NVIC_NUM_VECTORS; i++)
vectors[i] = old_vectors[i];
SCB->VTOR = (uint32_t)NVIC_RAM_VECTOR_ADDRESS;
.

// Somewhere in your code assign vector[x] = (uint32_t)foo; where foo() is your function


RogerClark
Thu Sep 08, 2016 9:24 pm
@slammer

I think the problem, is that in C++ it is not possible to get a pointer to a function of a particular instance of an object.

So when writing a library, for example software I2C, where each instance has private variables ( properties) for SDA and SCL

you could not do

attachInterrupt(sdaPin,this.isrFunction);

because the compiler can not resolve this.isrFunction to an individual address

I suspect the way to do this in C++ may be to use templates, so that each instance is an instance of a different class , but the class is based on the same template.

The class also would need to have a static function for the ISR and also ideally would be a singleton


Slammer
Thu Sep 08, 2016 10:04 pm
There are limitations, but with the vectors in RAM it is possible to play with the compiler to solve these problems (templates, singleton classes etc), it is far more flexible than FLASH allocation where only the linker decides about interrupt vectors.

RogerClark
Thu Sep 08, 2016 10:29 pm
Doesnt ultimately attachInterrupt() use update the VTOR ?

Perhaps there is a wrapper function, but I still think the issue that bubulindo is trying to solve is the pointer to method of an instance


edogaldo
Fri Sep 09, 2016 7:29 am
What I’d do is define a map that binds each interrupt to the related instance, pass the map to the isr and make the isr use it to address the correct instance.

RogerClark
Fri Sep 09, 2016 7:49 am
edogaldo wrote:What I’d do is define a map that binds each interrupt to the related instance, pass the map to the isr and make the isr use it to address the correct instance.

edogaldo
Fri Sep 09, 2016 8:18 am
RogerClark wrote:How do you handle the mapping? Do you use an Array of classes ?

racemaniac
Fri Sep 09, 2016 8:37 am
A related question to this: do we have any proper documentation on how to work with the interrupt vectors?
When i was developing my frameworks, getting to know that part was quite a pain (i knew the principle, but never encountered it in practice), also libmaple already specifying handler routines for a lot of the interrupts made it a bit of a mess for me to figure out what was happening where :).
I’ve been able to work with it, but if you’d ask me now how to specify your own ISR routine, i’d probably be searching around in the code for quite a while to figure it out again.
If someone is well versed in this, maybe it’s worth writing a page on it on the wiki? And then also link threads like this to it for related questions/discussions.

edogaldo
Fri Sep 09, 2016 9:12 am
respect to mixing C and C++ I found this link that seems me useful: https://isocpp.org/wiki/faq/mixing-c-and-cpp

bubulindo
Fri Sep 09, 2016 5:26 pm
That link has some useful information, but you’d still need the pointer of the object to be passed to the irq routine, which sounds a bit hard to do to me.
But I’m not a C++ expert. :\

edogaldo
Fri Sep 09, 2016 6:01 pm
Did you read also previous posts?

Slammer
Sat Sep 10, 2016 12:38 am
The use of a class method as interrupt function it is possible and the mbed API already support it.
First requirement is to use interrupt vectors in RAM (look my previous post)
Then examine carefully the Callback.h from mbed sources : https://github.com/ARMmbed/mbed-os/blob … Callback.h
You can use it almost directly as the Callback class has no dependencies and it is a header only class (it is done by Templates)
Callback class is a helper class that extracts the address of a plain function or a member function during runtime.
Finally you can use it for interrupt vector assigment.
Read here a related question about InterruptIn (is the function that assigns a function to an External Interrupt) to see the use of Callbacks : https://developer.mbed.org/forum/mbed/topic/639/

I made some small tests and it seems that this method is working. I am trying to find a way to relocate the vectors without touching anything in stm32duino sources (the Callback.h can be used almost untouched) and I will post a complete example.
Stay tuned…..


bubulindo
Sat Sep 10, 2016 6:24 am
As I said, C++ is a bit out of my depth and why I’ve been looking to create a library as a means to learn a bit more of it.
I’ll stay tuned for sure as this could be very interesting development. :)

Paul
Thu Nov 10, 2016 1:57 pm
Some of the Maple libraries have interrupt routines which make it easy to get an interrupt into a C++ routine.
For example, GPIO has two versions of attachInterrupt()

void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode);

void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg,
ExtIntTriggerMode mode);


Leave a Reply

Your email address will not be published. Required fields are marked *