mwf_periph_gint - GINT(GPIO)
mwf_periph_gint - GINT(GPIO)
汎用IOの入出力の設定、また GINT を用いたIO割り込みを実装しています。
TWENETでは、初期化、割り込み処理はTWENETライブラリ(TWENETcmpt)内で処理されます。ユーザプログラム内で本関数を呼び出すことは通常ありません。
include
#include "mwf_periph_gint.hpp"
class mwf::periph::gint
the_gint
クラスオブジェクトの定義です。ピンを割り込み動作させる場合(スリープ割り込みも含む)、the_gint
クラスオブジェクトの生成が必要です。実装の詳細は後述の「GINTを用いたDIO割り込み実装」を参照してください。
global_init_gint_manager() global_deinit_gint_manager()
static void global_init_gint_manager();
static void global_deinit_gint_manager();
クラスオブジェクトthe_gint
の生成と破棄を行う。
init_int() deinit_int()
void init_int(tpf_gpio_int_handler pf_callback, void *p_data = nullptr);
void deinit_int();
GPIO 割り込みの初期化を行う。割り込みハンドラ(pf_callback
と割り込みハンドラに伝達されるパラメータ(p_data
)を指定します。
GPIO 割り込みを停止するには deinit_int()
を呼びます。
pf_callback
は、以下のように定義されます。
using tpf_gpio_int_handler = void(*)(uint32_t bm_now, uint32_t bm_changed, void *p_data);
bm_now
は、現時点でのピン状態に対応するビットマップ。bm_changed
は、変更のあったピンに対応するビットマップ。p_data
は、init_int()
で指定したp_data
です。
set_int_pins_bm()
void set_int_pins_bm(uint32_t u32mask_rising_edge, uint32_t u32mask_falling_edge);
割り込み対象のピンを指定します。
1番目のパラメータu32mask_rising_edge
は立ち上がりエッジの検出対象ピンのビットマップ、2番目のパラメータu32mask_falling_edge
は立ち下がりエッジの検出対象ピンのビットマップです。
立ち上がり、立ち下がり両方のエッジを設定することも可能です。
gint_poll()
void gint_poll();
割り込み時の処理と同じ処理を行う。
1msシステムタイマーなどから一定周期で呼び出すことで、後述の「GINTを用いたDIO割り込み実装」で解説する制限(割り込みハンドラ中で読み出した状態からポート状態が変化してそのままその変化が処理されない場合)を緩和できる場合があります。多くの場合はこの処理は必要ありません。
set|unset|get_opt_stop_int_when_changed()
void set_opt_stop_int_when_changed();
void unset_opt_stop_int_when_changed();
bool get_opt_stop_int_when_changed();
メカボタンのチャタリングなどの影響を緩和するために、状態変化検出後に当該ピンの割り込み動作を停止します。
具体的には、ピンの状態が変化し割り込みが発生し、かつ、その割り込みハンドラ中で変化があったと判定されたピン*について、割り込みピンから一時的に除外します。
*割り込み要因のピンはGINTの割り込み機構では知ることが出来ないため、割り込みハンドラが実行された直後にピンの状態を読み出し、直前の状態で比較することで変化を検出しています。
このオプションを設定した場合、ピンの変化が検出されたあとピンの状態の安定を待ってからreactivate_in_pins()
を呼び出します。
reavtivate_int_pins()
void reavtivate_int_pins();
割り込みを一時停止したピンの割り込みを再開する。set_opt_stop_int_when_changed()
のオプション設定参照。
get_gint_context()
gint_context& get_gint_context();
内部構造体にアクセスします。設定済みの立ち上がり立ち下がりピンのビットマップ(.bm_rise
.bm_fall
)や、スリープ起床時の起床要因のピン(.bm_wake
)を得るために使用します。
_gint_update()
std::tuple<uint32_t, uint32_t> _gint_update(
uint32_t u32mask_rising_edge = 0x80000000
, uint32_t u32mask_falling_edge = 0x80000000);
(内部的に呼び出される関数でユーザプログラムからは使用しません)
1.割り込みピンの設定を行う。
2.ピンの状態変化を判定、更新する(u32mask_rising_edge
, u32mask_falling_edge
が0x80000000
の場合)。状態変化があれば init_int()
で登録したコールバック関数を呼び出す。
gint_handler()
static void gint_handler();
(内部的に呼び出される関数でユーザプログラムからは使用しません)
GINTの割り込みハンドラ。
_gint_get_changed_by_specified_edge()
uint32_t _gint_get_changed_by_specified_edge(uint32_t bm_cur, uint32_t bm_changed)
(内部的に呼び出される関数でユーザプログラムからは使用しません)
変化したピンのから、立ち上がり・立ち下がりの指定条件に合致するピンを抽出します。計算には、現在のビットマップ状態(bu_cur
)と変化したピン(bm_changed
)を用います。
class mwf::periph::gpio (sys_ev_handler)
on_sleep()
GINTが稼働中なら割り込みの停止を行います。
TWENETでは vAHI_DioOnSleep_MW()
で、本ライブラリを経由(set_int_pins_bm()
)して設定した割り込み設定ピンをスリープ起床用として設定しています。なお、スリープ起床では立ち上がりまたは立下りのエッジの指定はできません。
on_wakeup()
GPIO割り込み起床した場合は、起床要因に対応するピン情報 (PMC->WAKEIOSOUCE
) を保存します。
また、スリープ前に割り込みピンの指定があった場合は、改めて GINT による割り込みが動作するように再初期化します。
GINTを用いたDIO割り込み実装
PINT機能は利用数が最大4ポートまでの制限があるため、GINT(Group INT)の機能を用い類似の機能を実装してます。PINTのように特定のピンに注目した割り込み検出機構ではないため制限事項が存在します。TWENET ライブラリ中では PINT を用いていませんので、GINTによる実装の制限に問題がある場合は、PINT による実装も検討してください。
制限事項
ノイズや短いパルスといった状態変化後に短時間で再び状態が変化する信号の場合、期待しないふるまいになる場合があります(取りこぼしなど)。
- 状態変化後、一定の間同じ状態が維持されることを想定します。
- GINTの制約上、ごく短いパルスの場合GINT割り込みは検出できますが、変化したピンを得ることは出来ません。詳細は後述の「実装」を御覧ください。
- 変化(エッジ)から約10usecの間状態が維持されれば、GINT のエッジ再設定が行えるため原理的には動作が期待できますが、安全を見て割り込みハンドラ1回の処理時間に相当する約30~50usecの間同じ状態が維持することを目安としてください。
- GND状態で立ち下がりエッジを検出する、またその反対に VCC 状態で立ち上がりエッジを検出する場合は、原理上、取りこぼしが発生しやすくなります。
- チャタリング・ノイズが含まれるものについては、初回割り込み発生時点で割り込み対象から外すオプション(
vAHI_DioInterruptDisablePinsIntWhenChanged_MW(TRUE);
またはmwf::the_gpio->set_opt_stop_int_when_changed();
)を利用し、割り込み発生時点から一定時間待ってから、vAHI_DioInterruptReavtivate_MW();
またはmwf::the_gpio->reavtivate_int_pins();
を呼び出してください。 - 多くの場合必要ありませんが
the_gpio->gint_poll()
を1ms単位のシステムティックなど一定周期で呼び出すことで、割り込みのオーバーヘッドが増えるものの、取りこぼしの影響を緩和できる場合があります。
※ 記載の数値は CPU が 32Mhz 動作した場合を前提としてます。
※ 半導体の機能をそのまま利用したい場合は、当ライブラリの初期化を行わず、GINT や PINT を直接利用してください。
- 状態変化後、一定の間同じ状態が維持されることを想定します。
実装
GINTは本来、複数のピンをグループとして扱い、全体として変化があった場合に割り込みを発生させるもので、個別のピンの状態を意識した機能ではありません。
以下のように実装しています。
- 現在のピンの状態を読み出し、Hなら立ち下がり、Lなら立ち上がりエッジとして、GINTでの検出エッジの設定して、割り込みを有効にする。
- GINT割り込み発生(いずれかのピンに変化し、割り込みハンドラが呼び出される)
- 各ピンの状態を読み出し、変化のあったピンを検出する
- GINTの検出エッジ設定を、読み出したピンの状態に合わせて再設定する
- 変化のあったピンに対してアプリケーションに通知(コールバック)する
※ 割り込みハンドラは、直後にもう一度呼び出されます。
動作例
※ 記載中の数値などは、開発中のライブラリコード、検出対象ピンは2つ、マイコンは CPUは32MHzで駆動した場合です。
同時に2つのピンが L レベルになった時
割り込み発生から 1.5usec で割り込みハンドラが呼び出されます。割り込みの前段階の処理(ピンの読み出しと検出エッジの再設定)は、6.6usec後までかかります。その後、アプリケーション通知(割り込み時のコールバック)を行います(割り込み発生から 22usecまで)。
さらにもう一度割り込みが発生します(GINTのハードウェアの振る舞いと考えられます)。2回目の割り込みでは、多くの場合状態の変化は検出されないため値の確認のみですが、例外的な取りこぼしを抑制する場合があります。

- 横軸 (10usec/DIV)
- ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (1V/div)
- シアン・イエロー:入力信号 (2V/div)
割り込みハンドラ中に他のピンが変化した場合1
この例では、割り込みハンドラの前半処理中に他のピン(シアン)が変化したため、最初のハンドラ中で矛盾なく処理できた例です。上述の同時変化と同じ振る舞いになります。最初の割り込みでイエローとシアン両方の変化がアプリケーションに伝達されます。

- 横軸 (10usec/DIV)
- ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (2V/div)
- ブルー:割り込みハンドラの開始から終了まで (2V/div)
- シアン・イエロー:入力信号 (5V/div)
割り込みハンドラ中に他のピンが変化した場合2
この例では、割り込みハンドラ中で他のピン(シアン)が変化していますが、検出エッジ再設定後の変化であるため、直後に割り込みが発生しています。2回目のハンドラ終了後に、更にもう一度ハンドラが実行されます。最初の割り込みでイエローの変化がアプリケーションに伝達され、2回目の割りr込みでシアンの変化が伝達されます。

- 横軸 (10usec/DIV)
- ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (2V/div)
- ブルー:割り込みハンドラの開始から終了まで (2V/div)
- シアン・イエロー:入力信号 (5V/div)