目次

RTOS(リアルタイムOS)

Amazon FeeRTOS

Amazonのライセンス下(MITライセンス)になった. AWSに日本語のドキュメントがあるので要参照
FreeRTOS カーネルについて
The FreeRTOS™ Kernel
FreeRTOS の概要(自動翻訳 無保証)

STM32マイコンでFreeRTOSを用いてLEDを制御する(Lチカ)
FreeRTOSの使い方(PIC32MX版)
STM32/FreeRTOSでLua
STM32-P407でFreeRTOSを動かす
マイコン徹底入門:RTOS編
Lチカから始めよ/STM32ビルドツリーの作成2
PIC24F64GA002とFreeRTOS
ARM Cortex-M RTOS Context Switching

設定

FReeRTOSConfig.hでFreeRTOSの設定を編集可能.

configUSE_MUTEXES  # ミューテックス使うよ
configUSE_RECURSIVE_MUTEXES # 再帰的ミューテックス使うよ
configUSE_RATE_HZ # RTカーネルのタスクスケジューラが走る頻度,

configUSE_RATE_HZを大きくすればより早い応答ができると期待するがその分コンテキストスイッチが増えてオーバヘッドが大きくなりCPUの使用率が落ちてしまうので,ただ上げればいいというものではない.

コンテキストスイッチ

FPUを使用する場合,コンテキストスイッチの際に保存するレジスタが17ワードも追加で必要になる.
調べてると17だったり18だったりするがこれはレジスタへのアラインが4バイトか8バイトかの違いによる模様.
FPUを使う場合,FreeRTOSでではconfigUSE_TASK_FPU_SUPPORT設定をしておく必要がありそう.stm32CubeMXにはこの設定があったはず.
Cortex-M FPUも参照
Using the floating point unit (FPU) in interrupts

ヒープメモリの大きさ

configTOTAL_HEAP_SIZEでRTOSの管理するRAMの最大領域を設定する。スタック領域の総量がこのサイズを超えるとタスクの生成に失敗、スタックオーバーフローになる。 このためこの値は大きめに設定したい気持ちはあるけど、ここを大きくしすぎると今後はグローバル変数やOS管理外のローカル変数の領域が足りなくなってそれはそれでリンクエラーになるので注意。
動的メモリ確保をするとき、このHeap領域からメモリを使っていく。言い方を変えると静的メモリ確保しか使わないならここの領域は増やさなくてよい。

Newlibを使うときの注意

printfなどの標準Cライブラリを使うのであれば注意が必要, mallocを使ったメモリ周りでひと悶着あり.
Using FreeRTOS with newlib and newlib-nano
Implementing Malloc With FreeRTOS
FreeRTOSでmalloc(Newlib)を使おうとすると生じる問題にについては下記にまとめた.
CubeMXでFreeRTOSプロジェクト作った際のNewlibまわりに生じる問題

優先度の設定

stm32は優先度を主優先度と副優先度と分けることができるが、FreeRTOSの管理ではめんどくさいので全部主優先度にまとめておいたほうがよい。

Cortex-MコアでのRTOSについて

※これはBASEPRIレジスタを含むコア(Cortex-M3, M4, M4F, M7)にのみ適用される。Cortex-M0, M0+には適用されない。 

ARM Cortex-Mアーキテクチャは最大で8ビットの優先度ビットがある(2^8=256の優先度設定が可能。)。しかしメーカ、デバイスによって実装されてる割込み優先度はもっと少ない。
最大8ビットのうちいくつかの優先ビットが実装されている。 RTOSカーネルが起動する前にconfigMAX_SYSCALL_INTERRUPT_PRIORITYを使ってFreeRTOSのクリティカルセクションによりマスクされる優先度とそうでない優先度の境界を設定する。 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);が呼び出されていることを確認しておく。

Running the RTOS on a ARM Cortex-M Core

クリティカルセクション

taskENTER_CRITICAL()

FreeRTOSで管理してる割込みをすべて無効化し、クリティカルセクションに入る。configMAX_SYSCALL_INTERRUPT_PRIORITYで設定されたFreeRTOSよりも優先度の高い割り込みははこれに関係なく実行される.

taskEXIT_CRITICAL()

FreeRTOSの管理下にある割込みを有効化し、クリティカルセクションを抜ける。 クリティカルセクションのマクロでは、Cortex-MのBASEPRIレジスタを書き換えることで割込みを制御する。 BASEPRIに書き込まれた優先度以下(大きい数字)の割込みをマスク(割込み禁止)する。 0が書き込まれた場合、マスクは実行されない。taskEXIT_CRITICAL()はBASEPRIに0を書き込むマクロ

6. クリティカルセクション

バイナリセマフォを使った同期処理

タスクはセマフォ取得まち、割込みハンドラでセマフォをリリースすると、タスクはこのセマフォを取得して処理を行う。 終わったらタスクは再びセマフォの取得待ちになる。

