H8の割り込み

H8/3052Fには、様々なハードウエアが組み込まれている。この中で、割り込みを発生する周辺装置(デバイスという)は、以下のように複数ある。



  CPUは、これらの周辺デバイスが発生する割り込みを識別して、それぞれに合った処理(割り込みハンドラ)を行う必要がある。このために、それぞれの割り込みに対して、処理する割り込みハンドラを対応付けする必要がある。これを行うのが、割り込みベクタと呼ばれる表で、メモリの特定のアドレスに、割り込みベクタを配置している。(セクションのCVECTBLで、0xFE110から始まる256Byteの領域で、monitor.hの VectorTable配列として定義している。)
 この場合、ベクタ番号は配列の添字に相当する。

 ベクタ番号  アドレス  種類  説明
0 FFE110 リセット 電源投入/リセット入力時
1 FFE114 予約  
2 FFE118 予約  
3 FFE11C 予約  
4 FFE120 予約  
5 FFE124 予約  
6 FFE128 予約  
7 FFE12C NMI マスク不能割り込み(緊急時に利用)
8 FFE130 TRAP0 トラップ命令により発生
9 FFE134 TRAP1       〃
10 FFE138 TRAP2       〃
11 FFE13C TRAP3       〃
12 FFE140 IRQ0 外部割り込み
13 FFE144 IRQ1       〃
14 FFE148 IRQ2       〃
15 FFE14C IRQ3       〃
16 FFE150 IRQ4       〃
17 FFE154 IRQ5       〃
18 FFE158 予約  
19 FFE15C 予約  
20 FFE160 WOVI ウォッチドッグ(番犬)タイマ。システムの誤動作検出に使用
21 FFE164 CMI リフレッシュコントローラ(DRAM接続時に使用)
22 FFE168 予約  
23 FFE16C 予約  
24 FFE170 IMIA0 ITUチャネル0 (コンペアマッチ/インプットキャプチャA0)
25 FFE174 IMIB0 ITUチャネル0 (コンペアマッチ/インプットキャプチャB0)
26 FFE178 OVI0 ITUチャネル0 (オーバフロー0)
27 FFE17C 予約  
28 FFE180 IMIA1 ITUチャネル1 (コンペアマッチ/インプットキャプチャA1)
29 FFE184 IMIB1 ITUチャネル1 (コンペアマッチ/インプットキャプチャB1)
30 FFE188 OVI1 ITUチャネル1 (オーバフロー1)
31 FFE18C 予約  
32 FFE190 IMIA2 ITUチャネル2 (コンペアマッチ/インプットキャプチャA2)
33 FFE194 IMIB2 ITUチャネル2 (コンペアマッチ/インプットキャプチャB2)
34 FFE198 OVI2 ITUチャネル2 (オーバフロー2)
35 FFE19C 予約  
36 FFE1A0 IMIA3 ITUチャネル3 (コンペアマッチ/インプットキャプチャA3)
37 FFE1A4 IMIB3 ITUチャネル3 (コンペアマッチ/インプットキャプチャB3)
38 FFE1A8 OVI3 ITUチャネル3 (オーバフロー3)
39 FFE1AC 予約  
40 FFE1B0 IMIA4 ITUチャネル4 (コンペアマッチ/インプットキャプチャA4)
41 FFE1B4 IMIB4 ITUチャネル4 (コンペアマッチ/インプットキャプチャB4)
42 FFE1B8 OVI4 ITUチャネル4 (オーバフロー4)
43 FFE1BC 予約  
44 FFE1C0 DEND0A DMAC
45 FFE1C4 DEND0B       〃
46 FFE1C8 DEND1A       〃
47 FFE1CC DEND1B       〃
48 FFE1D0 予約  
49 FFE1D4 予約  
50 FFE1D8 予約  
51 FFE1DC 予約  
52 FFE1E0 ERI0 SCI0 受信エラー0
53 FFE1E4 RXI0 SCI0 受信データ・フル0
54 FFE1E8 TXI0 SCI0 送信データエンプティ0
55 FFE1EC TEI0 SCI0 送信終了0
56 FFE1F0 ERI1 SCI1 受信エラー1
57 FFE1F4 RXI1 SCI1 受信データ・フル1
58 FFE1F8 TXI1 SCI1 送信データエンプティ1
59 FFE1FC TEI1 SCI1 送信終了1
60 FFE200 ADI AD変換終了

                             H8/3052Fの割り込みベクタ
 


 ■実際のプログラミング


