AVR32のEIC(External Interrupts Controller)

ここではAVR32の例としてAT32UC3B0256を対象に、ドキュメント「AT32UC3B Series Preliminary」(現在はRev.G)を読んでいく。



外部割込端子(NMIやEXTINT)機能がEICの担当で、内蔵周辺モジュール全般をINTC(Interrupt Controller)が担当している。EICも周辺モジュールの1つであり、INTCから見るとNMIもEXTINTも優先度やマスクの扱いが異なるだけで、他のモジュールの割込と何ら変わらない。その辺は「Table 11-3. Interrupt Request Signal Map」からも判る(NMIは割込グループに属さない)。
外部割り込み端子がすべて多機能ピンに割り当てられていて、設定次第ではNMI,EXTINT,SCAN端子をすべて無くすことも出来る。多機能ピンの設定はGPIOの機能だ。ちなみにピン番号/名称と割り当て可能な信号名の組み合わせは、GPIOの章ではなく、Peripheralsの「11.8 Peripheral Multiplexing on I/O lines」にある(怒)。こういうのは「6. Package and Pinout」に載せて欲しいものだ。

どのスリープ・モードでも、すべての割込端子が動作可能だが、クロックが停止するスリープ・モードでは非同期割込を選択しなければならない(後述)。

外部割り込み端子EXTINTを有効にするには、レジスタENの該当ビットへ1を書き込まねばならない。同様に、無効にするにはレジスタDISの該当ビットへ1を書き込む。各割込信号線の状態はCTRLレジスタで観測される。(ブロック図の「Enable」と書かれた1段目の箱。)
割込生成の立ち上がり/立ち下がりエッジあるいはハイ/ロー・レベルをMODE、EDGEそしてLEVELレジスタにより環境設定できる。(ブロック図の「Polarity control」と「Edge/Level Detector」と書かれた箱。)
トリガ設定
EDGEの該当ビットLEVELの該当ビット
0101
MODEの該当ビット0立ち下がり
エッジ
立ち上がり
エッジ
don't care
1don't careロー・
レベル
ハイ・
レベル
各割込nがこれらレジスタ内にビットINTnを持つ。

重大な注意が一点。
「16. External Interrupts Controller (EIC)」に記述されている「INT0〜INT7」はすべて「この章内部でのみ有効な名称」と考えること。
INTCで割り込み優先度を表すINT0〜3とは別物である。本来書きたいことは割込要因を識別する名称であり、「11.3 Interrupt Request Signal Map」の「Table 11-3. Interrupt Request Signal Map」にあるEIC0〜EIC7が相当するはずだ。
AVR32の周辺モジュール開発は独立性が高らしく、マニュアルにもモジュール毎にリビジョン番号が振られていて(16 EICには「Rev: 2.3.0.1」と記述有り)、ヘッダファイルもリビジョンに合わせてeic_230.hとなる。AVR32の別製品へ変更しても、モジュールのリビジョンが合っていれば同一動作を期待できる。
想像だが、これが災いして周辺モジュール開発者間の意思疎通が取れず、名称の衝突が起きたのではないか?
ということで、ヘッダファイルにもAVR32_EIC_CTRL_INT0というようなマクロ名が存在し、勝手に変える訳にもいかず、そのままINT0〜7という用語を使用するしかない。
INTCとEICのいずれを指しているか自分で注意する必要がある。

同様に、各割込は割り込み制御と状態のレジスタにそれぞれ対応するビットを持つ。IERレジスタの該当ビットに1を書き込むことは(INTCへの)割込を有効にし、IDRレジスタの該当ビットに1を書き込むことは割込を無効にする。
レジスタともwrite-onlyなので、最後に1を書き込んだレジスタを覚えておく必要がありそうだが、IMRレジスタを読めば割込が有効かチェックできる。
割込トリガ発生時、ISRレジスタの対応するビットがセットされる。このフラグは、ICRレジスタの対応するビットに1が書き込まれるまでセットされ続ける(1が書かれればクリアされる)。
レベル・トリガ・モードではクロック周期より長いスパイク(訳注:「数クロック周期より短い」の誤りのようだ)を消去するため、レジスタFILTERに1を書くことで有効になるフィルタを含んでいる。
各割込信号は、レジスタASYNCの該当ビットに1を書き込むことにより非同期で生成される。これはEICモジュールの非同期パスを通って信号を送る(ブロック図中央の上側)。


外部割り込みの同期(レジスタASYNCの該当ビットが0)について。
EXTINT端子の取り込みは通常CPUクロックと同期しており、CPUクロック周期より短いスパイク(状のパルス)が割込生成することを保証しない。
ストップ・モードでは32kHz周期より短いスパイクが割込生成することを保証しない。
スタティック・モードでは、同期していない割込のみがアクティブで残っていて、この割込における短いスパイクがデバイスを(スリープから?)ウェイクアップする。

CPUは外部割り込みによりスリープ・モードからウェイクアップすることが出来る。ウェイクアップは2通りの解釈が出来る。レジスタIMRの対応するビットがセットされていれば、実行はこの割込のハンドラから開始する。レジスタIMRのビットがセットされていなければ、実行はsleep命令後の次の命令から開始する。(いずれでもsleep命令後の命令を実行するが、その前に割込ハンドラを実行するか否かの違い。)



NMI(None-Maskable Interrupt)は外部割り込み(EXTINT)と同じ機能をサポートし、同じレジスタを通してアクセスされる。

結局NMIの特徴は、CPU実行モードやSRレジスタのマスク・ビットからマスクできないということであり、EICのレジスタからマスクすることが可能だ。この辺は他社CPUと違う。

外部割込モジュールはキーパッド・スキャン・サポートを内蔵している。キー・パッド・スキャン機能は、キーが押されたときロウが接触したカラムとショートさせられるタイプのキー・パッドと互換性がある。
(ブロック図から読み取りづらいが)SCAN発生部はNMI/EXTINT部と独立していて、レジスタSCANのビットENのセットでSCAN0〜7端子からスキャン信号を発生する。スキャンのステップ周期は同レジスタのPRESCで制御する。使用したくないSCAN端子はGPIOで割り付けなければよい。
キーが押されたとき、プルアップされたロウがカラムによりロー・レベルにドライブされるので、外部割り込みがトリガされる。スキャンは停止し、割込ハンドラはレジスタISRとレジスタSCANのPINSから押されたキーを識別できる。割込ハンドラが割込要因をクリアするとスキャンは再開される。

うーん、キーパッド・スキャンは便利そうだけど本当に使える(実用的)かな?
キーパッド・スキャン機能は、64pinパッケージでのみサポート。割り付けられる多機能ピンも一部がパッケージの反対側にあったりして基板レイアウトには苦労しそう。
32kHzクロックと同期するので、同期モードを使用する。同期モードのフィルタを使用可能だが、32kHzでフィルタしてもチャタリング除去には役に立たない(周期が短い)。チャタリングが発生すると、前回のイベントからの経過時間を求めて...などという処理が必要になりそうだ。
実現したいキー・パッドの仕様に依るが、複数キー同時押しは検出&認識できるが、スキャン一周分の結果から判断したり、キーを離したことを検出しようとすると結局タイマを利用せざるをえなくなる。簡単な仕様なら十分だが。