Q on C++ ISR linkage (in AVR context)

Go To Last Post
22 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Anyone know...
I have an interrupt service routine, declared as C code (I don't know how to do an ISR in a class)...

That ISR needs to access a variable in a C++ class.
All I can figure to do is make the variable a global but within the class' dot h file. That doesn't protect it and seems wrong.

And... one variable is a void * pointer which will, at run-time, contain the address of a function to call from the ISR, and that function ideally is a class member. The class name isn't known at compile-time, but the type will be void * and the params are void.

I'm learning; bear with me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I don't know how to do an ISR in a class
You can't.
Quote:
All I can figure to do is make the variable a global but within the class' dot h file. That doesn't protect it and seems wrong.
Certainly something must be global, that is the only way for the ISR to see anything, but it doesn't have to be the variable. You can have the global variable be a pointer to an instance of the class (or a base class that it is derived from) with accessor functions to the variable.
Quote:
And... one variable is a void * pointer which will, at run-time, contain the address of a function to call from the ISR
You can have a function in the class that calls the function pointed to by the variable. But keep in mind that function calls from within an ISR are rather inefficient. Since the function to be called can't be known at compile time, the compiler has no choice but to push and pop all registers that might be trashed by a function call.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For avr-gcc I use C-linkage ISR functions that declared as friend functions to class with inline isr() handler
https://www.avrfreaks.net/index.p...

AFAIK, in IAR/AVR it is possible to declare class member function as interrupt handler. The function must be static member of class.

Koshchi wrote:
But keep in mind that function calls from within an ISR are rather inefficient.

So, all functions called from interrupt handler must be inline.
Sometime __attribute__((__always_inline__)) is needed.

wbr, ReAl

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Aside:

Quote:

one variable is a void * pointer which will, at run-time, contain the address of a function to call from the ISR, [...] the type will be void * and the params are void.

If the return value and the parameter list is known at compile time, then why not make the type of the function pointer "stronger" than just "void *"?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stevech wrote:
Anyone know...
I have an interrupt service routine, declared as C code (I don't know how to do an ISR in a class)...
It can be done, but it's not a good idea.
Quote:
That ISR needs to access a variable in a C++ class.
All I can figure to do is make the variable a global but within the class' dot h file. That doesn't protect it and seems wrong.
As another suggested, make the ISR a friend of the class.
Quote:

And... one variable is a void * pointer which will, at run-time, contain the address of a function to call from the ISR, and that function ideally is a class member. The class name isn't known at compile-time, but the type will be void * and the params are void.
As another noted, not good at all.
'Tis time to rethink what belongs in the ISR and what belongs in the main line.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

It can be done, but it's not a good idea.

If "it" refers to having a member function be an ISR then please elaborate - even if it is a bad idea.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Quote:

It can be done, but it's not a good idea.

If "it" refers to having a member function be an ISR then please elaborate - even if it is a bad idea.
With avr-gcc make the member static and use asm to give it the right name.
With other tool chains, the process might be trickier.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

With avr-gcc make the member static and use asm to give it the right name.

OK, thank you.

Next question: What makes it "not a good idea" in your opinion? Do you refer to the clumpsiness, asm coding etc? Or do you have a principal argument against an ISR as a static member function in a class?

(Please note - those questions are not rethorical manouvres to start an argument. They are honest questions - I am turning and twisting things and thoughts about C++ in embedded systems, and ISRs always pops up as "not really any nice solution available". Yes, I understand the principal problem that since the hardware calls the ISR, and the hardware can not pass an instance reference (a this-pointer) we can never get away with having a non-static member function as an ISR.

My mind is currently toying with using template classes with only static members, and instantiating one such class for each actual hardware device of a given (meta-)class that I need to handle. I'm hoping that I can do some experiments with this in the near future.)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's what I'm trying to do...
recurring timer interrupt (systick).
Each interrupt, I want the ISR to call a function (void type, no params of course) - the address of that function is not known at compile time. Ideally the function is in a class. I know how to do this in C, but not C++. Indeed, the pointer to the function is, in my goal, a linked list of functions to call each clock tick, where the list is built at run time. The intent is that each in the chain is small/fast.

The class instances are, in my embedded code, static, as new() and delete() are bonkers for a small micro.

I'm learning.

I have read about "friend" in C++ but the more I read about it, in the context of embedded processors, the more confused I get. Most, of course, are high level GUI oriented examples.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Quote:

With avr-gcc make the member static and use asm to give it the right name.

OK, thank you.

Next question: What makes it "not a good idea" in your opinion? Do you refer to the clumpsiness, asm coding etc? Or do you have a principal argument against an ISR as a static member function in a class?

I was thinking mostly in terms of clumsiness,
but the syntax could be handled by a write once-use forever macro.

stevech wrote:
Here's what I'm trying to do...
recurring timer interrupt (systick).
Each interrupt, I want the ISR to call a function (void type, no params of course) - the address of that function is not known at compile time. Ideally the function is in a class. I know how to do this in C, but not C++. Indeed, the pointer to the function is, in my goal, a linked list of functions to call each clock tick, where the list is built at run time. The intent is that each in the chain is small/fast.
It might be better to have the ISR set a flag and have the main line handle the list.
Supposing what you are asking for is a good idea:
Is the ISR written in C++?
If so, calling a static method can be done like any other function call.
Register-saving might slow it down a bit though.
The called functions need not be ISRs.

If the ISR is written in assembly, you might have name-mangling issues.
A cure is to use the asm keyword to give the linked list a name you can type.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
It might be better to have the ISR set a flag and have the main line handle the list.
But... the idea is to not "poll" a flag!

ISR is now 8 lines of C code. Could be most anything. No need for asm.

Quote:
Is the ISR written in C++?
No, in C. Don't know how to do so in C++. How do you declare the interrupt vector initialization in C++?
Quote:
If so, calling a static method can be done like any other function call.
Calling a static method... presumes the address is known at compile time, right? Which I didn't want to do - so it could be a dynamically built linked list.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stevech wrote:
Quote:
If so, calling a static method can be done like any other function call.
Calling a static method... presumes the address is known at compile time, right? Which I didn't want to do - so it could be a dynamically built linked list.
In C or C++:
(*fptr)();

IIRC explicit dereferencing is not necessary:

fptr();

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes, for C.
Confusion for me is C++.

Would you assign fptr to be the address of a function within a class, where the class instance is static, something like

fptr = &myInstance.classMemberFunction;

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stevech wrote:
yes, for C.
Confusion for me is C++.

Would you assign fptr to be the address of a function within a class, where the class instance is static, something like

fptr = &myInstance.classMemberFunction;

If myInstance.classMemberFunction is static, that will work.
I'd use fptr = & ClassName::classMemberFunction;
The instance is irrelevant. You don't even need an instance.
C++ also has member function pointers.
One can take the address of a non-static member function.
To invoke it, one needs to specify an instance.
C++ doesn't, but least one other language, python,
also allows one to "take the address" of a non-static member function tied to an instance.
To invoke it, one does not need to specify the instance again.
Those more familiar with python than with C++ might mistake &myInstance.classMemberFunction for just such an expression.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I'd use fptr = & ClassName::classMemberFunction;
I'm getting the concept here: this works because the address of the function is the same for all instances, static or not. This wouldn't be true for a variable in a class, if I have this correct.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stevech wrote:
Quote:
I'd use fptr = & ClassName::classMemberFunction;
I'm getting the concept here: this works because the address of the function is the same for all instances, static or not. This wouldn't be true for a variable in a class, if I have this correct.
Now that I think of it, the same syntaxes can be used for both static and non-static member functions.
The difference is in the result.
The address of a static member function has type pointer to function and can be used accordingly.
The address of a non-static member function has type pointer to member function.
Part of the type is the type of the object necessary to use it: (obj.*mfptr)(args);

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
The address of a static member function has type pointer to function and can be used accordingly.
The address of a non-static member function has type pointer to member function.
Uh oh. You lost me. What's the difference between "pointer to function" and "pointer to member function" ? Isn't the code in the same address for both cases?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stevech wrote:
Quote:
The address of a static member function has type pointer to function and can be used accordingly.
The address of a non-static member function has type pointer to member function.
Uh oh. You lost me. What's the difference between "pointer to function" and "pointer to member function" ? Isn't the code in the same address for both cases?
Pointer to double and pointer to struct both point to data,
but one uses them differently.
Pointer to function and pointer to member function can both point to code,
but that does not mean that you do not have to use them differently.
To add fuel to the fire, if the member function is virtual,
the pointer is probably an offset into a vtable.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moreover,

sizeof(pointer_to_C_function) == sizeof(pointer_to_static_class_member)

but

sizeof(pointer_to_non_static_member_function) > sizeof(pointer_to_static_class_member)

Not only usage differs

pointer_to_static_class_member();

and

class_instance.*pointer_to_non_static_member_function();
pointer_to_class_instance->*pointer_to_non_static_member_function();

but internal structure differs also.

pointer_to_static_member_function is just pointer but pointer_to_non_static_member_function is structure. The structure contains information about class and function type, method of pointer to class_instance to "this" pointer conversion and so on. Not only virtual functions must be handled in special manner.
non-static member function can be a member of one of base classes => "this" for the function can point to base class subobject inside current object and some offset can be needed.

wbr, ReAl

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks for the above.
Q on "this" when used for static members. I wonder if the C++ "standards" say that this must be permitted. I am using it in may learning exercise and it's handy - the using function utilizes "this.xxx" and I suppose, it's transparent to the coder at design time whether the member will be static or not.

yes?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is no need to use friend declarations for this.

Declare your ISR as a static member of the class. Make sure it uses the same calling convention as other ISRs. If you want to access non-static members of your class in the ISR, the ISR needs a reference to the this pointer of an object.

Once the ISR - the static member - has the this pointer of a valid object, it can access members through that pointer. That includes calling non-static member functions.

Typically, you want to register the ISR from within a regular class method. In that method, you have easy access to the this pointer and can store it in a static member variable for use in the ISR, prior to registering the ISR.

Of course, you need to make sure the object stays alive for as long as the ISR needs it.

If this is all Greek to you, start with something simpler to learn C++.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Plenty of strange advice here.

The difference between a function pointer, and a
pointer-to(-non-static)-member-function, is that the latter requires an object to invoke the function.

Every non-static member function of your class takes a hidden parameter that's pushed on the stack prior to any declared parameters. That parameter is the "this" pointer, and it lets the member function know which object it is working with.

That's why you can't use a non-static member function as an ISR. The ISR invocation doesn't push any "this" on the stack for your object to use.

Sid

Life... is a state of mind