からくりブログ

株式会社からくり社員のブログです

Raspberry Pi 3 + μITRON その6(イベントフラグその2)

新年明けましておめでとうございます。今年もよろしくお願いいたします。 前回はイベントフラグについて説明しました。今回はRaspberry Pi3での動きを見ながらイベントフラグについておさらいしたいと思います。 イベントフラグを増やしたり減らしたりについては、前々回同様「コンフィギュレータ」を使用してリソースをいくつ使用するかを定義します。
前々回のasp3/sample/sample1.cfgをもう一度掲載しておきます。
/*
 *      サンプルプログラム(1)のシステムコンフィギュレーションファイル
 *
 *  $Id: sample1.cfg 705 2016-03-29 14:16:41Z ertl-hiro $
 */
INCLUDE("tecsgen.cfg");

#include "sample1.h"
CRE_TSK(TASK1, { TA_NULL, 1, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK2, { TA_NULL, 2, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK3, { TA_NULL, 3, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(EXC_TASK, { TA_NULL, 0, exc_task, EXC_PRIORITY, STACK_SIZE, NULL });
CRE_CYC(CYCHDR1, { TA_NULL, { TNFY_HANDLER, 0, cyclic_handler }, 2000000, 0 });
CRE_ALM(ALMHDR1, { TA_NULL, { TNFY_HANDLER, 0, alarm_handler }});
#ifdef INTNO1
CFG_INT(INTNO1, { INTNO1_INTATR, INTNO1_INTPRI });
CRE_ISR(INTNO1_ISR, { TA_NULL, 0, INTNO1, intno1_isr, 1 });
#endif /* INTNO1 */
#ifdef CPUEXC1
DEF_EXC(CPUEXC1, { TA_NULL, cpuexc_handler });
#endif /* CPUEXC1 */
今回はここにイベントフラグを追加します。具体的には、前回簡単に説明した「CRE_FLG」を追加します。場所は「CRE_ALM」の下にでも追加しましょう。
追加した結果は以下の通りとなります。
/*
 *      サンプルプログラム(1)のシステムコンフィギュレーションファイル
 *
 *  $Id: sample1.cfg 705 2016-03-29 14:16:41Z ertl-hiro $
 */
INCLUDE("tecsgen.cfg");

#include "sample1.h"
CRE_TSK(TASK1, { TA_NULL, 1, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK2, { TA_NULL, 2, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK3, { TA_NULL, 3, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(EXC_TASK, { TA_NULL, 0, exc_task, EXC_PRIORITY, STACK_SIZE, NULL });
CRE_CYC(CYCHDR1, { TA_NULL, { TNFY_HANDLER, 0, cyclic_handler }, 2000000, 0 });
CRE_ALM(ALMHDR1, { TA_NULL, { TNFY_HANDLER, 0, alarm_handler }});
CRE_FLG(FLG1, {TA_CLR | TA_WMUL, 0});        // ★
#ifdef INTNO1
CFG_INT(INTNO1, { INTNO1_INTATR, INTNO1_INTPRI });
CRE_ISR(INTNO1_ISR, { TA_NULL, 0, INTNO1, intno1_isr, 1 });
#endif /* INTNO1 */
#ifdef CPUEXC1
DEF_EXC(CPUEXC1, { TA_NULL, cpuexc_handler });
#endif /* CPUEXC1 */
今回は前々回のサンプルプログラムを改造します。タスクが3つあるので、それぞれ個別のイベントフラグがセットされるのを待つというふうに改造しようと思ったのですが、タスク自体は1つの関数として実装されているので、1つのイベントフラグに対して待ちを行い、「waiptn」で自分が待っているビットパターンと一致した場合にイベントフラグ待ちから抜けるという仕様にしたいと思います。待つビットパターンはタスク番号とします。 「TA_CLR」とついていますが、これは「wai_flg」のイベントフラグセット待ちから抜けた際に、セットされているイベントフラグを自動的にクリアするオプションです。指定しない場合は自分で「clr_flg」を使用してクリアしないと、ずっとセットされっぱなしで「wai_flg」で待たずにずっと抜け続けてしまうことになります。 「TA_WMUL」ですが、先程書いたように1つのイベントフラグを複数箇所で待つようにするので、それを許可するための指定です。 それでは、並行に実行される3つのタスクの改造箇所を見てみましょう。
asp3/sample/sample1.cの抜粋は以下の通りです。
/*
 *  並行実行されるタスク
 */
void task(intptr_t exinf)
{
    volatile ulong_t    i;
    int_t       n = 0;
    int_t       tskno = (int_t) exinf;
    const char  *graph[] = { "|", "  +", "    *" };
    char        c;
    ER          ercd;                                       // ★
    FLGPTN      p_flgptn;                                   // ★

    while (true) {
        syslog(LOG_NOTICE, "task%d is running (%03d).   %s",
                                        tskno, ++n, graph[tskno-1]);
        //for (i = 0; i < task_loop; i++);                  // ★
        ercd = wai_flg(FLG1, tskno, TWF_ANDW, &p_flgptn);   // ★
        c = message[tskno-1];
        message[tskno-1] = 0;
:
「★」印のところが改造箇所となります。for文でループして待つのをやめ、「wai_flg」で待つように変えました。 さて、これだとイベントフラグがセットされるのを待つところのみができただけなので、今度はイベントフラグをセットする箇所も用意しなくてはなりません。
このサンプルプログラムは、キーボードから「e/s/S/d/y/Y/z/Z」のいずれかが入力された場合に並行実行されるタスクが要求を判断して動作を変えるようになっています。(それ以外の入力はメイン側で動作を変えています)そのため、その箇所にイベントフラグをセットする処理を追加しました。以下が同じソースファイルからの抜粋です。
/*
 *  メインタスク
 */
void main_task(intptr_t exinf)
{
:
#endif /* TASK_LOOP */
    HRTCNT  hrtcnt1, hrtcnt2;
    ER      flg_ercd;                           // ★
:
    /*
      *  メインループ
     */
    do {
        SVC_PERROR(serial_rea_dat(TASK_PORTID, &c, 1));
        switch (c) {
        case 'e':
        case 's':
        case 'S':
        case 'd':
        case 'y':
        case 'Y':
        case 'z':
        case 'Z':
            message[tskno-1] = c;
            flg_ercd = set_flg(FLG1, tskno);    // ★
            break;
:
同じく「★」印のところが改造箇所になります。変数「message」に値をセットしたあと、イベントフラグをセットするようにしました。 それでは実際に動かしてみましょう。まず電源を入れた状態のログは以下のとおりです。
4緲儺b愁喉有J?х頻濠R4
                      ・.・W・H.]X杭s (exinf = 0).
task1 is running (001).   |
task2 is running (001).     +
task3 is running (001).       *
文字化けしているのはご愛嬌。前々回ではログが流れていたのが、この状態で止まっています。「wai_tsk」でイベントフラグがセットされているのを待っている証拠です。ここで1番のタスクを終了させてみましょう。「1」を押してから「e」を押します。以下のようなログになりました。
4緲儺b愁喉有J?х頻濠R4
                      ・.・W・H.]X杭s (exinf = 0).
task1 is running (001).   |
task2 is running (001).     +
task3 is running (001).       *
#1#ext_
最後が切れてしまっていますが、1番のタスクが「ext_tsk」で終了したようです。では同じく1番のタスクを「act_tsk」で動かしてみましょう。「1」「a」です。今度は次のようなログになりました。
4緲儺b愁喉有J?х頻濠R4
                      ・.・W・H.]X杭s (exinf = 0).
task1 is running (001).   |
task2 is running (001).     +
task3 is running (001).       *
#1#ext_
#act_tsk(1)
task1 is running (001).   |
これでタスクが動き出したことが確認できました。2番や3番のタスクも、同様の手順で確認できます。
4緲儺b愁喉有J?х頻濠R4
                      ・.・W・H.]X杭s (exinf = 0).
task1 is running (001).   |
task2 is running (001).     +
task3 is running (001).       *
#1#ext_
#act_tsk(1)
task1 is running (001).   |
#2#ext_
#act_tsk(2)
task2 is running (001).     +
#3#ext_
#act_tsk(3)
task3 is running (001).       *
このようにして、イベントフラグの動作を確認することができました。 今回はサンプルプログラムを最小限の改造で動かすようにしたので、一つのイベントフラグIDに対して複数のビットパターンで待つという仕様にしましたが、イベントフラグIDはどう分ければいいのか?ビットパターンで分けるのと、どう使い分ければいいのか?それは設計方針によって変わってくるので、いろいろと考えてみてください。それではまた。

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>