目次

割り込み ( PIC32MX270F256B )

割込み制御の特殊機能レジスタ(SFR)

周辺モジュールからCPUへ割込み要求がある場合、割込み要求(IRQ)番号、割込み優先レベル(Priority Level)情報がCPUに伝達されます。
伝達された割込み要求は、適切な順番でプロセッサに処理されることになります。
(なおこのデバイスでは、ソフトによるノンマスカブル割り込み[NMI]や、シャドーセットが存在しません。 またCPUの初期時はシングルベクタモードですが、マルチベクタモードに変更して使っています。 )

この割込みを制御するための特殊機能レジスタ(SFR)は次の通りです。


上記先頭に記載される「INTCON」のレジスタは、割り込みベクタ間隔、シングルベクタまたはマルチベクタ動作モード、 割り込み近接、外部割り込みエッジ検出を制御するレジスタで、内部ビットは次のようになっています。

この当ボードにおいて、INTCONレジスタの設定は、次のように確認できます。
unsigned int temp = INTCON;//割り込み制御レジスタ
これで得られる情報は、0x00001000 となりますが、MVECのbitが1です。
bit 12のMVECは、マルチベクタ コンフィグレーション ビットで、次のように決められています。
1 =割り込みコントローラをマルチベクタ モードに設定する
0 =割り込みコントローラをシングルベクタ モードに設定する
これにより、マルチベクタ モードになっていると分かります。これは割込みが、種類により異なるスタートアドレスを持つモードです。
このスタートアドレスが記憶される間隔は、IntCtl レジスタ(CP0 レジスタ12、Select 1)よりわかるようになっており、間隔は、32byteになっています。
この割込みベクタのベースアドレスは次のように取得できます。
unsigned int * ebase = _CP0_GET_EBASE(); // 現状では [ 9d03f0000 ]が得られます。

この他にも、次のようなレジスタ群があり、その概要を示します。
INTSTAT 割り込みステータス レジスタ この読み出し専用レジスタは、CPUに提示する割り込み優先度またはベクタのステータスを格納します。
IPTMR 割り込み近接タイマレジス このレジスタは、CPUに提示するまで割り込みを保持しておくタイミング ウィンドウを制 御します。
IFSx 割り込みフラグ ステータス レジスタ これらのレジスタは、各種割り込み要因のステータスを示すフラグを格納し、これらの割り込み要因のクリアも行います。
IECx 割り込みイネーブル制御レジスタ これらのレジスタは、割り込み要因によるCPU割り込みのトリガを有効または無効とするフラグを格納します。
IPCx 割り込み優先度制御レジスタ これらのレジスタは、各種割り込み要因の優先度と副優先度を制御します。
xの指定は番号とそれに続く「CLR」、「SET」、「INV」の3通り(クリア / セット / 反転)の指定があります。
例 IEC0CLR=_IEC0_T3IE_MASK; ( Timer3 割込み不可)

割り込みの動作(割込み番号(IRQ), 割込みベクタ番号、割り込み制御用SFRの使われ方)

周辺モジュールからCPUへ割込み要求で使う割込み要求(IRQ)番号は、決まっています。(下記表に記載)
(PIC32MX270F256Bで、IRQの割込み要求番号は[Core Timer]の0から[DMA Channel 3]の63番まであります。)
またマルチベクタにおいて、ベクタ番号も決まっています。(0から43番まであります。)
IRQの数は利用可能なベクタ番号の数よりも多いため、一部のIRQは別のIRQと同じベクタ番号を共有します。
それら情報と制御情報を、周辺モジュール別に表にした情報の一部を下に示します。
実際の各割込みのスタートアドレスは、ベースアドレス+0x200起点に、32bit間隔で配置されます。
それはCP0から得られるベースアドレスと、ベクタ番号から求められます。

