トロンフォーラム

3. μT-Kernel 3.0プログラミング

3-1. タスクの生成・実行のプログラム

μT-Kernel上で動作するプログラムの基本的な実行単位はタスクです。ユーザプログラムは一つまたは複数のタスクから構成されます。タスクを生成して実行するプログラムを作ってみましょう。

プログラム3-1:タスクの生成と実行

一つのタスクを生成し実行します。タスクはデバッグ用のシリアル通信出力にメッセージ「Start Task-A」を出力して終了します。

以下のプログラムを作成します。

本プログラムで使用するAPI

本プログラムで使用するタスク制御APIを以下に説明します。

タスクの生成

タスクは、タスク生成API tk_cre_tskにより生成します。

tk_cre_tskのAPIの仕様を以下に説明します。

タスク生成API
関数定義 ID tk_cre_tsk( CONST T_CTSK *pk_ctsk );
引数 T_CTSK *pk_ctsk タスク生成情報
戻り値 タスクID番号、またはエラーコード
機能 * pk_ctskで指定したタスク生成情報に基づき、タスクを生成します。
生成したタスクのID番号を戻り値として返します。

タスク生成情報T_CTSKは、タスクを生成するための情報を格納した構造体です。tk_cre_tskの引数にこの構造体を指すポインタを渡します。

T_CTSK構造体のメンバーは必要に応じて設定しますが、以下のメンバーは必ず設定する必要があります。

タスク属性 tskatr

生成するタスクがどのようなタスクであるか、タスクの属性を指定します(「2-2 タスクの基本」を参照)。

一般的なアプリケーションのタスクの属性は、TA_HLNGおよびTA_RNG3です。TA_HLNG属性はタスクがC言語で記述されていることを示します。TA_RNG3はタスクが一般的なユーザプログラムであることを示します。

なお、MMUによるメモリ保護を使用していないμT-Kernel 3.0では、保護レベルの指定があっても、実際の動作には影響しません。ただし、メモリ保護のあるシステムとの互換性を考慮し、タスクの用途に応じた保護レベルの設定を推奨します。

タスク起動アドレス task

タスクのプログラムの実行開始アドレスを示します。タスク属性がTA_HLNG(C言語で記述)の場合は、タスクの実行関数へのポインタを指定します。

タスクの実行関数は、以下の形式の関数です。

void task( INT stacd, void *exinf);

第一引数のstacdは、後述のタスク起動API tk_sta_tskで指定します。第二引数のexinfはタスク生成時に指定可能です(本記事では使用しません)。

タスク起動時優先度 itskpri

タスクの優先度の初期値です。タスクが実行を開始する際には、ここで指定された優先度で動作します。

タスクの優先度は、一般にはユーザプログラム全体を通じたシステム設計によって決める必要があります。本記事に記載のプログラムでは優先度10とします。

スタックサイズ stksz

タスクが使用するスタックのサイズです。タスクの生成時に指定したサイズのメモリがスタックとして確保されます。もし、タスクの実行中に指定を超えるサイズのスタックを使用した場合は、重大なエラーとなる危険があります。

スタックサイズは、そのタスクのプログラムのスタック必要量から計算し、それ以上のサイズを設定する必要があります。本記事に記載のプログラムでは、アプリケーションのタスクのスタックサイズを、余裕をみた値として1024バイトにしています。

tk_cre_tskは戻り値として新しく生成されたタスクのID番号を返します。以降は、このID番号を使って生成したタスクへの操作を行います。

タスクの実行

生成したタスクは休止状態であり、まだ実行されていません。タスク起動API tk_sta_tskを呼び出し、タスクを実行できる状態とします。

tk_sta_tskのAPIの仕様を以下に説明します。

タスク起動API
関数定義 ER tk_sta_tsk( ID tskid, INT stacd );
引数 ID tskid タスクID番号
INT stacd タスク起動コード
戻り値 エラーコード
機能 tskidで指定したタスクを休止状態から動作できる状態に移します。
stacdに設定した値は、タスクの実行関数の引数に渡されます。
タスクの起床待ち(タスクの一時停止)

タスクの動作を一時的に停止するには、タスク起床待ちAPI tk_slp_tskを呼び出して、タスクを起床待ち状態にします。起床待ち状態のタスクは他のタスクから起床されるまで動作を停止します。

tk_slp_tskのAPIの仕様を以下に説明します。

