开发者

Interrupt-safe way to set function pointer in HiTech C on PIC32

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);

    callbackW开发者_开发知识库ritten = (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)


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)

void (*myCallback)() = NULL;        

void RegisterCallback(void (*callback)())        
{        
   myCallback = callback;
}        

void interrupt MyExternalInterrupt() @EXTERNAL_1_VCTR        
{        
   // Do a bunch of other things here...        

   if (myCallback!=NULL)
      myCallback();        
   myCallback = NULL;        
}  

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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