例えば、「T1(Timer1)」の割込みであれば、4のIRQ番号で、4のベクタ番号、
「T2(Timer2)」の割込みであれば、9のIRQ番号で、8のベクタ番号になっており、関連する緑のビットが情報を使っています。
この情報は、特殊機能レジスタ(SFR)内の同じ色で示したbit位置に記憶されます。
なお、IFS0は割り込みフラグステータスの0番レジスタ、 IEC0は割り込みイネーブル制御用の0番レジスタ、 IPC1は割り込み優先度制御用の1番レジスタで、<>の中で情報が格納されるビット位置を示しています。
これらを利用する割り込みの動作は次のようになります。
  1. IRQはSYSCLKの立ち上がりエッジでサンプリングされ、対応するIFSxレジスタにラッチされます。 (これでIFSxのフラグビットが「1」の保留状態になる)

  2. 割り込みコントローラは、保留中IRQの中で最優先のIRQを選択し、対応するベクタ番号、優先度をプロセッサコアに提示します。
    (割り込み優先度は、その割り込みに割り当てられているベクタのIPCxレジスタの設定によって決まります。)

  3. プロセッサコアは、パイプラインのE段とM段の間で、提示されたベクタ情報を取得します。
    このベクタの優先度がCPU割り込み優先度ビット「 IPL<2:0>(Status<12:10>) 」が 示す現在の優先度よりも高い場合、その割り込みはサービスされます。
    これ以外の場合、その割り込みは、現在の優先度がその割り込みの優先度よりも低くなるまで保留されます。

  4. 割り込みをサービスしている時、プロセッサコアはプログラム カウンタをCPU内の例外プログラム カ ウンタ(EPC:CP0の14番)レジスタにプッシュし、 CPU内の例外レベル(EXL)ビット(Status<1>)をセットします。
    EXLビットがセットされると、アプリケーションが明示的にEXLビットをクリアするまで後続の割り込みは無効にされ、 CPUは提示されたベクタ番号から算出したベクタアドレスへ分岐します。

  5. 例外からの復帰(ERET)命令が実行されると、プロセッサは以前の状態に戻ります。ERET命令はEXLビットをクリアし、プログラム カウンタを復元します。
    (なおERETの前に、割り込みの原因となったIFSxのフラグビットを明示的にクリアする必要があります。)


割り込みに関連で、他の留意点を以下に列挙します。

具体的なC言語での割込み例

sys/attribs.h ヘッダファイルで、次のISRというマクロが定義されており、これで割込みベクタを定義します。
__ISR(v,ipl)
これで、優先度ipl を持ち、ベクタ番号v の割込みベクタを定義します。
以下で、コアタイマの割込みベクタの定義例を示す。(2000000uカウントごとに_RB15のビット反転)
void __ISR(_CORE_TIMER_VECTOR, IPL7SOFT) CTInterruptHandler(void)
{
    IFS0CLR = _IFS0_CTIF_MASK; // 割り込み要求フラグをクリア
    _RB15 = ! _RB15;// 出力を反転
    _CP0_SET_COMPARE(2000000u);//この値までカウントしたら割り込む
    _CP0_SET_COUNT(0);//コアタイマを0にセット(CP0の9番レジスタ)
}
参考に上記のディスアセンブラ( disassembler「逆アセンブラ」)のコード例を示す。
271:                 void __ISR(_CORE_TIMER_VECTOR, IPL7SOFT) CTInterruptHandler(void)
272:                 {    
9D00759C  415DE800   RDPGPR SP, SP
9D0075A0  401A7000   MFC0 K0, EPC
9D0075A4  401B6000   MFC0 K1, Status
9D0075A8  27BDFFE8   ADDIU SP, SP, -24
9D0075AC  AFBB0014   SW K1, 20(SP)
9D0075B0  7C1B7844   INS K1, ZERO, 1, 15
9D0075B4  377B1C00   ORI K1, K1, 7168
9D0075B8  409B6000   MTC0 K1, Status
9D0075BC  AFBF000C   SW RA, 12(SP)
9D0075C0  AFA40008   SW A0, 8(SP)
9D0075C4  AFA30004   SW V1, 4(SP)
9D0075C8  AFA20000   SW V0, 0(SP)
273:                     IFS0CLR = _IFS0_CTIF_MASK; // 割り込み要求フラグをクリア
9D0075CC  24030001   ADDIU V1, ZERO, 1
9D0075D0  3C02BF88   LUI V0, -16504
9D0075D4  AC431034   SW V1, 4148(V0)
274:                     _RB15 = ! _RB15;// 出力を反転
9D0075D8  3C02BF88   LUI V0, -16504
9D0075DC  8C446120   LW A0, 24864(V0)
9D0075E0  38848000   XORI A0, A0, -32768
9D0075E4  7C8403C0   EXT A0, A0, 15, 1
9D0075E8  94436120   LHU V1, 24864(V0)
9D0075EC  7C837BC4   INS V1, A0, 15, 1
9D0075F0  A4436120   SH V1, 24864(V0)
275:                     _CP0_SET_COMPARE(2000000u);//この値までカウントしたら割り込む
9D0075F4  3C02001E   LUI V0, 30
9D0075F8  34428480   ORI V0, V0, -31616
9D0075FC  40825800   MTC0 V0, Compare
9D007600  000000C0   EHB
276:                     _CP0_SET_COUNT(0);//コアタイマを0にセット(CP0の9番レジスタ)
9D007604  00001021   ADDU V0, ZERO, ZERO
9D007608  40824800   MTC0 V0, Count
9D00760C  000000C0   EHB
277:                 }
9D007610  8FBF000C   LW RA, 12(SP)
これを呼び出すベクタは次のようになっていた。_CP0_GET_EBASE()が「9d03f000」の場合です。これで、割込みがあると、 上記9d00759cの位置に処理が移動します。
9d03f200 <__vector_dispatch_0>:
9d03f200:	0b401d67 	j	9d00759c <.LFE957>
9d03f204:	00000000 	nop