割り込み処理の記述


 割り込み処理は組み込みシステムでは重要な処理で、マイコンのシステムでは
必ず必要になります。MPLAB C30コンパイラでは、この割り込み処理の記述を
C言語だけで記述できるようになっています。

【割り込み処理関数の記述】

 16ビットPICファミリの割り込みは、内蔵周辺モジュールの動作に関連するイベント
で発生し、特定の割り込みベクタにジャンプします。この割り込みベクタを使って対応
する割り込み処理ルーチン(これを割り込みサービスルーチン(ISR)と呼ぶ)にジャンプ
するようになっています。
 したがって割り込み処理を記述するには、割り込みサービスルーチンの作成と、割り
込みベクタの作成が必要になります。

 この割り込みサービスルーチンを記述する場合に注意すべき点がいくつかあります。
(1) 割り込みサービスルーチンはパラメータなし戻り値なしとすること
  MPLAB C30では、割り込みサービスルーチンを独立の関数として記述します。
  そしてこの割り込みサービスルーチンは、もともとハードウェアの割り込みで呼び出される
  わけですので、呼び出し元関数がないわけですから、パラメータや戻り値を持つことは
  できません。

(2) 割り込みサービスルーチンをmain関数から呼んではならない
  割り込みサービスルーチンは通常の関数と異なり、RETURN命令ではなくRETFIE命令
  で戻りますから、main関数などから呼び出すと、その後の割り込みが正常に実行され
  なくなります。

(3) 割り込みサービスルーチンから他の関数を呼ばない方がよい
  割り込みサービスルーチンでは、通常の関数と同じようにローカル変数を持つことも
  できますし、グローバル変数にもアクセスできます。しかし、割り込みサービス関数から
  他の関数をコールすると、その時点のレジスタをすべてスタックに保存し、戻るとき復帰
  させますので処理時間が遅くなります。したがって、できるだけ他の関数を呼ばないよう
  に記述する方が効率的な処理となります。

(4) 割り込みフラグのクリア記述が必要
  この修飾で生成される割り込みサービスルーチンでは、割り込みフラグのクリアは行い
  ませんので、この処理はユーザーが追加記述する必要があります。

【割り込み処理関数の構文】


 MPLAB C30には、関数の修飾のアトリビュートに割り込み処理関数とする修飾が用意
されています。
 この__attribute__を使って関数の属性を指定することで、その関数が割り込みサービス
ルーチンとなります。この属性指定の構文は下記のようになります。


 最初の__interrupt__(またはinterrupt)属性で この修飾を付けた関数が割り込みサービス
ルーチン関数であることを定義します。
 オプションの__save__(またはsave)はsymbol-listで指定した変数列を割り込み処理で退避、
復旧するよう指定します。変数のシンボルを括弧内にカンマで区切って並べて指定します。
ただし普通は、Wレジスタは自動的に退避、復旧されますので、特別に保存する場合以外
には必要ありません。
 この標準の自動退避、復旧の代わりにシャドーレジスタを使って高速に退避、復旧するよう
指示するには、__shadow__パラメータを使います。

 オプションの__irq__(またはirq)パラメータは、この関数で処理する割り込みベクタを指定し、
()内に割り込みベクタ番号を記述します。
 __altirq__(またはaltirq)は同じように代替割り込みベクタを指定します。

 実際の記述では、__irq__や__altirq__パラメータを指定する代わりに、別途割り込みベクタごと
に用意されているIRQ用既定ラベルで指定します。こうすればこのパラメータを省略することが
できます。このirqを記述すると、指定したIDの割り込みベクタに、この定義した割り込み
サービス関数の開始番地が自動的に設定されます。

 オプションの__preprologue__(またはpreprologue)パラメータが指定されると、割り込み処理
関数としてコンパイラが自動生成する前処理preprologueと後処理epilogueというシーケンス
の中のpreprologueの直前に、asmで指定されたアセンブリ言語文を挿入します。

 __auto_psv__(またはauto_psv)および__no_auto_psv__(またはno_auto_psv)は、割り込み処理
関数内でPSVPAGレジスタの退避、復旧を行うかどうかを指定します。指定しない場合には
デフォルトでauto_psvとなり、PSVPAGレジスタの退避復旧を行うようにし、コンパイラが
warningメッセージを出力します。

 実際の記述は下記のようにします。



【割り込み処理関数用マクロ】

 割り込みに関する処理をする割り込みサービスルーチン(ISR)の記述にはマクロが
用意されており、このマクロにより簡単な書式で割り込みサービスルーチンを記述する
ことができるようになっています。
 Cの関数を割り込みサービスルーチンとするためには、下表の2種類のマクロの
いずれかを使って関数を宣言します。このマクロは最も単純な割り込み処理関数を
生成します。Wレジスタなどのコンテキストの保存と復帰のプログラム部も自動的に
生成されますので、ユーザーがレジスタ保存復帰のプログラムを記述する必要は
ありません。
 ただし、auto_psvには対応していないので、warningメッセージが出ます。
