FreeRTOS【STM32学習向け】
マイコン向けにさまざまなRTOSがありますが当サイトではSTM32マイコンの学習用にFreeRTOSを使用します。最新のAMAZON系のものではなく従来タイプを使用しています。学習用ですのでできるだけシンプルなものから始めるのがよいと考えます。
FreeRTOSとは
FreeRTOSはオープンソースとして提供されており、無償で商用アプリケーションに使用することができるマイクロコントローラーおよび小型マイクロプロセッサ向けのリアルタイムオペレーティングシステム (RTOS) です。現状ではAmazon社が維持管理しています。
FreeRTOSはフリーで使用できるのですが、RTOSとして要求される基本機能はそろっており、必要最低限に絞って使用し、コードサイズを小さくすることもできます。
当サイトではFreeRTOS機能のうちタスクの管理(優先度設定、実行頻度設定、タスク切換え)、キュー(待ち行列)を使ったアプリケーションを解説したいとおもいます。(タスク間通信のバイナリセマフォ、カウンティングセマフォ、ミューテックスについてはとりあげていません)
FreeRTOSを使うための準備、設定(マイコンに対するもの、初めだけ)
FreeRTOSに必要な要素は「Source」フォルダ以下にすべて含まれています。「Source」フォルダをプロジェクト内にコピーし、アプリケーションのプロジェクトの設定でこのフォルダおよびこれに属するサブフォルダすべてのパスを通しておきます。
FreeRTOSにおける最近の事情:
STM32マイコンの最新開発環境であるSTM32CubeIDEでは自動生成ツールSTM32CubeMXの流れでFreeRTOSも手順に従うと自動的に組み込むことができます。
ところが、自動生成されたコードはペリフェラルドライバがHALになり抽象化されたようにRTOSコードも抽象化されたCMSIS(ARM Cortex規格)のAPI(Application Programming Interface)がベースのものになっており従来のFreeRTOSとは似ても似つかないものになっています。
RTOSに慣れないうちはこの新しいものをあえて使う必要はなく、情報も豊富な従来通りのFreeRTOSで理解を深めることがいいように思われます。
FreeRTOSを使ったタスク管理の仕組み
早速FreeRTOSを採用したプログラムの構成について見ていきましょう。
タスク管理を行うRTOSの中核部分をカーネルといいます。
アプリケーションプログラムにおいて処理Aと処理Bをそれぞれのタスクに登録してカーネルを起動(タスクスケジューラスタート)して並列処理(マルチタスク)させる例です。
FreeRTOSを使用する場合はまず使用するタスクを登録します。処理Aと処理Bはタスク関数(TaskAとTaskB)として登録し、それぞれの関数のなかにある無限ループwhile(1)内に記述します。この例では処理AをTaskA関数内に、処理BをTaskB関数内に記述します。
それぞれの処理は無限ループ内にありますが、RTOSカーネルがCPUの状態を退避させたり復元したりしてタスクを切り替えます。この切替処理をコンテキストスイッチといいます。
タスクを登録するためにはxTaskCreate関数を使用します。
タスク登録 xTaskCreate関数実行例:
xTaskCreate(TaskA, (signed portCHAR *)”TaskA”, 192, NULL,1,NULL);
関数の第1引数はタスク関数名、第2引数はデバッグ用タスク名とありますが例のようにタスク名でいいと思います。第3引数はタスクのデータを格納するスタックの大きさ、第4引数はタスクに渡すパラメータへのポインタ、第5引数は優先順位、そして第6引数はタスク管理に使用するハンドラです。
引数の定義として説明するのに言葉で表すとわかりにくいので例をあげて説明します。
これら引数について具体例で後に説明しますが基本設定ヘッダファイルFreeRTOSConfig.hで設定するパラメータと関連するものもあります。
第3引数はタスクで使用するデータを保管するスタック容量でオーバーフローが起きない程度は確保しておく必要があります。ワード単位で指定し、最小奨励スタック領域は128ワード(512バイト)で標準的に192ワード(768バイト)としておけば大抵は安定しています。ただ、スタック容量は大きい方が安定して安心なのですが、タスク数が増える場合はマイコンのRAM容量を超えないようにしなければいけません。実際にプログラムを動かしながら加減するようにします。
第4,5,6引数は後に実例で解説します。
タスクを登録したあとはvTaskStartScheduler関数を実行するとRTOSのカーネルが起動(スケジューラ起動)します。
タスク登録 vTaskStartScheduler関数実行例: xTaskStartScheduler();
main関数の最後には無限ループwhile(1)を挿入しておきます。必要あればこの無限ループ内にエラー処理などを記述しておきます。カーネルが起動し、タスクが実行されると、あらかじめ設定した切り替える期間(タイムスライス)で自動的にタスクは切り替わり(コンテキストスイッチ)交互に実行されます。
FreeRTOSタスク管理の基本的な構成は図に示したものをこれまで解説してきたとおりです。実際のアプリケーションにおいてタスク優先順位、タスク実行頻度を設定したり、タスクの有効、無効を切り替えたりできるようになれば、より複雑で多機能なシステムを容易で柔軟に実現できるようになります。
FreeRTOSを使うための初期設定:FreeRTOSConfig.h
初期設定はヘッダファイルFreeRTOSConfig.hでパラメータの指定を行います。使用する機能の有無も指定できますので必要な機能だけに絞った設定でサイズを小さくすることができます。この設定ファイルは「Source」フォルダ直下に置いておきます。この中で特に重要なパラメータについて解説していきます。
このファイルの冒頭部分で割り込みハンドラの名称の変更定義を追加していますがこれはFreeRTOSで使用するハンドラ名称とARM Cortex-M3で使用するハンドラ名称が異なるからです。STM32で使われる標準名称に修正しています。
教材ボードではクロックは72MHzですのでconfigCPU_CLOCK_HZは72000000を指定しています。タイムスライス単位を1msとするためconfigTICK_RATE_HZは1秒間のTick数を1000(Tick:1ms)に指定しています。これでタスクを切り替えるコンテキストスイッチが1msごとに発生します。
タスク優先度は5段階としたいためにconfigMAX_PRIORITIESは5に指定しています。優先度は0(IDLEタスク)から機能しますので、この場合、設定優先度は1から4までとなります。必要以上に大きな値を指定するとそれだけメモリを消費します。configMINIMAL_STACK_SIZEには128を指定しておきます。RTOSに割り当てるRAM合計サイズとして確保する値をconfigTOTAL_HEAP_SIZEに指定します。登録するタスクの数と各タスクに割り当てる容量を考慮して値を指定します。
最後のconfigMAX_TASK_NAME_LEN(タスク名最大長)は16(半角16文字)を指定しておきます。
教材ボードではRAMが64kで十分なためRTOSに割り当てるメモリ容量は少し贅沢な設定としていますが、RAMが小さい場合はシビアに調整する必要があります。RTOSを使用するアプリケーションではRAM容量の大部分はRTOSの割当になりますのでマイコンの仕様に合わせて意識して設定するようにしてください。
これでFreeRTOSの初期設定は完了ですので、あとはアプリケーションに合わせて、どのようなタスクの管理ができるかを解説していきます。