目的
割り込みコントローラ(ICU)による外部割り込み処理をGPIO(SW1,SW2)を使用して理解する。
全体フロー
- プロジェクト作成(bare-metal)
- コンフィギュレーション設定
- ソースコード修正(hal_entry.c)
- 結果
準備
- RA6M4評価キット
- e2studio統合開発環境
本編
S1, S2のSWを使って外部割り込みが発生していることを確認するために、
S1 or S2 SW押しにより外部割り込み発生(IRQ)→割り込み関数がコール→LED点灯/消灯処理を実行、の流れで
プロジェクト作成, コンフィギュレーション設定、ソースコード修正をおこなう。
プロジェクト作成
プロジェクトをスクラッチビルドする。bare-metalでのプロジェクト作成方法はpart.3: GPTタイマーで説明してあるので、ここでは割愛する。
プロジェクトの名前は「TestICUextIntProject」とした。
コンフィギュレーション設定
プロジェクトからconfiguration.xmlを開き、PinsタブからInput:ICU→ICU0を選択する。
Input/Output以下に各IRQとValueに設定されているポートが表示されているので、確認する。
現在の割当はIRQ11がP006, IRQ12がP008となっており、今回の操作対象とするSW1はP006, SW2はP008の各ポートに接続してあるので
ここでは特に修正する箇所はない。

例えばIRQ11であればP006以外にもP501, P708が選択可能である。ただ、既にこれらのポートは別の箇所で予約させているため、
実際に設定可能なのはP006のみである。(予約済で設定不可なポートはポート名の前にアスタリスク*がつく)
各IRQで割当可能なポートについての詳細については、RA6M4ユーザーズマニュアル p.73 – 76 端子一覧の表に網羅されているので
こちらを参照するとよい。

次にStacksタブを選択し、Stacks ConfigurationでNew Stack→Input→External IRQ(r_icu)を選択し、r_icuモジュールを生成する。
今回はIRQ10, IRQ11の2つのIRQを使用するので、スタックはそれぞれ2つ作成する必要がある。

上記操作を2回繰り返すと、g_external_irq0とg_external_irq1の名前のモジュールが生成される。

モジュールの一つ(g_external_irq0)を選択し、プロパティを開く。
このモジュールにはIRQ10を割り当てるので、Channelは「10」を設定する。また合わせてNameも「g_external_irq10」と変更する。
Callbackに割り込み発生時のコールバック関数が設定できるので、ここに「external_irq10_cb」という関数名を入力した。
またPin Interrupt Priorityはデフォルトの「Priority 12」とした。ここは番号が若いほど、割り込みの優先順位が高くなる。
Pins→IRQ10には既にICUの項目でIRQ10にポート設定されたP005が表示されるので、確認しておくとよい。

同様にもう片方のモジュール(g_external_irq1)にも以下の設定をおこなう。
Nameは「g_external_irq11」、Channelは「11」、Callbackは「external_irq11_cb」、Pin Interrupt Priorityは「Priority 13」とした。
被ってしまうとこの後プロジェクトをビルドしてもプログラムは正常に動作しなくなる。

各r_icuモジュールの設定が完了しInterruptタブを開くとICUの割り込みの設定がなされていることが確認できるので
合わせて確認。

ソースコード修正 (hal_entry.c)
src\hal_entry.cの中身を以下のものに修正する。
処理の内容は以下の通りになる。
- コールバック関数:external_ir10_cb()にてLED1の状態変数:LED1_levelを点灯または消灯に設定
- コールバック関数:external_irq11_cb()にてLED2の状態変数:LED2_levelを点灯または消灯に設定
- メイン関数:hal_entry()にて、IRQ10, IRQ11をオープン(関数: R_ICU_ExternalIrqOpen()), 開始(関数: R_ICU_ExternalIrqEnable())
- メイン関数:hal_entry()にて、while(1)内で状態変数:LED1_level, LED2_levelを各LED出力ポートに設定
#include "hal_data.h" FSP_CPP_HEADER void R_BSP_WarmStart(bsp_warm_start_event_t event); FSP_CPP_FOOTER extern bsp_leds_t g_bsp_leds; static bsp_io_level_t LED1_level = BSP_IO_LEVEL_LOW; static bsp_io_level_t LED2_level = BSP_IO_LEVEL_LOW; /* external IO IRQ10 call back (SW1) */ void external_irq10_cb(external_irq_callback_args_t *p_args) { (void)p_args; LED1_level = (LED1_level == BSP_IO_LEVEL_LOW) ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW; } /* external IO IRQ11 call back (SW2) */ void external_irq11_cb(external_irq_callback_args_t *p_args) { (void)p_args; LED2_level = (LED2_level == BSP_IO_LEVEL_LOW) ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW; } /*******************************************************************************************************************//** * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function * is called by main() when no RTOS is used. **********************************************************************************************************************/ void hal_entry(void) { /* ICU Open,Enable (IRQ 10) */ R_ICU_ExternalIrqOpen(&g_external_irq10_ctrl, &g_external_irq10_cfg); R_ICU_ExternalIrqEnable(&g_external_irq10_ctrl); /* ICU Open,Enable (IRQ 11) */ R_ICU_ExternalIrqOpen(&g_external_irq11_ctrl, &g_external_irq11_cfg); R_ICU_ExternalIrqEnable(&g_external_irq11_ctrl); /* loop main for LED1,2 ON/OFF by IRQ10 and IRQ11 interrupt */ while(1){ g_ioport.p_api->pinWrite(&g_ioport_ctrl, g_bsp_leds.p_leds[BSP_LED_LED1], LED1_level); g_ioport.p_api->pinWrite(&g_ioport_ctrl, g_bsp_leds.p_leds[BSP_LED_LED2], LED2_level); } #if BSP_TZ_SECURE_BUILD /* Enter non-secure code */ R_BSP_NonSecureEnter(); #endif } ...
結果
プロジェクトをビルド、書き込みした後の基板の動作は以下になる。
SW1,SW2のボタンを押すことによって、それぞれLED1, LED2が点滅、点灯を切り替わることがわかる。
外部割り込みが正常に機能していることが確認できたところで、本編は終了とする。
