I'm writing an Arduino library using C++ classes. Inside the class, I have a private member variable which is a pointer to a function.
The problem is that I need the pointer to be volatile since the pointer to the function will be set outside an ISR, and can be changed during program execution, but the function will be called inside an ISR. Hence, I think I need a volatile pointer to a nonvolatile function, is that right?
Anyway, what I'm doing is creating a mechanism for allowing a custom user function which will be called periodically by my library.
Here's the basics:
This just shows the essential parts for you to see.
.h file
class myLib
{
public:
void attachOverflowInterrupt(void (*myFunc)());
private:
volatile void (*userOverflowFunction)(void);
}
.cpp file
void myLib::attachOverflowInterrupt(void (*myFunc)())
{
//ensure atomic access
uint8_t SREGbak = SREG; //back up interrupt state
noInterrupts(); //interrupts off
userOverflowFunction = myFunc; //attach function //<--the part that matters to my problem here
SREG = SREGbak; //restore interrupt state
}
//inside the interrupt, their function is called essentially like this:
this->userOverflowFunction();
Arduino .ino file (only essential parts shown)
void doSomething()
{
}
myLib1.attachOverflowInterrupt(doSomething);
THIS CODE DOES NOT compile. I get this error:
error: invalid conversion from 'void (*)()' to 'volatile void (*)()' [-fpermissive] userOverflowFunction = myFunc; //attach function
If I do this in the class instead, however, it compiles:
class myLib
{
public:
void attachOverflowInterrupt(void (*myFunc)());
//volatile void (*userOverflowFunction)(void); //compile error
void (* volatile userOverflowFunction)(void); //<---compiles
}
OR, if I do this instead, it compiles:
typedef void (*voidFuncPtr)(void);
class myLib
{
public:
void attachOverflowInterrupt(void (*myFunc)());
//volatile void (*userOverflowFunction)(void); //compile error
//void (* volatile userOverflowFunction)(void); //compiles
volatile voidFuncPtr userOverflowFunction; //<---compiles
}
So, what is the difference between these three things that makes the first one fail but the latter 2 compile?
volatile void (*userOverflowFunction)(void); //compile error
void (* volatile userOverflowFunction)(void); //compiles
volatile voidFuncPtr userOverflowFunction; //compiles
Background reading I have done:
Additional question:
The 1st background link above states:
"Volatile pointers to non-volatile data are very rare (I think I've used them once), but I'd better go ahead and give you the syntax:"
int * volatile p;
So, when would you use this above technique? In my case?
The problem
The statement volatile void (*userOverflowFunction)(void);
says that you have a pointer to a function returning a type volatile void
.
While a volatile void
is rather conceptual (it's easier to understand what a volatile int
is), it is yet a valid return type, and it doesn't match the return type of doSomething()
.
The solution
You said that you wanted the pointer to be volatile.
Translating this in C++ gives: void (* volatile userOverflowFunction)(void);
and here you have your first finding.
THe second finding you describe corresponds to defining a function pointer type, and then says it's a volatile pointer of that type. Both are equivalent.
Edit: additional remarks
The approach that you use is perfectly logic: your function is not volatile (as Kerrek already pointed out in the comments), but your interupt handler needs to get the value of the pointer which might have been changed in a volatile manner.
You may also be interested in reading about std::signal
. As your function pointer is not a volatile std::sig_atomic_t
, you should consider making it atomic, using your second approach: std::atomic<voidFuncPtr> userOverflowFunction;