Безопасный от прерывания способ установить указатель функции в HiTech C на PIC32 - PullRequest
2 голосов
/ 28 января 2010

У меня определен ISR для запуска по внешнему прерыванию. Внешнее прерывание не всегда может быть включено, но при определенных обстоятельствах я хочу иметь возможность зарегистрировать функцию, которая будет вызываться ONCE, внутри прерывания из основного кода. Функция может быть заменена другой или удалена до следующего прерывания.

Я не знаю много о методах синхронизации на PIC32, но я придумал следующее:

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

Хотя мне сложно рассуждать об этом. Делает ли это на самом деле то, что я надеюсь, т.е. запретить ISR вызывать указатель на половинную функцию или дважды вызывать функцию? Является ли петля do ... while лишней? Есть ли лучший способ?

Добавлено: отключение этого прерывания исключено. Используется для определения времени.

Инструкции для flag = TRUE:

lui         s1,0x0
ori         s1,s1,0x1
addiu       at,s1,0
or          t0,at,zero

Инструкции для fnc1 = &testfunc:

lui         a2,0x9d00
ori         a2,a2,0x50
or          a1,a2,zero
sw          a1,16376(gp)

Ответы [ 3 ]

2 голосов
/ 28 января 2010

Предполагая, что установка bool является атомарной операцией (для уверенности разберите и прочитайте руководство) - я бы использовал флаг для установки указателя функции, но этот флаг должен читаться только ISR и записываться только обычным код, давая вам простой семафор. Если написание указателя на функцию является атомарным (опять же, проверьте путем разборки), вы можете использовать его вместо флага.

Вот так (с макушки головы)

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

Редактировать После просмотра разобранных инструкций сработает указатель функции в качестве флага. Модифицированный код для отображения использования.

1 голос
/ 28 января 2010

Учитывая тот факт, что в ISR присутствуют импульсы времени, зачем вообще вызывать функцию в ISR? Почему бы не назвать его в основном коде, где бы он ни был, чтобы основной код проверял результаты синхронизации импульсов?

Если вы ответили, что критично, то код выполняется в огне ISR, тогда я предполагаю, что также критично, что у вас есть возможность установить функцию для вызова до каждого выполнения прерывания. В этом случае ваши единственные варианты - определить правильную функцию для вызова следующего прерывания в ISR или отключить прерывание, пока вы определяете правильную функцию для вызова в другом месте кода. Если время имеет решающее значение, вы также должны убедиться, что этот ISR не может быть прерван прерыванием с более высоким приоритетом.

0 голосов
/ 28 января 2010

Я бы использовал только указатель на функцию и проверил бы, что в прерывании он не равен нулю, вызову и установлю его на нуль. Там, где вы устанавливаете указатель, стандартным решением будет отключение прерываний.

...