(1)割り込みハンドラの定義
  割り込みハンドラというと、特別な関数のように聞こえるかもしれないが、書き方は通常の関数と同じ。ただ、関数の宣言の前に

#pragma interrupt(割り込みハンドラの関数名)

を記述しておくこと。

(2)割り込みハンドラをベクタテーブルに登録
 monitor.hに定義されているベクタテーブルに、割り込みハンドラの関数名を記述する。

(3)割り込みマスクと優先順位に関する設定を行う。

  • システム・コントロール・レジスタ(SYSCR)のI ビットを1にし、設定されている全割り込みを禁止にする。(設定中に割り込みが発生して、おかしな事にならないようにするため)

SYSCRのI ビットを制御するには、

  set_imask_ccr(1);  // SYSCRのI ビットを1に設定し、全割り込みを不許可にする。

 

 

もしくは、

set_imask_ccr(0);  // SYSCRのI ビットを0に設定し、全割り込みを許可する。

とする。

【注意】
set_imask_ccr関数を呼び出すには、monitor.hの先頭付近に

#include <machine.h>

を入れておくこと。... でないと、コンパイルエラーが発生する。
 

  • システム・コントロール・レジスタ(SYSCR)のUEビットを、必要に応じて設定する。UEビットの詳細はこちら
  • 割り込み優先順位の設定。必要に応じて、インタラプト・プライオリティ・レジスタ(IPRA、IPRB)を設定する。
  • 外部割り込み(IRQ)を使う場合は、IRQイネーブルレジスタ(IER)を設定する。その他のハードウエアが発生する割り込みについては、各ハードウエアの設定を行うレジスタで対応する。

  以下のように示すように、IERの各ビットが、IRQの信号線に対応している。(IRQxEが、IRQx信号線に対応)

 bit       7      6        5        4        3        2        1        0
 IRQ名       IRQ5E  IRQ4E  IRQ3E  IRQ2E  IRQ1E  IRQ0E
初期値       0      0        0        0        0        0        0        0

IRQxEの値を1にすれば、該当するIRQx信号線による割り込みが有効になる。

  • 外部割り込み(IRQ)を使う場合は、割り込みの発生用件にレベルトリガかエッジトリガかを選択する。
  • システム・コントロール・レジスタ(SYSCR)のI ビットを0にし、設定されている全割り込みを許可する。これ以降、何らかの割り込みイベントの発生によって、ベクタテーブルに割り当てられた割り込みハンドラが呼び出される。
     

 以下は、外部割り込み信号線(IRQ0)にイベント(信号の立下り:エッジトリガ)が発生した時に、割り込みハンドラirq0_handlerを呼び出すプログラムの例。 main関数と割り込みハンドラの記述、およびベクタテーブルへの割り込みハンドラの登録例を示したもの。
  (割り込みに関連する記述を赤字で示した。)
※ 外部割り込み信号線と、マイコンボード上の端子との関係は、回路図を参照のこと。

#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)

#pragma interrupt(irq0_handler)   // 以下に続く関数が、割り込みハンドラで
                                              // ある事を示す。

void irq0_handler()         // 割り込みハンドラの定義
{
    printf("\n");
}


int main()
{
    long int w;

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

    
    while(1) {    // 無限ループ
        for(w=0; w<999999; w++);
        printf(".");
    }
}

             割り込みハンドラとmain関数の記述例
 

#define  printf  ((int (*)(const char *,...))0x00002b52)
#define  scanf  ((int (*)(const char *,...))0x00002ba4)

#pragma section VECTBL

void PowerON_Reset();

void irq0_handler();   // 割り込みハンドラのプロトタイプ宣言
                                 //  (これが無いとコンパイルエラーになる)

typedef void (*fp)(void);