タスク起床待ちAPI
関数定義 ER tk_slp_tsk( TMO tmout );
引数 TMO tmout タイムアウト時間(単位ミリ秒)
戻り値 エラーコード
機能 APIを呼び出したタスクを起床待ち状態とします。
他のタスクから起床されると待ち状態は解除されます。またはtmoutで指定した時間内に、他のタスクから起床されなかった場合はタイムアウトのエラーで待ち状態は解除されます。
タスクの終了

タスクを終了する際には、自タスク終了API tk_ext_tskを呼び出して、タスクを終了させます。もしタスクを終了させることなく、タスクの実行関数からreturnが実行されてしまうと、そのタスクは暴走してしまいますので注意が必要です。

tk_ext_tskのAPIの仕様を以下に説明します。

自タスク終了API
関数定義 void tk_ext_tsk( void );
引数 なし
戻り値 なし
機能 APIを呼び出したタスクを終了します。

プログラム例

「プログラム3-1:タスクの生成・実行」のプログラムのリストを以下に示します。

リスト3-1 タスクの生成と実行

リスト3-1のプログラムの内容を順番に説明していきます。

  1. タスクAの生成情報と関連データ
    タスクAの実行関数task_aのプロトタイプ宣言、タスクAのID番号を格納するための変数tskid_a、タスクAの生成情報の変数ctsk_aを記述しています。
  2. タスクAの実行関数
    関数task_aは、タスクAの実行関数です。本プログラムでは、デバッグ用出力関数tm_printfでメッセージ「Start Task-A」を出力したのち、自タスク終了API tk_ext_tskを呼び出してタスクAを終了します。
  3. usermain関数
    usermain関数は、タスク生成API tk_cre_tskを呼び出してタスクAを生成します。続いてタスク起動API tk_sta_tskを呼び出して生成したタスクAの実行を開始します。
    最後にusermain関数は、タスク起床待ちAPI tk_slp_tskを実行し、起床待ち状態となります。これは、usermain関数の終了によりμT-Kernelのシステム全体が終了することを防ぐためです。
    なお、usermain関数を実行している初期タスクの優先度は最高優先度(優先度1)ですので、usermain関数の実行中は優先度10のタスクAは実行されません。
    tk_slp_tskの呼び出しにより初期タスクが待ち状態になると、タスクAが実行されます。

3-2. マルチタスクのプログラム

複数のタスクを生成して同時に実行するマルチタスクのプログラムを作ってみましょう。

ここでは、LEDとスイッチの制御を、それぞれ別のタスクとして同時に実行させることにします。別々のプログラムに含まれていたタスクが、一つのプログラムの中で同時に動作することが確認できます。

なお、特定のハードウェアは想定せず、LEDとスイッチの制御関数があるものとしてプログラムを作成します。

以下のプログラムを作成します。

プログラム3-2:マルチタスクの実行

二つのタスクを生成、実行し、二つのタスクの機能が同時に動作することを確認します。二つのタスクは以下の動作をします。

  1. スイッチ制御タスク
    ボタン・スイッチを監視し、ボタン・スイッチが押されると、デバッグ出力に「SW-ON」と表示します。
  2. LED制御タスク
    LEDを0.5秒ごとに点滅させます。

本プログラムで使用するAPI

使用するμT-KernelのAPIは「3-1 タスクの生成と実行」と同じです。

以下のLEDとスイッチの制御関数があるものとします。実際のプログラムを動作させるには、実行するハードウェアに応じてこの関数を作成する必要があります。

LED制御関数
LED制御関数
関数定義 void led_ctl( UINT on_off );
引数 UINT on_off LEDの状態(0で消灯、それ以外は点灯)
戻り値 なし
機能 引数on_offの指定に応じてLEDを制御します。
スイッチ制御関数
スイッチ制御関数
関数定義 UW get_sw( void );
引数 なし
戻り値 スイッチの状態(0でオフ、それ以外はオン)
機能 スイッチの状態を戻り値に返します。

プログラム例

「プログラム3-2:マルチタスクの実行」のプログラムのリストを以下に示します。

リスト3-2 マルチタスクの実行

