割り込みの優先順位

 何事も、やれば良いってものではない。ものには順番というものがある。

...というわけで、割り込みにも順序というものがある。これまでも説明したように、H8/3052Fには、割り込みイベントを発生する複数のハードウエアがある。それぞれのハートウエアが「同時に割り込みイベントを発生する」などということも、世の中には有りえるのだが、CPUは同時には1つの処理しか実行できない。

 この様な場合はどうするか.....

  「面倒なので、無視する」

 と言うのも一案である。
(冗談に聞こえるかもしれないが、本当である。その程度の緊急性しかない処理なら、放っておくというのは、正しい設計と言える。)

 しかし、世の中、そう簡単には行かない。「それぞれ」に「それぞれ」の事情があって、「それぞれ」は、その事情を満たしてほしいと願うものだ。(念仏の様であるが)

 では、どうするか。

  同時に発生した割り込みは、発生したイベント毎に順位付け

 すれば良さそうである。ただし、順位付けが固定化すると、問題が生じる(場合がある)。例えば、

 有名人のかすり傷と、瀕死のパンピーが119番した時に、有名人が優先されたのでは、たまったものではない...  
   ※パンピー:一般people = 一般の人

 のである。
 この場合の優先順位(プライオリティ)は、有名/無名の差ではなく、症状の程度で左右されるべきである。従って、常にパンピーが優先されるわけでも無い。状況によって変化するということである。

  この様な問題に対応するため、H8シリーズのCPUには、場合によって、割り込みの優先順位を切り替える機構が備わっている。
 具体的には、

 インタラプト・プライオリティ・レジスタ(IPRA、IPRB) を設定する。

 事で、実現できる。

 具体的には、 IPRAのビットを1に設定すると、そのビットに対応する割り込みイベントが優先されるようになる。
 

                [IPRAのビットの定義]

割り込みイベントは沢山あるのでIPRAだけでは表現できないので、足りない分はIPRBを使っている。

                [IPRBのビットの定義]

実際のプログラミングでは、以下のようになる。

#include "monitor.h"

#define PB_DDR (*(volatile unsigned char *)0xFFFFD4)
#define PB_DR (*(volatile unsigned char *)0xFFFFD6)

#define PA_DDR (*(volatile unsigned char *)0xFFFFD1)
#define PA_DR (*(volatile unsigned char *)0xFFFFD3)

#define ISCR (*(volatile unsigned char *)0xFFFFF4)
#define IER (*(volatile unsigned char *)0xFFFFF5)
#define ISR (*(volatile unsigned char *)0xFFFFF6)

#define IPRA (*(volatile unsigned char *)0xFFFFF8)
#define IPRB (*(volatile unsigned char *)0xFFFFF9)


#pragma interrupt(irq0_handler)   // 以下に続く関数が、割り込みハンドラで
                                         // ある事を示す。
void irq0_handler()         // 割り込みハンドラの定義
{
    static int cnt = 0;

    printf("irq0=%d\n", cnt++);
}


#pragma interrupt(irq1_handler)   // 以下に続く関数が、割り込みハンドラで
                                         // ある事を示す。
void irq1_handler()         // 割り込みハンドラの定義
{
    static int cnt = 0;

    printf("irq1=%d\n", cnt++);
}

int main()
{
    long int w;

    PB_DDR = 0xFF;

    set_imask_ccr(1);   // 全ての割り込みを不許可   
    IER |= 0x3;         // IRQ0,1を有効にする。(CNX551の3,4ピン)
    ISCR = 0x3;        // IRQ0,1をエッジトリガにする。
    set_imask_ccr(0);  // 全ての割り込みを許可

   IPRA |= 0x80;      // IRQ0 優先
    while(1) {    // 無限ループ
        printf(".");
    }
}

 



割り込みのマスク(有効化/無効化)

 また、H8を含む、ほとんど全てのCPUには、割り込みの発生自体を抑止する(これを割り込みマスクと呼ぶ)仕掛けも備わっている。例えば、

  1. 有名人がかすり傷を負った。(有名人)
  2. 119番に電話して救急車を呼ぼうとした。(有名人)
  3. 症状を聞いたら、かすり傷なので、「我慢しろ」と返事した。(消防署)
  4. この様な事例があった事を、ノートに記録した。(消防署)

  この例では、1,2は割り込みイベントの発生であるが、3で割り込みがマスクされ、割り込みハンドラ(救急車の出動)は抑止された。
 しかし、事実そのものは、何らかの形で記録しておくことも必要なので、この様な処理を行った。(4の処理)

 割り込みのマスクについては、複数の割り込みを一括してマスク(もしくはマスク解除)したい場合は、

 CCRのIおよびUIビットを設定する。ただし、UIビットの動作条件は、CCRのUEビットの設定で変化する。
       ※ set_imask_ccr()関数により行う。

 であり、個別の割り込みマスクを制御したい場合は、各ハードウエアごとのレジスタを設定する。外部割り込み(IRQx)の例では、

 IERの当該ビットを設定

 である。
 また、「4の記録する」という動作についても、、各ハードウエアごとに状態がレジスタに保存される。外部割り込み(IRQx)の例では、

 ISRの当該ビットに、割り込み発生の有無が記録される。

 ことになる。 ISRの各ビットの定義は、以下のようになっている。

 bit   7   6   5   4   3   2   1   0
割り込みイベントが発生したIRQ   -   -  IRQ5F IRQ4F IRQ3F IRQ2F IRQ1F IRQ0F
初期値       0   0   0   0   0   0

 各ビットは、IRQ信号線による、割り込みイベントの発生によって1にセットされる。また、割り込みハンドラの呼び出しによって0にクリアされる。

 IERの設定によって、割り込みハンドラがマスクされている状態で、割り込みイベントが発生した場合は、該当するビットは1にセットされたままで、プログラムによってクリアする必要がある場合もある。(でないと、割り込みマスクを解除した瞬間に、保留されていた割り込みイベントに該当する割り込みハンドラが起動されるため。)

 具体的には、以下のようにする。

  ISR &= ~0x1;    // IRQ0の割り込みイベントをクリア

 とする。

 



マスク不可能な割り込み(NMI)


 話が前後するが、世の中には緊急事態と言う事もあって、どんな事があっても処理しなければならないということもある。
  マイコンの世界では、この様な割り込みを、

 NMI (Non Mascable Interrupt)  ~ マスク不可能な割り込み

 と呼んでいる。
 

なお、言うまでも無いが、割り込みをマスクする = 割り込み禁止
であり、

割り込みマスクの解除=割り込み許可
である。

 

 



割り込み周辺回路のブロック図



 

最終更新:2014年06月26日 14:26