Question

I'm developing software for an ARM Cortex M3 (NXP LPC1769) microncontroller. At the moment I'm searching for a mechansim to detect if my function is called within an ISR. I asume that I have to check a register. Based on this information I would like to call difficult functions.

I already checked the reference manual, if there is a register containing the necessary information.

For example I tried to detect if I'm called from an ISR (I used SysTick-ISR) based on the "Interrupt Active Bit Register" (IABR) register. This register should be != 0 if an ISR is active. But the value was 0x00000000. This implies that no interrupt is active. Besides this test I checked the NVIC and SC register in the reference manual searching for a register containing the necessary flag but I didn't found one.

Does anybody know a suitable register / mechanism for my problem?

Was it helpful?

Solution

You need to test the VECTACTIVE field of the Interrupt Control State Register.

I use the following:

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

SCM and SCB_ICSR_VECTACTIVE_Msk are defined in the CMSIS (core_cm3.h), which I imagine would be included indirectly by your part specific header (lpc17xx.h or similar I guess). I am using C++, including stdbool.h in C will get you a bool type, or change to an int or typedef of your own.

It is then used thus for example:

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

If a solution is required that assumes no knowledge of the architecture consider the following:

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

However the question refers to safely detecting the interrupt context, and this relies on the enter/exit macros being added to all ISRs.

OTHER TIPS

After some discussion and more searching I found the right register: Interrupt Program Status Register: The IPSR contains the exception type number of the current Interrupt Service Routine (ISR). See the register summary in Table 626 for its attributes.

If a function isn't called from an isr the value of the register is IPSR == 0

The simplest method is to pass the context as a parameter to the function. It is also platform independent.

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

Call to the function from ISR:

func(param1, param2, isr_context);

Call to the function from normal code:

func(param1, param2, normal_context);

If the ISR code is not under your control and you are just passing a function pointer, then just use two different wrapper functions. One that passes isr_context and another that passes normal_context as a parameter to the function.

The best way is probably to make two different functions: one that is called from the ISR and another that is called from the rest of the program.

If that isn't an option, then you could determine the caller with pure standard C, no registers needed:

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

If you give your ISRs smart names, the above code will be quick enough to run from an isr.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top