2017年4月15日土曜日

FreeRTOS入門(1)

FreeRTOS入門(1)

RTOSって何?

身近なOSであるWindowsやMACのデスクトップを見てください。CPUは1つなのに複数のアプリが同時に動いていますよね。
これがOSの役割でマルチタスクという機能です。

 昔のWindowsなら何か1つ固まると全体がフリーズして何も操作できなくなる事態がありましたが、RTOSだとフリーズしません。
こんな事を書くと
今あるすべてのOSはRTOSであるべき

と思ってしまいますが、そうでもないんです。
そのあたりの詳しい話は後の方で説明します。

 この記事を見る方はマイコンで利用を想定していると思いますので、RTOSの定義について少し触れたいと思います。
そもそもマイコンOSとWindowsOSを比較してもマイコンにはUIが無いし、スケール感が異なるのでイメージが結びつきません。

そこで、
  • デスクトップ=マイコンボード
  • アプリ=マイコン
  • 機能=タスク
というように言葉を定義すると、

マイコンボード上に様々なICやCPUが乗っていて、それらはいろんな機能が入っている。

こう考えれば、マイコンOSの実態が見えてきてイメージしやすくなります。

マルチタスクの種類について

最初の方でもう少し掘り下げて説明しときます。
マルチタスクには
  • プリエンティブ
  • ノンプリエンティブ
という2つの種類があります。

プリエンティブとは、ハードウェアタイマーを使ってマルチタスクを行う方法で、
ノンプリエンティブとは、タスク内部で明示的にタスク切り替えタイミングを指示してマルチタスクを行う方式です。

両方ともメリットデメリットがあります。
プリエンティブだとタイマー周期に依存して処理を切り替える

 メリット

  • 確実に同じ周期で処理が開始される

 デメリット

  • 本気でリアルタイム処理したいものが処理できない
  • タスク別にPC・レジスタ退避など行うので処理コストがかかる。

ノンプリエンティブだとタスク切り替えはタスク依存なので

 デメリット

  • タスク毎に均等な処理時間が回せない
  • 本気でリアルタイム処理したいものに処理時間が渡せる

 メリット

  •  スケジューラは非常にシンプル

相反する関係になっています。
もちろんRTOSでどちらを使うか選べるので、システムに合わせて選びましょう。

タスクの定義

RTOSでタスクを作るといってもどの程度の粒度が最適なのか人それぞれ見方が変わってきます。何かルールがあればそれに沿って従うまでなんですが、何もない時は単機能だけに絞っておくとよいです。
単機能の例
  •  タスク1=500ms周期でLチカさせる
  •  タスク2=シリアル通信する
  •  タスク3=LCD制御する
     ・・・
このように粒度が単機能に絞ってあると、他のプロジェクトで似たような処理があったらコピペできるので生産性はUPします。

もちろんOS無しの場合も移植できますが、タスクの粒度のように均一でないケースがほとんどです。

コピペしようにも他のいらない処理が入っていたり、、
1処理で完結しないで他の処理に依存していて芋づる式になっていたり、、

素直にコピペで動くようなものが少ないと思えます。

タスクの書き方

ここではOS無しとRTOSを使った場合を比較しつつ実装例を書きます。

タスクの粒度は両社どちらも同じものだとします。

OS無しの場合

タスクの中をswitch-case文で軽い処理単位に分割(いわゆるシーケンス処理)
 それをメインループでタスクを順番に処理する。
 これがノンプリエンティブ型です。
 プログラム内部で1処理行ったら抜けて次の処理へと渡していきます。
 処理コストは関数コールとSwitch~Case部分になります。

コード例:
void main() {
    init();

    for( ; ; ) {
        task1();
        task2();
        task3();
    }
}

RTOSを使う場合

タスク単位に何も気にせずそのままコードを書ける。
 これがプリエンティブ型です。
 タスクの切り替えはハードウェアタイマーの割込み処理で行います。
 もちろん切り替える際は、タスク毎にレジスタ、プログラムカウンタなど回避するのでその分コストはかかっています。

コード例:

void main() {
    xTaskCreate(task1, "task1", 128, NULL, 1, NULL);
    xTaskCreate(task2, "task2", 128, NULL, 1, NULL);
    xTaskCreate(task3, "task3", 128, NULL, 1, NULL);

    vTaskStartScheduler();
    for( ; ; ) ;

見慣れないものはFreeRTOSのAPIです。
タスクを作る。スケジューラを動かすの2つをやっています。


ちなみに国産OSのTRONと呼ばれるものも基本同じ作りです。ほかに独自の機能が備わってたりして便利だったり複雑だったり好みが出てくる部分ですね。

TronOSはがんばってほしいけど、1000円くらいのボードで気軽に試せる環境がないのでホビーユーザ数が増える事はないですね。。せめてArduinoスケッチでライブラリも実行できるところまで来たら触れるのにもったいないです。

コメントを投稿

Androider