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);
が呼び出されていることを確認しておく。
クリティカルセクション
taskENTER_CRITICAL()
FreeRTOSで管理してる割込みをすべて無効化し、クリティカルセクションに入る。configMAX_SYSCALL_INTERRUPT_PRIORITY
で設定されたFreeRTOSよりも優先度の高い割り込みははこれに関係なく実行される.
taskEXIT_CRITICAL()
FreeRTOSの管理下にある割込みを有効化し、クリティカルセクションを抜ける。
クリティカルセクションのマクロでは、Cortex-MのBASEPRIレジスタを書き換えることで割込みを制御する。
BASEPRIに書き込まれた優先度以下(大きい数字)の割込みをマスク(割込み禁止)する。
0が書き込まれた場合、マスクは実行されない。taskEXIT_CRITICAL()
はBASEPRIに0を書き込むマクロ
バイナリセマフォを使った同期処理
タスクはセマフォ取得まち、割込みハンドラでセマフォをリリースすると、タスクはこのセマフォを取得して処理を行う。 終わったらタスクは再びセマフォの取得待ちになる。
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だと一応設定はできるようになっている。
タスクの利用量など計測
void vTaskList( signed char *pcWriteBuffer );
を使うことでタスクの状態を知ることが可能.
引数として渡すバッファ(pcWriteBuffer
)の中にASCIIでタスクの状態を保存してくれる.
得られる情報は以下
- タスク名
- タスクの状態
- タスクの優先度
- 呼び出し時のタスクのスタック量
- タスク番号
引数として渡すバッファにはこのタスク情報全体の情報を保持できる大きさが必要.バッファの境界チェックは行われない.
タスク一つあたりに40バイトあればいいと書いてあるが,これはタスク名長がいくつの場合の数字なのかがちょっと不明.
標準だとタスク名長は16になっているはず,これ以上長いタスク名をつけるとこの関数のではタスク名長までしか表示されない.
これを解決するには,タスク名長を短くするか,タスク名長の最大値を長くする必要がある.タスク名長を長くするにはMAX_TASK_NAME_LEN
の数字を大きくする.
しかしその場合は1タスク当たりに必要と思われるバッファの容量を多く見積もる必要がある.
タスクの状態はアルファベットで示される.それぞれの状態は以下
- X:Run(実行中)
vTaskList
を呼び出したタスク - R:Ready(準備完了)
- B:Blocked(ブロック)
- S:Suspended(停止)
- D:Deleted(削除済み)
この関数は実行中に割り込みを禁止するので頻繁に呼び出すはやめおこう.
スタック量は使用するマイコンによって異なるので改めて注意すること,32ビットマイコンなら1スタックはWORDなので4バイト.
FreeRTOSのタスクの動作状況を調べる
uxTaskGetStackHighWaterMark
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
渡したタスクの残りのスタック量を返す.タスクが実行されてから最も低いスタック量を返す.
この数字が少ないほどスタックオーバーフローに近い.
これもスタック値に注意する.32ビットマイコンなら戻り値(スタック)が1なら空き領域は4バイトである.
CubeMXで初期設定をするときはInclude paramtetersから有効にすることを忘れず.
トレース
タスクの切り替わりタイミングの測定など。configUSE_APPLICATION_TASK_TAG
を定義しておく。 コレを定義することでタスクコントロールブロック内部にタグという属性を持たせることができる。これはタスクにおける特定の値を割り当てることが可能となる。このタグと言う値をGPIOやDACの出力に使うことでコンテキストスイッチングによるタスクの切り替わりをRTOSのTickよりも細かい単位で計測が可能となる。
traceTASK_SWITCHED_IN()
がタスクの切り替わり時に呼ばれる関数のdefineとなる。このdefineをタスクの値を使用してDACやGPIOの値を変化させてオシロスコープで引っ掛けることが可能となる。
/* First task sets its tag value to 1. */ void vTask1( void *pvParameters ) { /* This task is going to be represented by a voltage scale of 1. */ vTaskSetApplicationTaskTag( NULL, ( void * ) 1 ); for( ;; ) { /* Task code goes here. */ } } /*************************************************/ /* Second task sets its tag value to 2. */ void vTask2( void *pvParameters ) { /* This task is going to be represented by a voltage scale of 2. */ vTaskSetApplicationTaskTag( NULL, ( void * ) 2 ); for( ;; ) { /* Task code goes here. */ } } /*************************************************/ /* Define the traceTASK_SWITCHED_IN() macro to output the voltage associated with the task being selected to run on port 0. */ #define traceTASK_SWITCHED_IN() vSetAnalogueOutput( 0, (int)pxCurrentTCB->pxTaskTag )
FreeRTOS+CLI
FreeRTOS+CLI
An Extensible Command Line Interface Framework
FreeRTOSにCLI環境を追加する.
CLI用のタスクが追加され,このタスクが文字列処理を行いCLI環境を実現.
必要な項目は以下の通り
- FreeRTOS+CLIに必要なFreeRTOSでの設定を追加
- API関数を用いてコマンドを登録
- 入出力の関数を統合
という流れ.
コマンドの実行により生成された出力を保持するために用いるため,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