リスト3-2のプログラムの内容を順番に説明していきます。

  1. スイッチ制御タスクの生成情報と関連データ
    スイッチ制御タスクの実行関数task_swのプロトタイプ宣言、スイッチ制御タスクのID番号を格納するための変数tskid_sw、スイッチ制御タスクの生成情報の変数ctsk_swを記述しています。
  2. LED制御タスクの生成情報と関連データ
    LED制御タスクの実行関数task_ledのプロトタイプ宣言、LED制御タスクのID番号を格納するための変数tskid_led 、LED制御タスクの生成情報の変数ctsk_ledを記述しています。
  3. スイッチ制御タスクの実行関数
    関数task_swは、スイッチ制御タスクの実行関数です。
    関数の最後に自タスク終了API tk_ext_tskを記述していますが、本関数はwhile文による無限ループから抜けませんので、このAPIが実行されることはありません。
  4. LED制御タスクの実行関数
    関数task_ledは、LED制御タスクの実行関数です。
    関数の最後に自タスク終了API tk_ext_tskを記述していますが、本関数はwhile文による無限ループから抜けませんので、このAPIが実行されることはありません。
  5. usermain関数
    usermain関数では、スイッチ制御タスクとLED制御タスクの生成および実行を行います。
    最後にusermain関数は、タスクの起床待ちAPI tk_slp_tskを実行し、起床待ち状態となります。これはusermain関数の終了によりμT-Kernelのシステム全体が終了することを防ぐためです。tk_slp_tskの呼び出しによって初期タスクが待ち状態になると、LED制御タスクとスイッチ制御タスクが実行されます。

3-3. イベントフラグのプログラム

マルチタスクで実行するタスクの間では、イベントフラグを用いて、イベントの発生を通知し、動作の同期をとることができます(「2-4. イベントフラグ」を参照)。

3-2. マルチタスクのプログラム」では、それぞれのタスクでLEDとスイッチの制御を行いました。今回はイベントフラグを用いて、ボタン・スイッチが押されたというイベントをタスク間で通知し、タスクの動作を同期してみましょう(LEDとスイッチの制御は「3-2. マルチタスクのプログラム」と同様にLEDとスイッチの制御関数があるものとします)。

以下のプログラムを作成します。

プログラム3-3:イベントフラグによる同期

ボタン・スイッチを押すとLEDが3秒間点灯するプログラムを、二つのタスクをイベントフラグで同期させて実現します。

二つのタスクは以下の動作をします。

  1. スイッチ制御タスク
    ボタン・スイッチを監視し、ボタン・スイッチが押されると、イベントフラグをセットします。
  2. LED制御タスク
    イベントフラグがセットされるのを待ち、セットされると、LEDを3秒間点灯します。

本プログラムで使用するAPI

本プログラムで使用するイベントフラグのAPIを以下に説明します。タスク制御APIに関しては「3-1タスクの生成と実行」で説明しています。

イベントフラグの生成

イベントフラグはイベントフラグの生成API tk_cre_flgにより生成します。

tk_cre_flgのAPIの仕様を以下に説明します。

イベントフラグ生成API
関数定義 ID tk_cre_flg( CONST T_CFLG *pk_cflg );
引数 T_CFLG *pk_cflg イベントフラグ生成情報
戻り値 イベントフラグID番号、またはエラーコード
機能 *pk_cflgで指定したイベントフラグ生成情報に基づき、イベントフラグを生成します。
生成したイベントフラグのID番号を戻り値として返します。

イベントフラグ生成情報T_CFLGは、イベントフラグを生成するための情報を格納した構造体です。tk_cre_flgの引数にこの構造体へのポインタを渡します。

T_CFLG構造体のメンバーは必要に応じて設定しますが、以下のメンバーは必ず設定する必要があります。

イベントフラグ属性 flgatr

イベントフラグの性質を表わす属性です。主な属性を表3-3-1に示します。

表3-3-1 イベントフラグの主な属性
属性名 意味
TA_TFIFO 待ちタスクの並びは先着順(FIFO順)(※1)
TA_TPRI 待ちタスクの並びは優先度順(※1)
TA_WSGL 複数のタスクの待ちを許さない(※2)
TA_WMUL 複数のタスクの待ちを許す(※2)

(※1)TA_TFIFOとTA_TPRIのいずれか一方を必ず指定する必要があります

(※2)TA_WSGLとTA_WMULのいずれか一方を必ず指定する必要があります

イベントフラグの初期値 iflgptn

イベントフラグの生成時の初期値です。イベントが何も発生してなければ、初期値は0とします。

イベントフラグのセット

