Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safely detect, if function is called from an ISR?

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?

like image 438
ferraith Avatar asked May 20 '13 19:05

ferraith


2 Answers

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.

like image 126
Clifford Avatar answered Nov 13 '22 03:11

Clifford


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

like image 20
ferraith Avatar answered Nov 13 '22 04:11

ferraith