FreeRTOS + ESP32  〜チュートリアル①FreeRTOSの基礎知識〜

# FreeRTOSとは
>FreeRTOS は、マイクロコントローラーおよび小型マイクロプロセッサ向けの市場をリードするリアルタイムオペレーティングシステム (RTOS) です。
MIT オープンソースライセンスで無料配布される FreeRTOS には、すべての業種での使用に適したカーネルと増え続けるライブラリのセットが含まれています。FreeRTOSは、信頼性と使いやすさを重視して構築されています。
FreeRTOS には、接続、セキュリティ、無線による更新 (OTA) 用のライブラリが含まれています。

FreeRTOSには、FreeRTOSの機能を表示するデモアプリケーションも含まれています認定されたボード。


## FreeRTOS バージョニング

FreeRTOS カーネルとコンポーネントは、個別にリリースされ、セマンティックバージョニングを使用します。統合 FreeRTOS リリースが定期的に行われます。すべてのリリースでは、YYYYMM.NN 形式の日付ベースのバージョニングを使用します。

Y は年を表します。

M は月を表します。

N は、指定された月内のリリース順を表します (00 が最初のリリースです)。

たとえば、2021 年 6 月の 2 番目のリリースは 202106.01 になります。

以前は、FreeRTOS リリースでは、メジャーリリースでセマンティックバージョニングを使用していました。日付ベースのバージョニング (FreeRTOS 1.4.8 は FreeRTOS に更新AWSReference Integration 201906.00) と同様に、FreeRTOS カーネルと個々の FreeRTOS ライブラリは引き続きセマンティックバージョニングを使用します。セマンティックバージョニングでは、バージョン番号自体 (X.Y.Z) でメジャーリリース、マイナーリリース、またはポイントリリースの区別を示します。セマンティックバージョンのライブラリを使用して、アプリケーションの新しいリリースの範囲と影響を評価できます。



## FreeRTOS アーキテクチャ

FreeRTOS は通常、デバイスのアプリケーションに必要なすべてのコンポーネントを含む、単一のコンパイル済みイメージとしてデバイスにフラッシュされます。このイメージは、組み込み開発者が作成したアプリケーション、Amazon が提供するソフトウェアライブラリ、FreeRTOS カーネル、およびハードウェアプラットフォーム用のドライバーとボードサポートパッケージ (BSP) の機能を組み合わせたものです。使用されている個々のマイクロコントローラーとは別に、組み込みアプリケーション開発者は、FreeRTOS カーネルおよびすべての FreeRTOS ソフトウェアライブラリと同じ標準化されたインターフェイスを期待できます。

![FreeRTOS architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/904294/0c91d37a-2042-f458-4b56-f68d856b7a9a.png)

## FreeRTOS 認定済みハードウェアプラットフォーム