TCB:タスクコントロールブロック、それぞれのタスクに存在する。タスクの各情報を管理するためのやつ。 osSemaphoreCreate()ではセマフォはGiveされた状態になっている。これはvSemaphoreCreateBinaryというFreeRTOSの古いAPIを使っているから。新しいAPIであるxSemaphoreCreateBinaryではそのようなことはない。
ODriveはセマフォを作った直後にosSemaphoreWaitをしてセマフォをTakeしてキューを空にしておく、これでブロッキング状態になる。つまりセマフォが開放されるまでその動作は実行されない.

CubeMXを用いてFreeRTOSを実装する.

CUbeMXやCudeIDEを使うと,FreeRTOSを初期化してコードを実装できる.実装はFreeRTOSだけど,CMSIS-RTOSでラッピングしてある. stm32でFreeRTOSを使う場合にはCMSIS-RTOSも参照
systickはRTOS用のタイムベースカウンタとして使用されるので,stm32のHALやLLのためのTimebase sourceには別途タイマを設定することが強く推奨されるので,適宜設定する.stm32はタイマの種類が多いので,機能が少ないものを設定しておけばいいでしょう.
MPU/FPUの設定を切り替えることができる部分があるが、これはARMv8-Mでしか現状使用されない?(CubeMX5.6.0時点) でもF4だと一応設定はできるようになっている。

タスクの利用量など計測

vTaskList

void vTaskList( signed char *pcWriteBuffer );

を使うことでタスクの状態を知ることが可能.
引数として渡すバッファ(pcWriteBuffer)の中にASCIIでタスクの状態を保存してくれる. 得られる情報は以下

引数として渡すバッファにはこのタスク情報全体の情報を保持できる大きさが必要.バッファの境界チェックは行われない.
タスク一つあたりに40バイトあればいいと書いてあるが,これはタスク名長がいくつの場合の数字なのかがちょっと不明. 
標準だとタスク名長は16になっているはず,これ以上長いタスク名をつけるとこの関数のではタスク名長までしか表示されない. これを解決するには,タスク名長を短くするか,タスク名長の最大値を長くする必要がある.タスク名長を長くするにはMAX_TASK_NAME_LENの数字を大きくする. しかしその場合は1タスク当たりに必要と思われるバッファの容量を多く見積もる必要がある. タスクの状態はアルファベットで示される.それぞれの状態は以下

この関数は実行中に割り込みを禁止するので頻繁に呼び出すはやめおこう.
スタック量は使用するマイコンによって異なるので改めて注意すること,32ビットマイコンなら1スタックはWORDなので4バイト.
FreeRTOSのタスクの動作状況を調べる

uxTaskGetStackHighWaterMark

UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );

渡したタスクの残りのスタック量を返す.タスクが実行されてから最も低いスタック量を返す.
この数字が少ないほどスタックオーバーフローに近い.
これもスタック値に注意する.32ビットマイコンなら戻り値(スタック)が1なら空き領域は4バイトである.
CubeMXで初期設定をするときはInclude paramtetersから有効にすることを忘れず.

FreeRTOS+CLI

FreeRTOS+CLI An Extensible Command Line Interface Framework
FreeRTOSにCLI環境を追加する.
CLI用のタスクが追加され,このタスクが文字列処理を行いCLI環境を実現.
必要な項目は以下の通り

という流れ.

コマンドの実行により生成された出力を保持するために用いるため,configCOMMAND_INT_MAX_OUTPUT_SIZEの定義を追加しておく.
FreeRTOSConfig.hにでも追加しておけばいいだろう.
関数FreeRTOS_CLIGetOutputBuffer()を使う場合に,上記のていぎが必要となる.
この関数を使わないのであれば,RAMの容量を節約するために1にしておく.

動作しているタスクの一覧を表示するコマンドにて,関数vTaskList()が実装されている.
この関数を呼び出すにはFreeRTOSにて以下の設定をゆうこうにする必要がある.
configUSE_TRACE_FACILITY
configUSE_STATS_FORMATTING_FUNCTIONS
FreeRTOSConfig.hに追記しておく.
CubeMX上であれば,「Config Parameters」より設定可能.

できたこと

UARTは実装できた.
次はUSBCDCでやり取りできるようにしておきたい.
## C++を使いたい

Defining task in C++ compiles but doesn…
Freertos-addons FreeRTOSの導入とTips
FreeRTOS-Cpp
Implementing an Asynchronous Dispatch Queue with FreeRTOS
FreeRTOScpp
FreeRTOS C++ integration
Deleting a FreeRTOS task from another task
C++ freeRTOS Task, invalid use of non-static member function
FreeRTOS creating a task within a C++ class

参考文献

FreeRTOSカーネル 開発者ガイド 開発者サポート
FreeRTOS Documentation PDF files
8.2.2. スタックオーバーフローのフック
FAQの前に