LoginSignup
8
3

More than 1 year has passed since last update.

TOPPERS/ASPのイベントフラグの使い方

Last updated at Posted at 2021-12-19

はじめに

TOPPERSが提供する各種 RTOSのうち、「TOPPERS新世代カーネル」とよばれるグループの仕様は「TOPPERS新世代カーネル統合仕様書」というドキュメントで提供されています。

・TOPPERS新世代カーネル
 TOPPERS/ASPカーネル
 TOPPERS/FMPカーネル
 TOPPERS/HRP2カーネル
 TOPPERS/SSPカーネル
 TOPPERS/ASP Safetyカーネル

「TOPPERS新世代カーネル統合仕様書」には複数のTOPPERS新世代カーネルの説明が記述され、機能やAPIがまとめられているため、1ファイルを持っているだけで必要な情報を持つことができる反面、特定のAPIの使い方を見ようとした場合に非常に探しにくいという一面もあります。

2021年のTOPPERSコンテスト用の作品を開発中に、締め切り時間まで間もなく分単位の時間で作業をしていてる状況で、イベントフラグを使ってタスク間の同期をとろうと考えました。
直ぐに「TOPPERS新世代カーネル統合仕様書」を開いてイベントフラグの使い方を確認しようと思ったのですが、焦った状況で直ぐにこのように使うといのが瞬時に把握できませんでした。

このため、今後の利用を考慮して、APIの利用方をサンプルプログラムとしてQiita上にまとめようと考えました。
今回はコンテスト作品の開発で欲しかった「イベントフラグ」のサンプルを作りました。

イベントフラグの静的API

オブジェクトの生成情報や初期状態などを定義するために,システムコンフィギュレーションファイル中に記述するインタフェース。
システムコンフィギュレーションファイルは、TOPPERSに含まれるサンプルプログラムではsample1.cfgになります。

CRE_FLG( ID flgid, { ATR flgatr, FLGPTN iflgptn } )
引数 内容
ID flgid オブジェクトの識別子、プログラム内のAPIでこのマクロを使う
ATR flgatr イベントフラグの属性
FLGPTN iflgptn イベントフラグの初期ビットパターン

・イベントフラグの属性

マクロ 内容
TA_TPRI 0x01U 待ち行列をタスクの優先度順にする
TA_WMUL 0x02U 複数のタスクが待つのを許す
TA_CLR 0x04U タスクの待ち解除時にイベントフラグをクリアする

イベントフラグのプログラム内のAPI

イベントフラグのセット

flgidで指定したイベントフラグ(対象イベントフラグ)のsetptnで指定したビットをセットする。

ER ercd = set_flg(ID flgid, FLGPTN setptn)
引数 内容
ID flgid 対象イベントフラグのID番号
FLGPTN setptn セットするビットパターン

参考:ハンドラ(非タスクコンテキスト)からの呼び出し

ER ercd = iset_flg(ID flgid, FLGPTN setptn)

イベントフラグのクリア

flgidで指定したイベントフラグ(対象イベントフラグ)のclrptnで指定したビットをクリアする。

ER ercd = clr_flg(ID flgid, FLGPTN clrptn)
引数 内容
ID flgid 対象イベントフラグのID番号
FLGPTN clrptn クリアするビットパターン
クリアしないビットを1、クリアするビットを0

イベントフラグ待ち

flgidで指定したイベントフラグ(対象イベントフラグ)が、waiptn と wfmode で指定した待ち解除の条件を満たすのを待つ。

ER ercd = wai_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn)
引数 内容
ID flgid 対象イベントフラグのID番号
FLGPTN waiptn 待ちビットパターン
MODE wfmode 待ちモード
FLGPTN *p_flgptn 待ち解除時のビットパターンを入れるメモリ領域へのポインタ

・待ちモード

マクロ 内容
TWF_ORW 0x01U 待ちビットパターンに含まれるいずれかのビットがセットされるのを待つ
TWF_ANDW 0x02U 待ちビットパターンに含まれるすべてのビットがセットされるのを待つ

参考:イベントフラグ待ち(ポーリング)

ER ercd = pol_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn)
引数 内容
ID flgid 対象イベントフラグのID番号
FLGPTN waiptn 待ちビットパターン
MODE wfmode 待ちモード
FLGPTN *p_flgptn 待ち解除時のビットパターンを入れるメモリ領域へのポインタ

参考:イベントフラグ待ち(タイムアウト付き)

ER ercd = twai_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn, TMO tmout)
引数 内容
ID flgid 対象イベントフラグのID番号
FLGPTN waiptn 待ちビットパターン
MODE wfmode 待ちモード
FLGPTN *p_flgptn 待ち解除時のビットパターンを入れるメモリ領域へのポインタ
TMO tmout タイムアウト時間

イベントフラグの再初期化

flgidで指定したイベントフラグ(対象イベントフラグ)を再初期化する。
対象イベントフラグのビットパターンは,初期ビットパターンに初期化される。
対象イベントフラグの待ち行列につながれたタスクは,待ち行列の先頭のタスクから順に待ち解除される。
待ち解除されたタスクには,待ち状態となったサービスコールからE_DLTエラーが返る。

ER ercd = ini_flg(ID flgid)
引数 内容
ID flgid 対象イベントフラグのID番号

イベントフラグの削除

