今回はArduino Dueをレジスタ直接制御で割り込み処理を行います。
前回まで、GPIOの入出力を行ってきました。
過去の記事
- GPIO出力
- GPIO入力
GPIO入力に割り込み処理を追加します。
通常、Arduinoの外部割り込みにはattachInterruptを使うと思います。
これをレジスタ直接制御で実現していくことになります。
目次
Arduino Dueで外部割込みを実現する流れ
単純に前回のGPIO入力の延長です。
前回でマイコン端子のHi/Lo電圧はPIO_PDSRに格納されることは書きましたが、外部割り込みを設定する際には以下の割り込み関連ブロックの設定を行います。
Arduino Due搭載のSAM3XのGPIOでは、入力電位を読んだ後にEVENT DETECTORを通じて割り込み条件の成立を判定し、次に割り込み可否設定(PIO_IMR)を参照し
割り込みが許可されていれば、割り込み要求を(NVICへと)出力します。
①EVENT DETECTORの設定
まず、EVENT DETECTORで割り込みの種類の設定を行います。
EVENT DETECTORの中身は以下のようになっています。
割り込み成立条件は以下の5種類設定出来ます。
(Rise発生, Fall発生, RiseまたはFall発生, High電位時, Low電位時)
具体的なレジスタ設定方法として、Rise発生時に割り込みを有効とする場合は
以下のようになります。
Arduino Dueの3Pin(PIOC 28)を使う場合、ソースコードは
void setup() {
// put your setup code here, to run once:
PIOC->PIO_REHLSR = 1<<28;//Rising EdgeまたはHigh Levelを選択。
PIOC->PIO_ESR = 1<<28;//Edge検出を選択。(上と併せてRising Edge検出)
PIOC->PIO_AIMER = 1<<28;//両Edge検出は使用しない。
}
となります。
②割り込み可否の設定
EVENT DETECTORで設定した割り込みを有効化させるにはPIOコントローラの割り込みを有効化する必要があります。
PIO_IMRレジスタで割り込みを有効化します。PIO_IMRレジスタ自身はRead-onlyなので、割り込みを有効化させる場合はPIO_IERに値を書き込みます。
①のコードに一行追加する形です。
void setup() {
// put your setup code here, to run once:
PIOC->PIO_REHLSR = 1<<28;//Rising EdgeまたはHigh Levelを選択。
PIOC->PIO_ESR = 1<<28;//Edge検出を選択。(上と併せてRising Edge検出)
PIOC->PIO_AIMER = 1<<28;//両Edge検出は使用しない。
PIOC->PIO_IER = 1<<28;// 3番端子(PIOC28)からの割り込み発生を許可
}
③NVICの設定
②でPIOコントローラにて割り込みを有効となりましたが、最後にNVICにてPIOCの割り込みを有効化する必要があります。
具体的にはPIOCはPID13なので、PID13の割り込みを有効化します。
少しややこしいので詳細は割愛しますが、
NVIC->ISERで割り込み許可。NVIC->ICERで割り込み禁止となります。
void setup() {
// put your setup code here, to run once:
PIOC->PIO_REHLSR = 1<<28;//Rising EdgeまたはHigh Levelを選択。
PIOC->PIO_ESR = 1<<28;//Edge検出を選択。(上と併せてRising Edge検出)
PIOC->PIO_AIMER = 1<<28;//両Edge検出は使用しない。
PIOC->PIO_IER = 1<<28;// 3番端子(PIOC28)からの割り込み発生を許可
NVIC->ISER[0] = 1<<13;//PIOC(Peripheral ID:13)の割り込み発生を許可。
}
これで割り込みの設定は完了です。
割り込み発生時の処理の記入
上記で設定した割り込みが発生した際は、PIO_ISRレジスタに"1"が格納されます。
割り込みが発生した時の処理はHandler関数の中に書きます。
GPIOの割り込み時の処理はPIO_Handler関数として記載するのですが、
Arduinoインストール時のデフォルトのライブラリに既に定義されているため、
自分で作ったソースコードにもPIOC_Handler()等を書くと、関数名が重複してエラーになってしまいます。
なので、レジスタ直接制御で割り込みを有効化させる場合には、ライブラリを無効化する必要があります。(少しめんどくさいですね・・・)
PIO_Handler関数はWInterrupts.cに書かれているので一時的にコメントアウトしておきます。Arduino15に格納されています。
(\Arduino15\packages\arduino\hardware\sam\1.6.12\cores\arduino\WInterrupts.c)
ソースコード例(3Pinを外部割り込みとして使う)
void setup() {
// put your setup code here, to run once:
Serial.begin(250000);//シリアル通信開始 (250kbps)
//3Pinを入力設定する(GPIO入力設定の記事参照)
PIOC->PIO_PUER = 1<<28;//PIOC28のプルアップ抵抗を有効にする。
PIOC->PIO_SCIFSR = 1<<28;//PIOC28の内部フィルタ選択クロックをMCKにする。
PIOC->PIO_IFER = 1<<28;//PIOC28の内部フィルタを有効にする。
//3Pinの割り込み設定をする
PIOC->PIO_REHLSR = 1<<28;//Rising EdgeまたはHigh Levelを選択。
PIOC->PIO_ESR = 1<<28;//Edge検出を選択。(上と併せてRising Edge検出)
PIOC->PIO_AIMER = 1<<28;//両Edge検出は使用しない。
PIOC->PIO_IER = 1<<28;// 3番端子(PIOC28)からの割り込み発生を許可
NVIC->ISER[0] = 1<<13;//PIOC(Peripheral ID:13)の割り込み発生を許可。
}
void PIOC_Handler() {//3番端子はPIOC28のためPIOC_Handler()を使用。
if ((PIOC->PIO_ISR >> 28) & 1 == 1){//PIO_ISRが1の場合
//※ここに割り込み発生時の処理を書く
}
}
void loop() {
}
ここまで出来ればあとはPIO_ISRレジスタの中身で判定して色々な処理を拡張していってもいいですね。
次回はSPI通信のことでも書こうかな・・・覚えているうちに色々書きます。