Подтвердить что ты не робот

Безопасное обнаружение, если функция вызвана из ISR?

Я разрабатываю программное обеспечение для микроконтроллера ARM Cortex M3 (NXP LPC1769). В настоящий момент я ищу механизм, чтобы определить, вызвана ли моя функция в ISR. Я утверждаю, что мне нужно проверить регистр. Основываясь на этой информации, я хотел бы назвать сложные функции.

Я уже проверил справочное руководство, если есть регистр, содержащий необходимую информацию.

Например, я попытался определить, вызван ли я из ISR (я использовал SysTick-ISR) на основе регистра регистра активного прерывания (IABR). Этот регистр должен быть!= 0, если ISR активен. Но значение было 0x00000000. Это означает, что прерывание не активно. Помимо этого теста я проверил регистрацию NVIC и SC в справочном руководстве, в котором был найден регистр, содержащий необходимый флаг, но я не нашел его.

Кто-нибудь знает подходящий регистр/механизм для моей проблемы?

4b9b3361

Ответ 1

Вам нужно проверить поле VECTACTIVE в регистре состояния контроля прерываний.

Я использую следующее:

//! Test if in interrupt mode
inline bool isInterrupt()
{
    return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0 ;
}

SCM и SCB_ICSR_VECTACTIVE_Msk определены в CMSIS (core_cm3.h), который, как я полагаю, будет косвенно связан с вашим конкретным заголовком (lpc17xx.h или аналогичным, я думаю). Я использую С++, в том числе stdbool.h в C, вы получите тип bool или измените свой собственный int или typedef.

Затем он используется, например, следующим образом:

void somefunction( char ch )
{
    if( isInterrupt() )
    {
        // Do not block if ISR
        send( ch, NO_WAIT ) ;
    }
    else
    {
        send( ch, TIMEOUT ) ;
    }
}

Если требуется решение, которое не предполагает знания архитектуры, рассмотрите следующее:

volatile int interrupt_nest_count = 0 ;
#define ENTER_ISR() interrupt_nest_count++
#define EXIT_ISR()  interrupt_nest_count--
#define IN_ISR() (interrupt_nest_count != 0)

void isrA()
{
     ENTER_ISR() ;
     somefunction( 'a' ) ;
     EXIT_ISR() ;
}

void isrB()
{
     ENTER_ISR() ;
     somefunction( 'b' ) ;
     EXIT_ISR() ;
}

void somefunction( char ch )
{
    if( IN_ISR() )
    {
        // Do not block if ISR
        send( ch, NO_WAIT ) ;
    }
    else
    {
        send( ch, TIMEOUT ) ;
    }
}

Однако вопрос относится к безопасному обнаружению контекста прерывания, и это зависит от макросов ввода/вывода, добавляемых ко всем ISR.

Ответ 2

После некоторого обсуждения и поиска я нашел правильный регистр: Регистр состояния программы прерывания: IPSR содержит номер типа исключения текущая процедура обслуживания прерываний (ISR). См. Сводку реестра в таблице 626 для его атрибуты.

Если функция не вызывается из isr, значение регистра IPSR == 0

Ответ 3

Самый простой способ - передать контекст в качестве параметра функции. Он также независим от платформы.

typedef enum _context {
    normal_context = 0,
    isr_context = 1
} context;

Вызов функции из ISR:

func(param1, param2, isr_context);

Вызов функции из обычного кода:

func(param1, param2, normal_context);

Если код ISR не находится под вашим контролем, и вы просто передаете указатель на функцию, просто используйте две различные функции-обертки. Один, который передает isr_context, а другой, который передает normal_context в качестве параметра функции.

Ответ 4

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

Если это не вариант, вы можете определить вызывающего абонента с чистым стандартом C, не нужно никаких регистров:

inline void my_func (const char* caller);

static void isr (void)
{
  my_func(__func__);
}


inline void my_func (const char* caller)
{
  if(strcmp(caller, "isr")==0)
  {
    // was called from isr
  }
  else
  {
    // called from elsewhere
  }
}

Если вы дадите свои интеллектуальные имена ISR, приведенный выше код будет достаточно быстрым для запуска из isr.