続いての特徴は割り込みです。
NVICとICU
ARM Corex-M マイコンで割り込みと言ったら NVIC (Nested Vectored Interrupt Controller)が割り込みの元締め(本当はグローバル割り込みとして PRIMASK ビットを __enable_irq()
とかで設定できる)ですが、RA マイコンは NVIC の前段階に ICU という独自の割り込みコントローラーを積んでいます。
この ICUは 通常の割り込みも扱うし、DTC と呼ばれる DMA 機能のためにも使われ、そしてなんと NMI も受け持っているらしいです。
これだけ聴くと「まーたルネサスの独自謎仕様か」「要らん物付けるな」とか言われそうですが、僕個人的にこの ICU は、NVIC への割当を自由に変えられるというのが特徴だと思うんです。
「そんなの使うのか?」というのが懸念点ですが、まあ使わないでしょうね...僕個人的にはあまりメリットを見いだせませんでした...割り込み番号で優先度を自由に設定できるから?誰か有識者教えて。
ともかく、割り込みを司るのは NVIC と ICU という訳です。つまりぶっちゃけると、STM32 等のマイコンでは割り込みのために ペリフェラル + NVIC だけを設定すればよかったのですが、RA マイコンでは ペリフェラル + ICU + NVIC を設定する必要があります。やること増えてるじゃねーか。
実際の使い方
では、タイマーペリフェラルである GPT で実際に使っていきましょう。
#include <ARMCM23.h>
#include "ra.h"
void gpt_irq_init(void) {
MSTP.MSTPCRD.BIT.MSTPD5 = 0; // Start GP320 module
GPT320.GTCR.BIT.TPCS = 0b101; // /1024 => 46.875kHz
GPT320.GTUDDTYC.BIT.UD = 1; // Up Counting
GPT320.GTPR.WORD = 46875 - 1; // Upper Max
ICU.IELSR[0].BIT.IELS = 0x4A; // GP320 Overflow
NVIC_EnableIRQ(0);
GPT320.GTCR.BIT.CST = 1; // Count Start
}
void Handler0(void) {
if( GPT320.GTST.BIT.TCFPO ) {
PORT1.PODR.BIT.B0 ^= 1;
GPT320.GTST.BIT.TCFPO = 0;
ICU.IELSR[0].BIT.IR = 0; // Clear IRQ
}
}
まず、MSTP
はルネサスマイコン恒例のモジュールストップ機能です。RX マイコンを常用されている方はここで「あれ?レジスタライトプロテクション外さなくてもいいの?」と思われたと思います。そう、RA マイコンではモジュールを有効化/無効化する際に PRCR
レジスタをいじらなくても良いんです。不評だったんですかね。
デフォルトでは無効化されているので、0 を代入してモジュールストップを解除してあげます。
GPT 自体の設定は飛ばして、この2行が割り込み設定です。
ICU.IELSR[0].BIT.IELS = 0x4A; // GP320 Overflow
NVIC_EnableIRQ(0);
見て分かる通り、ICU と NVIC の設定をしています。GPT の場合は特別で、ペリフェラルで割り込み要因ごとに割り込みを有効化する必要はありません。0x4A
というのがコメントに書いてあるとおり、カウンタオーバーフロー割り込みです。例えば他の SCI (UART とかのアレ)ではペリフェラルの設定が必要だったりします。
IELSR
の [0]
は何かというと、自分で勝手に決めた割り込み番号です。ICU は割り込みを 0 〜 31 の 32 個登録でき、それを何番に入れるかはプログラマの自由です。例えばこれを 31 とすることも許されます。ただし、番号が若いほうが割り込み優先度が高いようです。NVIC はベクタテーブルが固定(変更もできるが、ベクタテーブルをまるごと別の領域に参照するようにコピー等する必要がある)ですが、ICU がフレキシブルなのはこういう仕組みがあるからです。
そして、最後に NVIC。
割り込み関数の方は、自分で指定したとおりに0番のハンドラを記載しています。
フラグをチェックしてクリアするのですが、ICU 側でも IELSR
レジスタ内 IR
ビットをクリアする必要があることに注意です。