mwf_common
mwf_common
共通定義やペリフェラル用のクラスのための基底クラスを定義する。
マクロ
BEGIN_CRITICAL, END_CRITICAL (割込み禁止)
#define BEGIN_CRITICAL { uint32_t __TWENET_regPrimask = DisableGlobalIRQ();
#define END_CRITICAL() EnableGlobalIRQ(__TWENET_regPrimask); }
// 例
extern volatile int critical_value;
void some_func() {
...
// 以下はクリティカルセクション
BEGIN_CRITICAL
{
critical_value++;
}
END_CRITICAL();
}
割込み禁止区間を設定するためのマクロです。DisableGlobalIRQ()
, EnableGlobalIRQ()
を呼び出すだけのマクロですが、ローカル変数を定義する必要があるなど、記述が煩雑に見えるため do {…} while() 構文に似せたマクロを定義しています。
上記例では、割り込みハンドラなどで変更しうる値 critical_value
がある場合に、アプリケーション処理内でその値を安全に更新するための手続きです。
※ このマクロは C++ コードのみで使用できます。
定数・列挙体など
enum class ID_SYSHAND
ペリフェラルクラスオブジェクトを識別するための ID を定義しています。
class sys_ev_handler
スリープとスリープ復帰時の手続きを共通化するためのインタフェース定義を行う上位(抽象)クラス。
on_sleep()
ペリフェラルのスリープ前の手続きを記述する。
on_wakeup(bool init_2nd)
スリープ復帰時に、スリープ前の状態に復帰するためのペリフェラルの手続きを記述する。この関数は2回呼び出されることを想定しています。
init_end
がfalseの場合は、起床後ごく初期の段階で呼び出されます。主に変数の初期化などを行いますが、デバイスなどの再初期化などはここでは行いません。trueで呼び出された2回目で。デバイスの再初期化などを行い、スリープ前の状態に復元します。TWENETでは
vAHI_OnWakeup_MW()
の呼び出し中に処理されます。以下のような呼び出し順になります。詳細は TWENETmcu のtwenet_main.c
を参照してください。WarmMain()
関数の呼び出し (スリープ復帰時に最初に呼び出される関数)vAHI_OnWakeup_MW(FALSE)
- ここで mwf ライブラリオブジェクトの
on_wakeup(false)
が呼び出される
- ここで mwf ライブラリオブジェクトの
ToCoNet_vInit_Warm_Pre()
cbAppWarmStart(FALSE)
(mwxではinit_warm()
)
ToCoNet_vBoard_Init()
- 無線マイコンのハードウェアの初期化(クロックなど)
vAHI_OnWakeup_MW(TRUE)
- ここで mwf ライブラリオブジェクトの
on_wakeup(true)
が呼び出される
- ここで mwf ライブラリオブジェクトの
ToCoNet_vInit_Warm()
cbAppWarmStart(TRUE)
(mwx ではsetup()
)
- TWENET初期化
- TWENETアプリケーションループ
class sys_global_resource_handler
I2C, PWMなど同一機能が複数単位定義される場合に、初期化と破棄の手続きを管理する上位クラス。
これら複数利用可能なペリフェラルでは一度だけ初期化の際に行う手続きと、全て利用終了してから破棄する手続きが存在する場合に利用する。(左記のペリフェラルであっても、実装状況に応じて本クラスを利用したりしない場合がある)
初期化と破棄の手続きは、オブジェクトが生成・破棄されるたびに更新される参照カウンタ(コンストラクタより渡す)により行う。
※ sys_ev_handler は抽象クラスだが、本クラスは CRTP を用いている。
init()
参照カウンタが1
になったとき(=初期化が必要な場合)に T::global_init()
を呼び出す。
※ このメンバ関数はペリフェラルクラスのコンストラクタから明示的に呼び出すこと。
deinit()
参照カウンタが0
になったとき T::global_deinit()
を呼び出す。
※ このメンバ関数はペリフェラルクラスのデストラクタから明示的に呼び出すこと。
class sys_ev_manager
ペリフェラルクラスオブジェクトを一括管理するためのコレクションクラス。ただし、オブジェクトの所有はせず、sys_ev_handler
クラスポインタを格納する固定配列にID_SYSHAND
列挙体が示すIDをインデックスとして格納する。
主目的はon_sleep()
, on_wake()
の手続きを一括で行うためである。
どのペリフェラルクラスオブジェクトが生成されるかはユーザプログラム次第であるため、すべてのクラスオブジェクトに対して if(the_pwm1) the_pwm1->on_sleep();
といった呼び出しは余分なコードをリンクすることにもなり非効率である。sys_ev_handler
型の抽象オブジェクトとして格納し、virtual
メソッドを呼び出している。
global_init_sysevmgr()
the_sys_ev_manager
インスタンスを生成する。
global_deinit_sysevmgr()
the_sys_ev_manager
インスタンスを破棄する。
reg_obj()
ペリフェラルクラスオブジェクトを登録する。
unreg_obj()
ペリフェラルクラスオブジェクトを登録から除外する。
on_wakeup(bool init_2nd)
登録オブジェクトに全てに対し、on_wake()
を実行する。
void on_sleep()
登録オブジェクトに全てに対し、on_sleep()
を実行する。
ペリフェラルクラスの定義例
class timer_n_pwm :
public mwf::sys_ev_handler // 基底クラス
, public mwf::sys_global_resource_handler<timer_n_pwm> // 基底クラス(必要な場合のみ)
{
using global_hdr = mwf::sys_global_resource_handler<timer_n_pwm>;
// 長いので省略形を定義しておく
static uint32_t _global_init_ct;
// sys_global_resource_handlerの参照カウンタ
public:
static void global_init_pwm(uint8_t u8_pwm_id, ...) { ... }
static void global_deinit_pwm_manager(uint8_t u8_pwm_id) { ... }
// the_pwm? の実体を生成・破棄するための手続き。
public:
// コンストラクタ
timer_n_pwm(/* コンストラクタ引数 */)
: mwf::sys_ev_handler(/*ID*/ ,static_cast<sys_ev_handler*>(this))
, mwf::sys_global_resource_handler<timer_n_pwm>(_global_init_ct)
{
global_hdr::init(); // sys_global_resource_handler<>の生成手続き
}
// デストラクタ (抽象クラスを継承しているため virtual 定義する)
virtual ~timer_n_pwm()
{
global_hdr::deinit(); // sys_global_resource_handler<>の破棄手続き
}
// sys_ev_handlerクラスの実装
virtual void on_sleep() { ... } // スリープ前に呼び出す
virtual void on_wakeup() { ... } // スリープ復帰後に呼び出す
// sys_global_resource_handler<>の実装。staticメンバ関数。
static void global_init(); // 一番最初の初期化手続き
static void global_deinit(); // 一番最後の破棄手続き
};
...
uint32_t mwf::periph::timer_n_pwm::_global_init_ct; // 参照カウンタの実体
上記は PWM (mwf_periph_pwm.hpp
) ペリフェラルクラスの定義抜粋です。他の殆どのクラスではsys_global_resource_handler<>
を利用していません。