FreeRTOS概要


FreeRTOSを仕事で使う機会がありましたので、使用方法・OSの振る舞いの概要をここにまとめておこうかと思います。
コンフィグや各API、タスクの状態監視の説明は下記の別記事にて説明いたします。
- [コンフィグ設定](https://qiita.com/tom_S/items/a0ef540427cd6f2b4188)
- [タスク制御](https://qiita.com/tom_S/items/1efb419e969e392da944)
- [セマフォの使い方](https://qiita.com/tom_S/items/95d8bf5271875ddc8ae5)
- [messageBufferの使い方](https://qiita.com/tom_S/items/a8aca2f74c59b69a1a8b)
- [eventGroupの使い方](https://qiita.com/tom_S/items/6d6b7cb16fc869fe8e29)
- [タスク状態監視用APIの使い方](https://qiita.com/tom_S/items/39162815c5abb85b9092)
- [tagの使い方](https://qiita.com/tom_S/items/99d3da9a94c16632daa6)
- [タイマーの使い方](https://qiita.com/tom_S/items/4e720c5cd77778727601)

# FreeRTOS( https://www.freertos.org/ )とは

複数のマイクロコントローラに対応した、オープンソースのRTOS。各マイクロコントローラごとにサンプルが用意されているため、導入は難しくない。

## ライセンス
バージョン9までは例外条項付きGPLの下で配布されていた。 例外条項は、カーネルそのものがオープンソースである場合にはユーザのコードをクローズドソースにしておくことができるという内容である。Amazon.comに買収された後のバージョン10からはMITライセンスを採用している。
(wikipediaより引用)

# 用語

| 用語       |   意味 |
|--------------|------------------|
| アイドルタスク | アイドルタスクとは優先度が最小値で設定されている。<br>常時実行可能な状態のタスクのことを示す。<br>実行するタスクが無い場合、このタスクが動く。アイドルタスクはOSの処理で定義されている(コルーチンを使う場合は一部ユーザで手を入れる)。 |
| タスクトレース | 作成されたタスク情報を出力する機能。OSの設定方法によっては使用可能 |
| コルーチン | コルーチンはタスクと違い、スタックを共有する小さなタスクのことを示す。主に低スペックなCPUでのマルチタスク動作がしたい場合に用いる |


# タスクステート

タスクの状態に関して説明する。タスクは生成された時点ではreadyステートになり、4つのステートどれかに設定されている。以下のリンクを参照のこと

![タスク状態図](https://www.freertos.org/media/2018/tskstate.gif)

引用元：https://www.freertos.org/RTOS-task-states.html

## Running

実行状態であることを示す。現在実行されているタスクがRunningステートとなる

## Ready

実行可能状態であることを示す。現在実行されているタスクより優先度が低く、Blockedステート・SuspendedステートではないタスクがReadyステートとなる

## Blocked

別タスク・もしくは割込みからのOSのシステムコール(イベントフラグ・メッセージボックス・データキュー等)を待っている際になるステート

## Suspended

vTaskSuspend()を呼び出した際になるステート。Blockedステートとは厳密には違う状態として扱う
(ただし、ソースコードを見る限りではBlockedステートと同じ扱いをしている)

# スケジューリング

FreeRTOSのスケジューラは「FreeRTOSConfig.h」の「configUSE_PREEMPTION」の値を1と定義するとプリエンプティブになる。「configUSE_PREEMPTION」の値を0とした際は協調的スケジューリングとなる

## プリエンプティブスケジューリング

基本的なスケジューリングは、Itron系OS等と同等なスケジューリングを行う。ただし、同じ優先度のタスクにおいては「FreeRTOSConfig.h」の「configUSE_TIME_SLICING」の値を1にしていると、同じ優先度のタスク同士でタイムスライスを行い、交互にそれぞれのタスクが動く。また、タスクの切り替えのタイミングは以下の3つである

- OS用のタイマ割込み

  - タイマ割込みの頻度はFreeRTOSConfig.h内のconfigTICK_RATE_HZの値で調節可能。1秒間の間にconfigTICK_RATE_HZで指定した値の回数分だけが呼ばれる。ただし、内ではOSで使用するタイマのカウントも行うため、タスクを1ms刻みでwait,delayする際にはconfigTICK_RATE_HZの値を1000にしておく必要がある。(configTICK_RATE_HZの値は1000で固定を推奨)

- RunningステートのタスクがBlockedステートorSuspendedステートに切り替わった時
- OSのシステムコールにより、BlockedステートorSuspendedステートのタスクがreadyステートに切り替わった時


## 協調的スケジューリング

「configUSE_PREEMPTION」の値を0に設定し、「configUSE_TIME_SLICING」の値を1にすると、
全てのタスクが均等に実行される設定となる。

「configUSE_PREEMPTION」の値を0に設定し、「configUSE_TIME_SLICING」の値を0にすると、
優先度低のタスクであろうと、実行中であれば、他のタスクへスイッチしなくなる。Delayなどで自身のタスクを待ち状態にしないといけなくなるので注意。


# コルーチン

- タスクとは異なる、複数の関数(コルーチン)を平行して実行させる仕組み。メモリの制約上、タスクを大量に作ることが困難な場合など、小規模なシステムで使用されることを想定している

- タスクとコルーチンではタスクの方が優先され、アイドルタスクが実行されるタイミングでコルーチンは動作する

- コルーチンも、ステートと優先度が存在し、優先度が高く実行可能な状態(Ready状態)のコルーチンから実行される(Running状態となる)

![引用元：https://www.freertos.org/media/2018/crstate.gif](https://www.freertos.org/media/2018/crstate.gif)
引用元：https://www.freertos.org/media/2018/crstate.gif

## タスクとの共存方法

アイドルタスク(vApplicationIdleHook())内でコルーチンを作動させるための関数「vCoRoutineSchedule()」を呼び出すことでタスクと共存させて、動作させる。


# FreeRTOSのコード例

一つ以上のタスクを生成し、「vTaskStartScheduler()」を呼び出すことによりOSのスケジューリングが開始される。

以下にFreeRTOSを使用した際のmain.cのコード例を示す。以下の例では優先度2、スタックサイズ1024のタスク(mainTask)を作成し、動作させている

コード例:

```c
/* FreeRTOS用モジュール */
#include "FreeRTOS.h"
#include "task.h"

#define THREAD_NAME  "THREAD1"
#define THREAD_PRIORITY  (2)
#define SAMPLE_STACKSIZE  (1024)

TaskHandle_t task1;
static int task_delay = 1000;
static void mainTask( void *pvParameters );

int main()
{
  if (pdTRUE != xTaskCreate(mainTask, THREAD_NAME, SAMPLE_STACKSIZE, &task_delay, THREAD_PRIORITY, &task1))
  {
    return;
  }

  /* RTOSの動作開始。中で無限ループしている。エラーがかかった場合のみリターンされる */
  vTaskStartScheduler();

  while(1);
}

static void mainTask( void *pvParameters )
{
  const TickType_t xTicksToDelay = 1000 / portTICK_PERIOD_MS;

  while(1) {
      vTaskDelay( xTicksToDelay );
  }
}
```