トロンフォーラム

第2回 タスクとは

今回からは、RTOSが提供する機能について説明します。

毎回サンプルプログラムを示しながら、RTOSが提供する機能について具体的に説明していきます。

なお、本稿で説明するサンプルプログラムは、トロンフォーラムが無償でソースコードを配布しているT-Kernel 2.0で実際に動作させることができます。

T-Kernel 2.0は、ARM11を搭載したT-Engineリファレンスボードに対応していますが、Windows PCで動作するCPUエミュレータ(ARM11をエミュレートします)や統合開発環境(Eclipse)も用意してあります。Windows PCがあればT-Kernel 2.0のプログラムを動作させることができますので、是非、毎回プログラムを実行して実際のRTOSの動作を確認してみてください。

※ T-Kernel 2.0 の概要についてはこちらをご覧ください。
※ T-Kernel 2.0 についてはTRONWARE Vol.140に詳細記事が掲載されています。
※ T-Kernel 2.0 はこちらからダウンロードしていただけます。

タスクとは?

一般に、組込み機器にはいろいろな機能が必要とされます。例えば、センサの値を読み取って結果を解析するとか、画面に図形を描画するとか、ネットワーク経由で外部と通信するとか。これらはそれぞれが独立して動作できる機能です。

T-Kernel 2.0 (以降、単にT-Kernelとします) には、このような複数の処理を並列して実行させる機能があります。T-Kernelでは、このような並列に実行する際の処理の単位を「タスク」と呼びます。T-Kernelで動作させるプログラムは、一つのタスクの中では逐次的に実行されますが、異なるタスクの間では並行して実行されることになります。

ただし、「並行して実行される」というのはアプリケーションからみた概念的な動作であり、実際にはT-Kernelが自動的に複数のタスクを切り換えて実行しています。

図 T-Kernelが機能毎のプログラムをタスクとして実行

図 T-Kernelが機能毎のプログラムをタスクとして実行

では、具体的にはどうやってタスクを記述するのか?

T-KernelのタスクはC言語の関数として記述できます。C言語で関数を作って、それをT-Kernelに登録すれば、後はT-Kernelがタスクとして実行してくれます。

例えば、以下の例では5行目〜12行目と14行目〜21行目の関数がタスクとして実行されるプログラムになります。

※ 以下のサンプルプログラムはこちらからダウンロードできます。

2つとも一定時間毎にメッセージを出力するだけのシンプルなタスクですが、基本的なタスクの書き方はこのプログラムに含まれています。この基本さえおさえておけば、T-Kernelを使ったマルチタスクのプログラムを開発することができます。

図 2つのタスクの基本動作

図 2つのタスクの基本動作

サンプルプログラムの説明

以下では、サンプルプログラムの詳細について、順を追って説明します。

ヘッダファイル 1行目〜3行目

T-Kernelでは、ヘッダファイルをtkernel_source/includeに集めています。ここでは3つのファイルをインクルードしていますが、まずは、「T-Kernelのアプリケーションの開発では、basic.hとtkernel.hをインクルードする」と覚えておいてください。

  • basic.hは、T-Kernelで使用する基本型などを定義しています。
    T-Kernel用のプログラムでは、まずこのファイルをインクルードしてください。
  • tkernel.hは、T-Kernelの機能(システムコール)を利用する場合にインクルードします。
  • tmonitor.hは、モニタ機能※1を利用する場合にインクルードしてください。
    具体的には、プリフィックスとして tm_ が付く関数を利用する場合にインクルードしてください。(サンプルではtm_putstringを利用しています。)
タスクを定義するプログラム 5行目〜21行目
タスクAの動作

タスクAは、T-Kernelから起動されると、コンソールに "I'm Task A." とメッセージを表示します。その後、T-Kernelの機能(tk_dly_tsk)を利用して1秒間の待ち状態になります。(tk_dly_tskのパラメータは単位がミリ秒なので、1000ミリ秒=1秒となります。)タスクが待っている間は、tk_dly_tskという関数から戻ってきませんので、tk_dly_tskの次にある処理は1秒後に実行されることになります。結局、プログラムとしては処理を順番に記述していけばよく、待っている間に何をしているかは気にする必要がありません。

なお、あるタスクが待ち状態になっている間は、他のタスクが動作します。どのタスクを動作させるかはT-Kernelが自動的に判断してくれますので、プログラマは気にする必要がありません※2

タスクを定義するプログラムの関数名

タスク用の関数名は自由に設定できます。特に制限はありませんので、普通にC言語の関数として作ってください。ただし、タスクの型はvoid、引数の型は INT と VP にしてください。これはT-Kernelがこの形式でタスクを呼び出すことになっているからです。

タスクBの動作

タスクBもタスクAと同じ動作をします。ただし、メッセージは "I'm Task B." 、待ち状態になる時間は2秒間になっています。