[Espressif ESP32-DevKitC](https://devices.amazonaws.com/detail/a3G0L00000AANtjUAH/ESP32-DevKitC)

[Espressif ESP-WROVER-KIT](https://devices.amazonaws.com/detail/a3G0L00000AANtlUAH/ESP-WROVER-KIT)

## 開発ワークフロー

開発を開始するには、FreeRTOS をダウンロードします。パッケージを解凍し、IDE にインポートします。その後、選択したハードウェアプラットフォームでアプリケーションを開発し、デバイスに適した開発プロセスを使用してこれらのデバイスを製造およびデプロイすることができます。デプロイされたデバイスは、完全な IoT ソリューションの一部として AWS IoT サービスまたは AWS IoT Greengrass に接続できます。

![afr-getting-started-workflow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/904294/edbf2798-132f-76f5-86c0-dcdfdc12f5f1.png)


## 参考資料
[FreeRTOS はオープンソースプロジェクト](https://github.com/aws/amazon-freertos)

# FreeRTOS カーネルの基礎

FreeRTOS カーネルは、多くのアーキテクチャをサポートするリアルタイムのオペレーティングシステムです。組み込みマイクロコントローラアプリケーションの構築に最適です。次の機能があります。
マルチタスクスケジューラ。

複数のメモリ割り当てオプション (完全に静的に割り当てられたシステムを作成する機能を含む)。

タスク通知、メッセージキュー、複数タイプのセマフォ、ストリームおよびメッセージバッファを含むタスク間調整のプリミティブ。

FreeRTOS カーネルは、クリティカルなセクションや割り込みの中でリンクされたリストを処理するなど、非決定的なオペレーションは実行しません。FreeRTOS カーネルには、タイマーが処理を必要としない限り CPU 時間を使用しない効率的なソフトウェアタイマーが実装されています。ブロックされたタスクは、時間を消費する定期的な処理を必要としません。タスクへのダイレクト通知により、実質的に RAM オーバーヘッドが無くなり、タスクシグナリングが高速になります。これらの機能は、ほとんどのタスク間、および割り込みとタスク間でのシグナリングのシナリオで使用できます。

FreeRTOS カーネルは、小さく、シンプルで使いやすく設計されています。一般的な RTOS カーネルバイナリイメージは、4000〜9000 バイトの範囲です。

## FreeRTOS カーネルスケジューラ

RTOS を使用する組み込みアプリケーションは、独立したタスクのセットとして構成できます。各タスクは、他のタスクに依存することなく、独自のコンテキスト内で実行されます。どの時点においても、アプリケーション内の 1 つのタスクだけが実行されます。リアルタイム RTOS スケジューラは、各タスクの実行時期を決定します。各タスクには独自のスタックが用意されています。他のタスクを実行できるようにタスクをスワップすると、そのタスクの実行コンテキストがタスクスタックに保存されるため、後で同じタスクをスワップバックして実行を再開すると復元できます。

決定的なリアルタイム動作を提供するために、FreeRTOS タスクスケジューラは、タスクに厳密な優先順位を割り当てます。RTOS は、実行可能な最優先タスクに確実に処理時間が与えられるようにします。これは、同時に実行する準備ができている場合に、等しい優先順位のタスク間で処理時間を共有することを意味します。FreeRTOS は、実行準備が整っているタスクが他にない場合にのみ実行されるアイドルタスクも作成します。

## メモリ管理

このセクションでは、カーネルのメモリ割り当てとアプリケーションのメモリ管理について説明します。

### カーネルメモリの割り当て

カーネルメモリの割り当て
RTOS カーネルは、タスク、キュー、または他の RTOS オブジェクトが作成されるたびに RAM を必要とします。RAM は以下のように割り当てることができます。

・コンパイル時に静的に

・RTOS API オブジェクト作成関数によって RTOS ヒープから動的に

RTOS オブジェクトを動的に作成する場合、標準の C ライブラリ malloc() と free() 関数を使用することは、次の理由から必ずしも適切ではありません。

・組み込みシステムでは使用できない可能性があります。

・貴重なコードスペースを占有します。

・通常はスレッドセーフではありません。

・決定的ではありません。

## アプリケーションメモリ管理

アプリケーションがメモリを必要とする場合、FreeRTOS ヒープからメモリを割り当てることができます。FreeRTOS には、複雑さと機能に幅があるいくつかのヒープ管理スキームがあります。独自のヒープ実装を提供することもできます。

FreeRTOS カーネルには、次の 5 つのヒープ実装が含まれています。

`heap_1`
最も簡単な実装です。メモリを解放することはできません。

`heap2`
メモリを解放することはできますが、フリーブロックに隣接するメモリを結合することはできません。

`heap3`
スレッドの安全性のために標準の malloc() と free() をラップします。

`heap4`
断片化を避けるために、隣接するフリーブロックを結合します。絶対アドレス配置オプションを含みます。

`heap5`
これは heap_4 に似ています。ヒープは複数の隣接していないメモリ領域にまたがることができます。

## タスク間の調整

このセクションには、FreeRTOS プリミティブについての情報が含まれています。

**Queues**

キューは、タスク間通信の主要な形式です。タスク間や、割り込みとタスク間でメッセージを送信するために使用できます。ほとんどの場合、スレッドセーフな先入れ先出し (FIFO) バッファとして使用され、新しいデータがキューの後ろに送られます。(データはキューの先頭に送ることもできます) メッセージはコピーでキューに送られます。つまり、データへの参照を単に格納するのではなく、データ (より大きなバッファへのポインタでも可能) 自体がキューにコピーされます。

キュー API は、ブロック時間を指定することを許可します。タスクが空のキューからの読み取りを試行すると、タスクは、データがキューで使用可能になるか、ブロック時間が経過するまでブロック状態になります。ブロック状態のタスクは CPU 時間を消費せずに他のタスクを実行できます。同様に、タスクがフルキューに書き込もうとすると、タスクはキュー内のスペースが使用可能になるかブロック時間が経過するまでブロック状態になります。複数のタスクが同じキューでブロックされている場合は、優先度の最も高いタスクが最初にブロック解除されます。

タスクへのダイレクト通知やストリーム、メッセージバッファなどの他の FreeRTOS プリミティブは、多くの一般的な設計シナリオでキューに対する軽量の代替手段を提供します。

**セマフォとミューテックス**

FreeRTOS カーネルは、相互排除と同期のためにバイナリセマフォ、カウントセマフォ、およびミューテックスを提供します。

バイナリセマフォは 2 つの値しか持てません。これらは、(タスク間またはタスクと割り込みの間の) 同期の実装に適しています。カウンティングセマフォは、2 つ以上の値を持てます。これにより、多くのタスクがリソースを共有したり、より複雑な同期操作を実行できます。

ミューテックスは、優先度継承メカニズムを含むバイナリセマフォです。つまり、現在優先度の低いタスクが保持しているミューテックスを取得しようとしている際に優先度の高いタスクがブロックした場合、トークンを保持しているタスクの優先度を一時的にブロックタスクの優先度に上げます。このメカニズムは、発生した優先度逆転を最小限に抑えるために、より高い優先度のタスクのブロックされた状態ができるだけ短時間になるよう設計されています。

**直接タスク通知**

タスク通知により、セマフォのような別個の通信オブジェクトを必要とせずに、タスクは他のタスクとやり取りし、割り込みサービスルーチン (ISR) と同期することができます。各 RTOS タスクには、通知に内容があればそれを格納するために使用される 32 ビットの通知値があります。RTOS タスク通知は、受信タスクのブロックを解除し、オプションで受信タスクの通知値を更新することができるタスクに直接送信されるイベントです。

RTOS タスク通知は、バイナリとカウンティングセマフォ、場合によってはキューの代わりに、より高速で軽量の代替として使用できます。タスク通知は、同等の機能を実行できる他の FreeRTOS 機能よりも、スピードおよび RAM フットプリントの両方で利点があります。ただし、タスク通知は、イベントの受信側になることができるタスクが 1 つしかない場合にのみ使用できます。

**ストリームバッファ**

ストリームバッファは、バイトのストリームを割り込みサービスルーチンからタスクに、またはあるタスクから別のタスクに渡すことができます。バイトストリームは任意の長さにすることができ、必ずしも先頭または末尾を必要としません。任意の数のバイトを一度に書き込み、および読み取りすることができます。プロジェクトに stream_buffer.c ソースファイルを含めることで、ストリームバッファ機能を有効にします。

ストリームバッファは、バッファ (ライター) に書き込むタスクまたは割り込みが 1 つだけであり、バッファ (リーダー) から読み取るタスクまたは割り込みが 1 つしかないことを前提としています。ライターとリーダーが異なるタスクになることやサービスルーチンを中断することは安全と言えますが、複数のライターやリーダーがあるのは安全とは言えません。

ストリームバッファの実装では、タスクへのダイレクト通知が使用されます。したがって、呼び出し元のタスクをブロックされた状態に配置するストリームバッファ API を呼び出すと、呼び出し元のタスクの通知状態と値が変更される可能性があります。

**データの送信**

`xStreamBufferSend()`は、タスク内のストリームバッファにデータを送信するために使用されます。`xStreamBufferSendFromISR()`は、割り込みサービスルーチン (ISR) 内のストリームバッファにデータを送信するために使用されます。

`xStreamBufferSend()` で、ブロック時間の指定が行えます。`xStreamBufferSend()` が呼び出され、ストリームバッファへの書き込みブロック時間が 0 以外になっている場合、バッファがいっぱいであると、メッセージバッファ領域が使用可能になるか、またはブロック時間が切れるまで、タスクはブロック状態になります。

`sbSEND_COMPLETED()` および `sbSEND_COMPLETED_FROM_ISR()`は、データがストリームバッファに書き込まれたときに (FreeRTOS API によって内部的に) 呼び出されるマクロです。更新されたストリームバッファのハンドルが必要です。これらのマクロはどちらも、データ待ちのストリームバッファにブロックされているタスクがあるかどうかを確認し、そのようなタスクが存在する場合はブロック状態からタスクを削除します。

このデフォルトの動作は、FreeRTOSConfig.h に `sbSEND_COMPLETED()` の独自の実装を提供することで変更できます。これは、ストリームバッファを使用してマルチコアプロセッサ上のコア間でデータを渡す場合に便利です。このシナリオでは、他の CPU コアに割り込みを生成するために `sbSEND_COMPLETED()` を実装することができ、割り込みのサービスルーチンは `xStreamBufferSendCompletedFromISR()` API を使用してデータを待機しているタスクをチェックし、必要に応じてブロックを解除します。


**データの受信**

`xMessageBufferReceive()`は、タスク内のメッセージバッファからデータを読み取るために使用されます。`xMessageBufferReceiveFromISR()`は、割り込みサービスルーチン (ISR) 内のメッセージバッファからデータを読み取るために使用されます。`xMessageBufferReceive() `で、ブロック時間の指定が行えます。メッセージバッファから読みだすブロック時間が 0 以外で `xMessageBufferReceive()` が呼び出され、かつバッファが空の場合、データが使用可能になるか、またはブロック時間が切れるまで、タスクはブロックされた状態になります。

`sbRECEIVE_COMPLETED()` および `sbRECEIVE_COMPLETED_FROM_ISR()` は、ストリームバッファからデータを読み込むときに (FreeRTOS API によって内部的に) 呼び出されるマクロです。マクロは、ストリームバッファに領域が使用可能になるまで待機しているブロックされたタスクがあるかどうかを確認し、そのようなタスクがあれば、ブロック状態から削除します。`sbRECEIVE_COMPLETED()` のデフォルトの動作は、FreeRTOSConfig.h に代替の実装を提供することで変更できます。

##ソフトウェアタイマー

ソフトウェアタイマーは、設定された時間に機能が実行されるようにします。タイマーによって実行される関数は、タイマーのコールバック関数と呼ばれます。タイマーが開始されてからコールバック関数が実行されるまでの時間をタイマーの周期と呼びます。FreeRTOS カーネルは以下のように、効率的なソフトウェアタイマー実装を提供します。

・割り込みコンテキストからはタイマーコールバック関数を実行しません。

・タイマーが実際に切れない限り、処理時間は消費されません。

・ティック割り込みに処理オーバーヘッドを追加することはありません。

・割り込みを無効にしている間は、リンクリストの構造を処理しません。

##低電力サポート

ほとんどの組込みオペレーティングシステムと同様に、FreeRTOS カーネルは、時間を測定するために使用する、周期的なティック割り込みを生成するためにハードウェアタイマーを使用します。通常のハードウェアタイマー実装は、ティック割り込みを処理するために低電力状態を定期的に終了し、再び低電力状態にする必要があるため、省電力性に限りがあります。ティック割り込みの周期が早すぎる場合、ティックごとの低電力状態の開始/終了時に電力と時間が消費されるため、最低レベルの省電力モードを除くすべての省電力モードで、上限ゲインを上回ることなります。

この制限に対処するために、FreeRTOS には低電力アプリケーション用のティックレスタイマーモードがあります。FreeRTOS のティックレスアイドルモードは、アイドル期間 (実行可能なアプリケーションタスクがない期間) に周期ティック割り込みを停止し、ティック割り込みが再開されたときに RTOS ティックカウント値を修正します。ティック割り込みを停止すると、割り込みが発生するか、RTOS カーネルがタスクを準備完了状態に移行するまで、マイクロコントローラはディープレベルの省電力状態になります。

##カーネル設定

`FreeRTOSConfig.h `ヘッダーファイルを使用して、特定のボードおよびアプリケーション用に FreeRTOS カーネルを設定できます。カーネル上に構築されるすべてのアプリケーションは、`FreeRTOSConfig.h`ヘッダーファイルをプリプロセッサのインクルードパスに格納します。`FreeRTOSConfig.h`は、アプリケーション固有であり、FreeRTOS カーネルのいずれかのソースコードディレクトリにではなく、アプリケーションディレクトリに配置する必要があります。

-`FreeRTOSConfig.hFreeRTOS デモおよびテストアプリケーション用のファイルは、freertos/vendors/vendor/boards/board/aws_demos/config_files/FreeRTOSConfig.h`および`freertos/vendors/vendor/boards/board/aws_tests/config_files/FreeRTOSConfig.h`。

`FreeRTOSConfig.h` に指定できる設定パラメータのリストについては、[FreeRTOS.org](https://www.freertos.org/a00110.html) を参照してください。

# FreeRTOS コンソール

FreeRTOS コンソールを使用して、マイクロコントローラーベースのデバイス用のアプリケーションを作成するために必要なものがすべて含まれたパッケージの設定およびダウンロードができます。

・FreeRTOS カーネル。

・FreeRTOS ライブラリです。

・プラットフォームサポートライブラリ。

・ハードウェアドライバー。

事前定義された設定でパッケージをダウンロードするか、またはアプリケーションに必要なハードウェアプラットフォームとライブラリを選択して、独自の設定を作成できます。これらの設定は AWS に保存され、いつでもダウンロードできます。



## クイック接続ワークフロー

FreeRTOS コンソールには、設定が事前定義されているすべてのボード用のクイックConnect ワークフローオプションも含まれます。クイックConnect ワークフローは、FreeRTOS デモアプリケーションを設定して実行するのに役立ちます。AWS IoTおよびAWS IoT Greengrass。開始するには、[事前定義された設定] タブを選択し、ボードを検索して [クイック接続] を選択し、クイック接続ワークフローのステップに従います。