const fp VectorTable[] =     // ベクタテーブルの定義
{
    (fp)PowerON_Reset,       //  vector  0 Reset
    (fp)0L,                  //  vector  1 Reserved
    (fp)0L,                  //  vector  2 Reserved
    (fp)0L,                  //  vector  3 Reserved
    (fp)0L,                  //  vector  4 Reserved
    (fp)0L,                  //  vector  5 Reserved
    (fp)0L,                  //  vector  6 Reserved
    (fp)0L,                  //  vector  7 NMI
    (fp)0L,                  //  vector  8 TRAP
    (fp)0L,                  //  vector  9 TRAP
    (fp)0L,                  //  vector 10 TRAP
    (fp)0L,                  //  vector 11 TRAP
    (fp)irq0_handler,//  vector 12 IRQ0   IRQ0割り込みを処理する割り込みハンドラを登録
    (fp)0L,                  //  vector 13 IRQ1
    (fp)0L,                  //  vector 14 IRQ2
    (fp)0L,                  //  vector 15 IRQ3
    (fp)0L,                  //  vector 16 IRQ4
    (fp)0L,                  //  vector 17 IRQ5
    (fp)0L,                  //  vector 18 [reserved]
    (fp)0L,                   //  vector 19 [reserved]
    (fp)0L,                  //  vector 20 Watch Dog Timer
    (fp)0L,                  //  vector 21 Refresh
    (fp)0L,                  //  vector 22 [reserved]
    (fp)0L,                  //  vector 23 [reserved]
    (fp)0L,                  //  vector 24 ITU0 IMIA0
    (fp)0L,                  //  vector 25 ITU0 IMIB0
    (fp)0L,                  //  vector 26 ITU0 OVI0
    (fp)0L,                  //  vector 27 [reserved]
    (fp)0L,                  //  vector 28 ITU1 IMIA1
    (fp)0L,                  //  vector 29 ITU1 IMIB1
    (fp)0L,                  //  vector 30 ITU1 OVI1
    (fp)0L,                  //  vector 31 [reserved]
    (fp)0L,                  //  vector 32 ITU2 IMIA2
    (fp)0L,                  //  vector 33 ITU2 IMIB2
    (fp)0L,                  //  vector 34 ITU2 OVI2
    (fp)0L,                  //  vector 35 [reserved]
    (fp)0L,                  //  vector 36 ITU3 IMIA3
    (fp)0L,                  //  vector 37 ITU3 IMIB3
    (fp)0L,                  //  vector 38 ITU3 OVI3
    (fp)0L,                  //  vector 39 [reserved]
    (fp)0L,                  //  vector 40 ITU4 IMIA4
    (fp)0L,                  //  vector 41 ITU4 IMIB4
    (fp)0L,                  //  vector 42 ITU4 OVI4
    (fp)0L,                  //  vector 43 [reserved]
    (fp)0L,                  //  vector 44 DMAC DEND0A
    (fp)0L,                  //  vector 45 DMAC DEND0B
    (fp)0L,                  //  vector 46 DMAC DEND1A
    (fp)0L,                  //  vector 47 DMAC DEND1B
    (fp)0L,                  //  vector 48 [reserved]
    (fp)0L,                  //  vector 49 [reserved]
    (fp)0L,                  //  vector 50 [reserved]
    (fp)0L,                  //  vector 51 [reserved]
    (fp)0L,                  //  vector 52 SCI0 ERI0
    (fp)0L,                  //  vector 53 SCI0 RXI0
    (fp)0L,                  //  vector 54 SCI0 TXI0
    (fp)0L,                  //  vector 55 SCI0 TEI0
    (fp)0L,                  //  vector 56 SCI1 ERI1
    (fp)0L,                  //  vector 57 SCI1 RXI1
    (fp)0L,                  //  vector 58 SCI1 TXI1
    (fp)0L,                  //  vector 59 SCI1 TEI1
    (fp)0L                   //  vector 60 ADI
};

#pragma section /* セクション名を省略すると、プログラム領域はP、定数領域はC、                      初期化データ領域はR,D、未初期化データ領域はBとなる。
                        */              

int main(void);

__entry void PowerON_Reset(void)
{
    main();    //スタートルーチンを呼び出し
    printf("program ended. push reset");
    sleep();    
}

                              monitor.hの内容とベクタテーブルの定義
 



多重割り込み

  H8/3052Fの割り込み処理では、割り込みハンドラ内部では、デフォルトで他の割り込みは禁止されている。(set_imask_ccr(1)の状態)従って、割り込みハンドラの処理中に、その他の割り込みイベントが発生しても、割り込みハンドラが新たに起動されることは無い。(つまり、多重割り込み禁止の状態)
 現実のプログラミングでは、ある割り込みハンドラ(例えばIRQ0)実行時に、他の割り込み処理(例えばIRQ1)を受け付けたい場合も存在する。(つまり、割り込み処理実行中に、他の割り込み処理を受け付ける事。同じ割り込みでも良い)こういうのを多重割り込みと呼ぶ。

 多重割り込みを受け付けるには、割り込みハンドラ内で、

 set_imask_ccr(0)

 を実行すればよい。



多重割り込みとリエントラント

 

最終更新:2015年01月26日 15:13