マイクロコンピュータH8/3664におけるタイマ割り込み

23May2004
Copyright(C) coskx

1.はじめに
タイマ割り込を中心に割り込みの記述について説明している。

2.ユーザから見た小坂の開発環境のタイマ割り込み
ユー ザはh8_3664.h中にある「タイマ割り込み初期化関数」と「CPUの割り込み許可関数E_INT()」を呼び,「タイマ起動関数」を呼ぶと,「タイ マ割り込み初期化関数」で設定した時間間隔でタイマ割り込みが起こり,「割り込み関数interrupt_cfunc() 」が周期的に起動するようになる。

なお「タイマ割り込み初期化関数」と「タイマ起動関数」「タイマ停止関数」は次のようになっている。
void initTimerAInt(short int n)
  TimerAを利用したタイマー割り込み初期化
 引数の値とタイマー割り込み周波数
  7    7812.5[Hz]
  6    1953.125[Hz]
  5     488.28125[Hz]
  4     244.140625[Hz]
  3     122.0703125[Hz]
  2      30.51757813[Hz]
  1      15.25878906[Hz]
  0       7.629394531[Hz]

void startTimerAInt(void)
  TimerAを利用したタイマー割り込みスタート
void stopTimerAInt(void)
 TimerAを利用したタイマー割り込みストップ

3.タイマ割り込みの仕組み
 H8CPU内部には 「タイマユニット」があり,その中にはシステムクロックをカウントアップするカウンタと,設定された値を保持しているレジスタがあり,この2つの値が一致 することによって割り込み要求信号を発生している。割り込み要求信号が発生すると同時にカウンタはリセットされるため,割り込み要求信号は周期的に発生す ることになる。(発生した割り込み要求信号は割り込み処理手続きの中で消さなければならない。)タイマユニットがこのような動作をするためには事前にこの ような動作をするように設定が必要である。
 CPUが割り込み許可状態で,割り込み要求信号を受け取ると,タイマ割り込み処理が始まる。
  タイマ割り込みが生ずると,メモリアドレスの先頭付近に置かれた割り込みベクタテーブル(割り込みが起こったらどのアドレスにジャンプするかのアドレス 表)中から,タイマ割り込みの時に参照するベクタ(具体的には割り込み関数の先頭アドレス)を取り出し,そのアドレスにジャンプする。(正確に は,CCR[コンディションコードレジスタ]と現在のPC[プログラムカウンタ]を退避させてから,割り込み関数呼び出しする)

割り込み関数は,次の作業を行なわなければならない。

(1)はじめに各レジスタの値をスタックに退避する
(2)タイマユニットの割り込みを禁止にする
(3)タイマユニットの割り込みフラッグをクリアする(割り込み作業が終了したことを知らせ,次の割り込みの準備をする)
(4)必要な作業を行なう
(5)タイマユニットの割り込みを許可する
(6)各レジスタにスタックから退避させた値を復帰する
(7)割り込みリターンする(通常の関数では関数リターン)

ここで小坂の仕掛けでは,多少時間は浪費するが以下のようにスタートアップファイル中に記述している。

(1)割り込みベクタ 0X26 に TIME_Aのアドレスを書いておく(関数interrupt_cfunc() のアドレスではない)
(割り込みベクタは2バイトである。)
(2)アドレスTIME_Aのところには次の内容を書いておく
   1)各レジスタの値をスタックに退避する
   2)タイマユニットの割り込みを禁止にする
   3)タイマユニットの割り込みフラッグをクリアする
   4)関数interrupt_cfunc() を呼び出す
   5)タイマユニットの割り込みを許可する
   6)各レジスタにスタックから退避させた値を復帰する
   7)割り込みリターンする

具体的には次のように書いてある。

ベクタテーブル部
    .ORG H'0026
    .DATA.W TIME_A  ;タイマーA割り込みベクトル

割り込み関数部
IENR1 .EQU H'FFF4  ;割り込みイネーブルレジスタ
IRR1 .EQU H'FFF6  ;割り込みフラグレジスタ
IENTA .BEQU 6,IENR1  ;タイマーAイネーブルビット
IRRTA .BEQU 6,IRR1  ;タイマーA割り込みフラグビット
TIME_A: PUSH.L ER0
    PUSH.L ER1
    PUSH.L ER2
    PUSH.L ER3
    PUSH.L ER4
    PUSH.L ER5
    PUSH.L ER6
    BCLR IENTA  ;割り込み停止
    BCLR IRRTA  ;割り込みフラグをクリアー
   
    JSR @_interrupt_cfunc

    BSET IENTA  ;割り込み再開

    POP.L ER6
    POP.L ER5
    POP.L ER4
    POP.L ER3
    POP.L ER2
    POP.L ER1
    POP.L ER0
    RTE

この結果,小坂の仕掛けを使用する立場から見ると,タイマ割り込みが生ずると関数interrupt_cfunc() が呼ばれているように見えるし,また関数interrupt_cfunc() 内で次の作業は行なう必要がない。

(1)はじめに各レジスタの値をスタックに退避する
(2)タイマユニットの割り込みを禁止にする
(3)タイマユニットの割り込みフラッグをクリアする(割り込み作業が終了したことを知らせ,次の割り込みの準備をする)
(5)タイマユニットの割り込みを許可する
(6)各レジスタにスタックから退避させた値を復帰する
(7)割り込みリターンする(通常の関数では関数リターン)