Smalight OSを使おう 11タスク目 イベントフラグの使用3 [Smalight OS]
この記事は、某SNSで書いているものを転載しています。
今回は、イベントフラグのクリアについて解説します。と言いましても、既に何度かサンプルの中で使っているので、もう用済みかな。
まずイベントフラグのクリアの方法には、二つの方法が有ります。
1.初期化時に、クリア属性を指定。
2.ユーザーがタスクの中でclr_flgを使用してクリア。
プログラムが一見簡単に構築できそうなのは、1.です。一々プログラムの中でクリアの処理を記述しなくても良いですから。
しかしこのクリア属性、そのクリアの仕方に落とし穴が有り、符号無し16bitを一気にクリアしてしまう為、もしビットそれぞれに意味が有ったとしたら、その意味を正しく受け取る前に、クリアされてしまうかも知れません。
この状況がどの様な時に問題になるのか説明します。
おそらく、一つのイベントフラグに、一つのタスクのみ待ち状態になるなら、wai_flgの戻り値を受ける事で、ビットの意味を失う事は無いでしょう。
しかし、一つのイベントフラグに複数のタスクが待ち状態になる時、それは起きます。
では実際にプログラムを動かして、その様子を見てみます。
コンパイラの設定は、
EVENTFLGを有効
config.cの設定は、
tsk01:優先度1、起動時READY
tsk02:優先度2、起動時READY
tsk03:優先度3、起動時READY
ユーザー初期化関数uinitの設定は、
EVTFLG_ATTR(FID_1, EVFLG_TA_AND | EVFLG_TA_CLR | EVFLG_TA_TPRI );
#define TID_1 1 /**/ #define TID_2 2 /**/ #define TID_3 3 /**/ #define FID_1 1 /**/ #define FLG_WAIT_PTN_01 0x0001 /**/ #define FLG_WAIT_PTN_02 0x0002 /**/ void uinit(void) { /* initialize */ /* event flag initialize */ evtflg_init(); EVTFLG_ATTR(FID_1, EVFLG_TA_AND | EVFLG_TA_CLR | EVFLG_TA_TFIFO ); } void tsk01( void ) { wai_flg( FID_1, FLG_WAIT_PTN_01 ); slp_tsk(); /*ここにブレークポイントを設定*/ } void tsk02( void ) { wai_flg( FID_1, FLG_WAIT_PTN_02 ); slp_tsk(); /*ここにブレークポイントを設定*/ } void tsk03( void ) { set_flg( FID_1, FLG_WAIT_PTN_01 | FLG_WAIT_PTN_02 ); while( 1 ) ; }
さて、二箇所にブレークポイントを設定しましたが、tsk02のブレークポイントに達したでしょうか?。
答えは否ですね。
動作を説明すると、まずtsk01が起動し、イベントフラグの待ち状態に入ります。続いてtsk02が起動し、やはり同様に待ち状態に入ります。最後にtsk03が起動し、二つのビットをセットします。
このset_flgの中でtsk01がイベントフラグ待ち状態である事を検知したOSは、tsk01の待ち状態を解除し、戻り値に現在のフラグをコピーした後、イベントフラグがクリア属性である為、フラグの内容を全てクリアしてしまいます。
その為、tsk02のWAITが解除とならず、このプログラムではそのまま待ち続ける事となってしまいました。
この様にクリア属性をうっかり使用すると、思わぬバグとなってしまいます。
では、複数のタスクが一つのイベントフラグの待ち状態になっても事故を起さない方法は、それは勿論無関係なビットのクリアを行わない事!これに尽きる訳です。
上のプログラムを下記の様に書き換えて動かしてみます。
void uinit(void) { /* initialize */ /* event flag initialize */ evtflg_init(); EVTFLG_ATTR(FID_1, EVFLG_TA_AND | EVFLG_TA_TFIFO ); } void tsk01( void ) { wai_flg( FID_1, FLG_WAIT_PTN_01 ); clr_flg( FID_1, ~FLG_WAIT_PTN_01 ); slp_tsk(); /*ここにブレークポイントを設定*/ } void tsk02( void ) { wai_flg( FID_1, FLG_WAIT_PTN_02 ); clr_flg( FID_1, ~FLG_WAIT_PTN_02 ); slp_tsk(); /*ここにブレークポイントを設定*/ } void tsk03( void ) { set_flg( FID_1, FLG_WAIT_PTN_01 | FLG_WAIT_PTN_02 ); while( 1 ) ; }
EVTFLG_ATTRマクロのEVFLG_TA_CLRを削除しています。
wai_flgの後にclr_flgを追加しています。
どうでしょうか、今度はtsk01、tsk02の両方のブレークポイントに到達した筈です。
最近、新しい本が出ましたね。
組み込みソフトウェアの設計&検証―割り込み動作からRTOSを使った設計、ツールによる動作検証まで
- 作者: 藤倉 俊幸
- 出版社/メーカー: CQ出版
- 発売日: 2007/02
- メディア: 単行本
コメント 0