19

ARM Cortex M3 (NXP LPC1769) マイクロコントローラ用のソフトウェアを開発しています。現在、関数が ISR 内で呼び出されているかどうかを検出するメカニズムを探しています。レジスターをチェックする必要があると思います。この情報に基づいて、難しい関数を呼び出したいと思います。

必要な情報を含むレジスターがあるかどうか、リファレンスマニュアルを確認しました。

たとえば、「割り込みアクティブ ビット レジスタ」(IABR) レジスタに基づいて、ISR (SysTick-ISR を使用) から呼び出されたかどうかを検出しようとしました。ISR がアクティブな場合、このレジスタは != 0 である必要があります。しかし、値は 0x00000000 でした。これは、アクティブな割り込みがないことを意味します。このテストに加えて、リファレンス マニュアルで NVIC および SC レジスタを調べて、必要なフラグを含むレジスタを探しましたが、見つかりませんでした。

私の問題に適したレジスタ/メカニズムを知っている人はいますか?

4

4 に答える 4

29

Interrupt Control State Registerの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に追加されている開始/終了マクロに依存しています。

于 2013-05-21T13:42:24.110 に答える
15

いくつかの議論と検索の後、適切なレジスタを見つけました。 割り込みプログラム ステータス レジスタ: IPSR には、現在の割り込みサービス ルーチン (ISR) の例外タイプ番号が含まれています。その属性については、表 626 のレジスタの概要を参照してください。

関数が isr から呼び出されない場合、レジスタの値は IPSR == 0 です。

于 2013-05-20T20:30:18.663 に答える
0

最も簡単な方法は、コンテキストをパラメーターとして関数に渡すことです。また、プラットフォームに依存しません。

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

ISR から関数を呼び出します。

func(param1, param2, isr_context);

通常のコードから関数を呼び出します。

func(param1, param2, normal_context);

ISR コードが制御下になく、関数ポインターを渡すだけの場合は、2 つの異なるラッパー関数を使用してください。1 つは isr_context を渡し、もう 1 つは normal_context をパラメーターとして関数に渡します。

于 2013-05-20T20:07:31.783 に答える