flgidで指定したイベントフラグ(対象イベントフラグ)を削除する。

ER ercd = del_flg(ID flgid)
引数 内容
ID flgid 対象イベントフラグのID番号

サンプルコード

TOPPERS/ASPsample1.cを使って、イベントフラグのサンプルプログラムを作ってみました。

サンプルプログラム

  • main_task()のほかにtask1()task2()task3()の計4つのタスクを生成します。
  • main_task()は他の3つのタスクをスタート後、tslp_tsk()でスリープを繰り返します。
  • task1()は1秒ごとにイベントフラグ FLG1へ0x01、0x02、0x03 (0x01|0x02) を順番にセットし、それを繰り返します。
  • task2()wai_flg()でイベントパターン0x01を待ち、イベントフラグがセットしたらコンソールにメッセージを出力します。
  • task3()wai_flg()でイベントパターン0x02を待ち、イベントフラグがセットしたらコンソールにメッセージを出力します。
  • task1()でイベントパターン0x01がセットされるとtask2()が起床してコンソールにメッセージが出力されます。
  • task1()でイベントパターン0x02がセットされるとtask3()が起床してコンソールにメッセージが出力されます。
  • task1()でイベントパターン0x03がセットされるとtask2()task3()が起床してコンソールにメッセージが出力されます。

以下に主要な設定や関数を記します。

sample1.cfg
CRE_TSK(TASK1, { TA_NULL, 1, task1, HIGH_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK2, { TA_NULL, 2, task2, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK3, { TA_NULL, 3, task3, LOW_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });
DEF_TEX(TASK1, { TA_NULL, tex_routine });
DEF_TEX(TASK2, { TA_NULL, tex_routine });
DEF_TEX(TASK3, { TA_NULL, tex_routine });

CRE_FLG(FLG1, { TA_WMUL, 0x00U });
sample1.h
#define MAIN_PRIORITY   5
#define HIGH_PRIORITY   9
#define MID_PRIORITY    10
#define LOW_PRIORITY    11

#define STACK_SIZE      4096

extern void     task1(intptr_t exinf);
extern void     task2(intptr_t exinf);
extern void     task3(intptr_t exinf);
extern void     main_task(intptr_t exinf);
sample1.c
void task1(intptr_t exinf)
{
  ER  er;

  syslog(LOG_NOTICE, "task1()");

  er = clr_flg( FLG1, 0x00 );

  while( 1 ) {
    tslp_tsk( 1000 );
    syslog(LOG_NOTICE, "set 0x01");
    er = set_flg( FLG1, 0x01 );

    tslp_tsk( 1000 );
    syslog(LOG_NOTICE, "set 0x02");
    er = set_flg( FLG1, 0x02 );

    tslp_tsk( 1000 );
    syslog(LOG_NOTICE, "set 0x03");
    er = set_flg( FLG1, 0x01 | 0x02 );
  }
}


void task2(intptr_t exinf)
{
  ER  er;
  FLGPTN  ptn;

  syslog(LOG_NOTICE, "task2()");

  while( 1 ) {
    er = wai_flg( FLG1, 0x01, TWF_ORW, &ptn );
    er = clr_flg( FLG1, ~0x01 );
    syslog(LOG_NOTICE, "wakeup task2()");
  }
}


void task3(intptr_t exinf)
{
  ER  er;
  FLGPTN  ptn;

  syslog(LOG_NOTICE, "task3()");

  while( 1 ) {
    er = wai_flg( FLG1, 0x02, TWF_ORW, &ptn );
    er = clr_flg( FLG1, ~0x02 );
    syslog(LOG_NOTICE, "wakeup task3()");
  }
}


void main_task(intptr_t exinf)
{
  syslog(LOG_NOTICE, "main_task()");

  SVC_PERROR(act_tsk(TASK1));
  SVC_PERROR(act_tsk(TASK2));
  SVC_PERROR(act_tsk(TASK3));

  while( 1 ) {
    tslp_tsk( 100 );
  }
}

結果

プログラムをビルドし、実行すると以下のような表示がコンソールへ出力されます。

TOPPERS/ASP Kernel Release 1.9.3 for RaspberryPi pico (Cortex-M0+) (Dec 20 2021, 01:07:24)
Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
                            Toyohashi Univ. of Technology, JAPAN
Copyright (C) 2004-2014 by Embedded and Real-Time Systems Laboratory
            Graduate School of Information Science, Nagoya Univ., JAPAN
Copyright (C) 2016-2017 by Education Working Group TOPPERS PROJECT

System logging task is started on port 1.
main_task()
task1()
task2()
task3()
set 0x01
wakeup task2()
set 0x02
wakeup task3()
set 0x03
wakeup task2()
wakeup task3()
set 0x01
wakeup task2()
set 0x02
wakeup task3()
set 0x03
wakeup task2()
wakeup task3()
set 0x01
wakeup task2()
set 0x02
wakeup task3()

さいごに

使いなれているAPIであれば、忘れたり曖昧な部分を「TOPPERS新世代カーネル統合仕様書」で直ぐに探してプログラムを書けると思いますが、初めて使う場合には少し読みにくい仕様書かなと個人的に思っています。
自分の備忘録や開発メモを兼ねて、他のAPIのサンプルを執筆していきたいと思ってます。

- 以上 -

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3