マクロ 機能と等価なattribute書式 記述例
_ISR 一般的なISR関数を宣言する。
これは下記と等価
__attribute__((interrupt))
void _ISR _T1Interrupt(void)
_ISRFAST シャドーレジスタを使って高速コンテ
キスト保存を行うISR関数を宣言する。
これは下記と等価
__attribute__((interrupt, shadow))
void _ISRFAST _ADCInterrupt(void)

【割り込みIRQ用既定ラベル】

上表の記述例にある _T1Interrupt とか _ADCInterrupt という記述は、あらかじめ
内蔵モジュールごとに定義されている割り込みベクタテーブルの既定ラベルです。
この定義されている名称を使えば、irqパラメータを指定したのと同じ効果となり、割り込み
ベクタテーブルが自動的に生成されます。
 例としてPIC24Fファミリ用の割り込みベクタテーブルの既定ラベルを下表に示します。
割り込みベクタテーブルには、主と代替の2つがありますので既定ラベルも両方別々に
定義されています。
IRQ69からIRQ117は未使用でReservedとなっています。上記以外に、どれでもない
割り込み用に、_DefaultInterruptというラベルも定義されていて、特定のハンドラを
持たないすべての割り込み処理関数として用意されています。
この割り込み処理では単にデバイスをリセットします。

表:割り込みベクタテーブルとラベル




【割り込みの禁止許可】

 実際に特定のモジュールの割り込みを許可するためには、下記の設定が必要
なりますが、いずれも割り込み制御用のSFRで制御できるようになっています。
この割り込み制御用レジスタの内容の、全体一覧の例を下図に示します。
 IFSnレジスタには各割り込みごとの割り込み発生を示す割り込みフラグがあります。
 IECnレジスタには、各割り込みごとの割り込み許可ビットがあります。
 IPCnレジスタには、各割り込みごとに3ビットづつの割り込み優先レベル設定ビットがあります。

表:割り込み制御用レジスタ例(PIC24Fの例)






【割り込みの許可手順】
 各割り込み要因ごとに割り込みを許可するには下記の手順で行います。

(1) 割り込み要因の割り込みを許可する
  各内蔵モジュールの割り込み要因には、割り込みを許可禁止するための
  ビット(xxxIE)がIECnレジスタに用意されています。このビットを1にすれば
  そのモジュールの割り込みが許可されます。xxxIEビットはIECnレジスタに
  ベクタ番号順に用意されています。したがってたとえばタイマ1の割り込み
  を許可するためには下記のように記述します。

     IEC0bits.T1IE = 1;
 
(2) 割り込み要因の割り込み優先レベルを設定する
  各内蔵モジュールの割り込み要因には、割り込み優先レベルを指定する
  ビット(xxxIP<2:0>)が用意されています。このビットはいずれも3ビット構成で
  0から7までの数値で設定します。実際の記述では、例えばタイマ1の場合は
  下記のようにビットフィールドにより3ビットをまとめた記述が可能です。
  リセット後のデフォルト値は4となっています。

    IPC0bits.T1IP = 4;

(3) CPUの割り込み優先レベルを設定する
  CPU自身の割り込み優先レベルはステータスレジスタ(SR)の中のIPL<2:0>
  ビットとして用意されています。この割り込み優先レベルは、内蔵モジュール
  との関係が下記の関係になると内蔵モジュールの割り込みが許可されます。

    xxxIP<2:0> > IPL<2:0> 

  CPUの割り込み優先レベルの設定は下記のような記述で可能になります。

    SRbits.IPL = 3;

 このCPU割り込み優先レベルはデフォルトでは2に自動的に設定されます。

 以上の設定をすれば割り込みが許可され、内蔵モジュールで割り込み要因が
発生すれば、レジスタIFSn内の割り込みフラグビット(xxxIF)が1になって割り込む
ことが可能になります。
 この割り込みフラグは自動的にクリアされることはありませんので、割り込みを
受け付けたら、割り込みサービスルーチンの中でクリアする必要があります。
これには下記のように記述します。これを忘れると同じ割り込みが永久に継続
発生します。

    IFS0bits.T1IF = 0;

【割り込みのネスティング(多重割り込み)】

 PICの16ビットファミリでは、デフォルトで多重割り込みができるようになっています。
割り込みサービスルーチンは、その最初でコンテキストを保存しますので、同じ割り
込み処理記述方法のままで、多重割り込みとなります。

 つまり、いったん割り込みが受け付けられても、その割り込みの優先レベルに
CPUの割り込み優先レベルが書き換えられるだけですので、現在の割り込みレベル
より優先レベルの高い割り込みが発生したら、その割り込みも受け付け、こちらを先
に処理します。

 このような割り込みのネスティングを禁止したい場合には、INTCON1レジスタの
NSTDISビットを1にすれば、割り込みが受け付けられるとCPUの割り込み優先レベル
が常に7に設定されますので、割り込み処理中は全割り込みが禁止となります。
さらに割り込み処理中はCPUの優先レベルの書き換えも禁止されます。






   目次ページへ