タスクの終了 11行目と20行目のtk_ext_tsk

タスクの最後には tk_ext_tsk(); と記述してください。tk_ext_tskによって、タスクの実行が終了したことをT-Kernelに通知します※3

usermain 23行目〜38行目

T-Kernelには「初期タスク」という、最初からT-Kernelに登録されていて、システムが起動すると同時に動作を開始するタスクがあります。初期タスクから呼び出される関数が usermain です。「T-Kernelのアプリケーションは usermain から記述する」と覚えておいてください。

タスクの生成 30行目、33行目のtk_cre_tsk

タスク用に作成した関数をT-Kernelに登録します。

タスクを生成する時に利用するシステムコールがtk_cre_tskです。パラメータにはT_CTSK型の構造体へのポインタを指定します。構造体は以下のように定義されていて、タスクに関するいろいろな情報を設定することができます。

必ず設定しなければならないのは tskatr, task, itskpri, stksz の4つです※4

サンプルプログラムでは以下の値を変数の宣言時に設定しています(25行目と26行目)。

  • tskatrには、TA_HLNG|TA_RNG0 を設定してください(まずはこれが基本です)。
  • taskには、タスク用に用意した関数を設定してください。
    例では、タスクAはtaskA、タスクBはtaskBを指定しています。
  • itskpriには、1以上の整数値を指定します。
    この値はタスク優先度と言い、どのタスクを優先的に実行するかを指定します。
    とりあえず1としておいてください。
  • stkszにはタスクで使用するスタックのサイズを指定します。
    タスクとして用意した関数と、そこから呼び出す関数で利用するスタックの最大値を設定する必要があります。関数のネストがそれほど深くなければ、とりあえず 4 KB くらいに設定します。

何も難しいことはありません。サンプルプログラムにあるように

T_CTSK ctskA = { NULL, TA_HLNG|TA_RNG0, taskA, 1, 4*1024 };

と書いて、3個目にタスク用に用意した関数の名前(関数へのポインタ)を指定すれば、タスク生成のためのパラメータ(T-Kernelにタスクを登録するための情報)は完成です。

なお、タスクの生成(登録)に成功すると、tk_cre_tskの戻値として、生成したタスクの識別子(タスクID)が返されます※5

タスクの起動 31行目、34行目のtk_sta_tsk

タスクの動作を開始します。第1引数は、tk_cre_tskで得られたタスクIDを指定します。タスクIDでT-Kernelに登録されたどのタスクを起動するかを指定します。

第2引数は、INT型の値であれば何を指定しても構いません。指定した値はタスク用関数の第1引数stacdに設定されますので、起動するタスクに情報を渡すことができます(サンプルでは使っていません)。

図 タスクの生成と起動

図 タスクの生成と起動

待ち状態に移行 36行目のtk_slp_tsk

tk_slp_tskはタスクを起床待ち状態にする機能です。起床待ちとは、他のタスクや割込みハンドラなどから起こしてもらうのを待っている状態です。ただし、本稿のサンプルでは起床してくれるタスクなどはありませんから、初期タスクはここで待ち状態になったままになります。

第1回 RTOS概論第3回 タスク間同期・通信機能1


※1 T-Kernel用のモニタ機能はT-Monitor(ティー・モニタ)と呼び、T-EngineリファレンスボートのフラッシュROMの中に予め格納されています。T-Monitorには、レジスタの表示やメモリのダンプ、ブレークポイントの設定、コンソール入出力の機能などが用意されています。サンプルプログラムにある tm_putstring は、コンソールに文字列を出力する機能です。T-Monitorの仕様については、トロンフォーラムが公開しているT-Monitor仕様書を参照してください。なお、T-Kernel 2.0では、モニタプログラムのソースコードも公開しています。(T-Kernel 2.0のソースコードに含まれています。)

※2 タスクを実行する順序は、タスクの優先度などによって決まります。このサンプルプログラムの場合は、タスクの優先度などを気にする必要はありませんが、複数のタスクを使う一般的なリアルタイムシステムであれば、タスクの優先度を調整する必要があります。

※3 while(1) による無限ループがあるのでこの行には到達しませんが、拡張していくと while を抜ける処理を記述するかもしれません。そのような場合に備えて、必ず tk_ext_tsk(); を記述してください。

※4 他のメンバ変数を使う場合は、対応する属性をtskatrに追加する必要があります。tskatrの指定が TA_HLNG|TA_RNG0 のみの場合は、他のメンバ変数は利用されないので設定する必要はありません。

※5 もし、何らかのエラーが発生した場合は、tk_cre_tskの戻値は負の値になります。T-Kernelでは、この負の値を「エラーコード」と呼び、エラーの内容をその値で確認することができます。

Return Top