如果从ISR调用函数,则安全检测?

时间:2013-05-20 19:01:40

标签: embedded cortex-m3

我正在为ARM Cortex M3(NXP LPC1769)微控制器开发软件。目前我正在寻找机制以检测我的功能是否在ISR中被调用。我认为我必须检查一个寄存器。基于这些信息,我想称之为困难的功能。

如果有一个包含必要信息的寄存器,我已经检查了参考手册。

例如,我试图根据“中断有效位寄存器”(IABR)寄存器检测我是否从ISR(我使用SysTick-ISR)调用。如果ISR处于活动状态,该寄存器应为!= 0。但值为0x00000000。这意味着没有中断处于活动状态。除了这个测试,我在参考手册中检查了NVIC和SC寄存器,搜索包含必要标志的寄存器,但我没有找到。

是否有人知道我的问题适合的注册/机制?

4 个答案:

答案 0 :(得分:27)

您需要测试中断控制状态寄存器 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或类似的猜测)间接包含在内。我正在使用C ++,包括在C中的stdbool.h会得到一个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中的进入/退出宏。

答案 1 :(得分:14)

经过一番讨论和搜索后,我找到了合适的注册表: 中断程序状态寄存器:IPSR包含异常类型编号 当前的中断服务程序(ISR)。请参阅表626中的寄存​​器摘要 它的属性。

如果未从isr调用函数,则寄存器的值为IPSR == 0

答案 2 :(得分:2)

最简单的方法是将上下文作为参数传递给函数。它也是独立于平台的。

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作为参数传递给函数。

答案 3 :(得分:2)

最好的方法可能是创建两个不同的函数:一个是从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运行。