イベントフラグのセットは、イベントフラグのセットAPI tk_set_flgを使用します。

tk_set_flgのAPIの仕様を以下に説明します。

イベントフラグのセットAPI
関数定義 ER tk_set_flg( ID flgid, UINT flgptn );
引数 ID flgid イベントフラグのID番号
UINT flgptn セットするビットパターン
戻り値 エラーコード
機能 flgidで指定したイベントフラグにflgptnで示されているビットパターンをセットします。具体的にはその時点のイベントフラグの値に、flgptnの値の論理和がとられます。
イベントフラグの待ち状態のタスクの中から、条件が成立したタスクの待ちを解除します。

イベントフラグ待ち

イベントフラグのセットを待つには、イベントフラグ待ちAPI tk_wai_flgを使用します。

tk_wai_flgのAPIの仕様を以下に説明します。

イベントフラグ待ちAPI
関数定義 ER tk_wai_flg( ID flgid, UINT waiptn, UINT wfmode, UINT *p_flgptn, TMO tmout );
引数 ID flgid イベントフラグのID番号
UINT waiptn 待ちビットパターン
UINT wfmode 待ちモード
UINT *p_flgptn 解除時のビットパターン
TMO tmout タイムアウト時間(単位ミリ秒)
戻り値 エラーコード
機能 flgidで指定したイベントフラグに対して、waiptnで指定したビットパターンと、wfmodeで指定したモードで、イベントフラグがセットされるのを待ちます。
条件が成立し待ちが解除されると、*p_flgptnに解除時のビットパターンが返されます。またはtmoutで指定した時間内に、条件が成立しなかった場合はタイムアウトのエラーで待ち状態は解除されます。

イベントフラグの待ちモードには表3-3-2に示すものがあります。

表3-3-2 イベントフラグの待ちモード
属性名 意味
TWF_ANDW 指定した全てのビットがセットされるまで待つ(※)
TWF_ORW 指定したビットのいずれかがセットされるまで待つ(※)
TWF_CLR 条件が成立したら全ビットをクリアする
TWF_BITCLR 条件が成立したビットをクリアする

(※)TWF_ANDWとTWF_ORWのいずれか一方を必ず指定する必要があります

プログラム例

「プログラム3-3:イベントフラグによる同期」のプログラムのリストを以下に示します。

リスト3-3 イベントフラグによる同期

リスト3-3のプログラムの内容を順番に説明していきます。

  1. イベントフラグの生成情報と関連データ
    flgid_aはイベントフラグのID番号を格納するための変数です。
    cflg_aはイベントフラグの生成情報の変数です。イベントフラグ属性はTA_TFIFO(待ちタスクは先着順)とTA_WMUL(複数のタスクの待ちを許す)としましたが、今回はイベントを待つタスクが一つだけですので、実際の動作には影響しません。
    イベントフラグの初期値は、まだイベントが発生していないという意味で0とします。
    イベントフラグの内容は、スイッチを押したことを通知するイベントのみですので、イベントフラグの第0ビット目をスイッチオンイベントとして、以下のように定義します。
    #define FLG_SW_ON (1<<0)
  2. スイッチ制御タスクの生成情報と関連データ
    「プログラム3-2:マルチタスク」と同じです。
  3. LED制御タスクの生成情報と関連データ
    「プログラム3-2:マルチタスク」と同じです。
  4. スイッチ制御タスクの実行関数
    関数task_swは、0.1秒の間隔でスイッチの状態をポーリングし、スイッチが押されたことを検出した場合には、イベントフラグのセットAPI tk_set_flgを呼び出し、スイッチオンイベントをセットします。
  5. LED制御タスクの実行関数
    関数task_ledは、最初にイベントフラグ待ちAPI tk_wai_flgを呼び出し、イベント待ち状態となって実行を一時停止します。その際、TWF_BITCLRモードを指定し、待ちが解除された際に条件ビットがクリアされるように指定します。
    イベントフラグがセットされると、LEDを点灯してから、タスクの遅延API tk_dly_tskを呼び出してタスクの動作を3秒間停止します。3秒が経過し再び実行されるとLEDを消灯します。
    以降、この動作を繰り返します。
  6. usermain関数
    usermain関数は、最初にイベントフラグ生成API tk_cre_flgを呼び出してイベントフラグを生成します。以降は「プログラム3-2:マルチタスク」と同じです。

Return Top