I have an ISR defined to trigger on an external interrupt. The external interrupt may not always be enabled, but under certain circumstances I want to be able to register a function to be called ONCE within the interrupt from within the main code. The function might be replaced by another one, or removed, before the next interrupt.
I don't know much about techniques for synchronisation on the PIC32, but I've come up with the following:
volatile BOOL callbackInterrupted = FALSE;
volatile BOOL callbackWritten = FALSE;
void (*myCallback)() = NULL;
void RegisterCallback(void (*callback)())
{
do
{
callbackWritten = FALSE;
myCallback = callback;
}
while(callbackInterrupted);
callbackWritten = (callback != NULL);
}
void interrupt MyExternalInterrupt() @EXTERNAL_1_VCTR
{
// Do a bunch of other things here...
if(callbackWritten)
{
myCallback();
myCallback = NULL;
callbackInterrupted = TRUE;
callbackWritten = FALSE;
}
}
I'm having trouble reasoning about it though. Does this actually do what I hope, ie. prevent the ISR calling a half-set function pointer, or calling a function twice? Is the do ... while
loop superfluous? Is there a better way?
Added: disabling this interrupt is out of the question. It is used for timing.
Instructions generated for flag = TRUE
:
lui s1,0x0
ori s1,s1,0x1
addiu at,s1,0
or t0,at,zero
Instructions generated for fnc1 = &testfunc
:
lui a2,0x9d00
ori a2,a2,0x50
or a1,a2,zero
sw a1,16376(gp)
I would use only a function pointer and check that for non-null in the interrupt, call and set it to null. Where you set the pointer the standard solution would be to disable interrupts.
Assuming setting the bool is an atomic operation (disassemble & read the manual to be sure) - I would use a flag to set the function pointer, but this flag shold only be read by the ISR, and only written by the normal code, giving you a simple semaphore. If writing the function pointer is atomic (again, check by disassembling), you can use it instead of the flag.
Like this (off the top of my head)
Edit After seeing disassembled instructions, using the function pointer as a flag will work. Modified code to show usage.
Given the fact that the ISR is there to time pulses why call the function within the ISR at all? Why not call it in the main code where ever it is that the main code checks up on the results of the pulse timing?
If your answer is that its critical the code is executed on the fire of the ISR, then i assume its also critical that you have the opportunity to set a function to call prior to every execution of the interrupt. In this case your only options are to determine the proper function to call for the next interrupt within the ISR or to disable the interrupt while you determine the proper function to call elsewhere in the code. If timing is critical you should also make sure this ISR can't be bumped by a higher priority interrupt.