STM32のCMSIS RTOS v1のメモリープールの使い方を、サンプルコードと合わせてわかりやすく解説します。
メモリープールとは
CMSIS RTOSにおけるメモリープールとは、スレッドセーフな固定サイズのメモリーブロックの塊です。メモリーに格納したいデータ(例えば構造体)のサイズが1つのメモリーブロックのサイズになります。
作成するプログラム
それでは今回のゴールを確認しましょう。今回はメモリープールを使って、2つのスレッド間で構造体データのデータ共有を行います。構造体はLEDの点灯設定(点灯間隔と点灯回数)を表現します。動きとしてはメールキューのプログラムと同じです。
前提条件
前提条件は目次の記事を参照してください。
プログラムの作成
メモリー管理の方法の設定
メモリープールは内部でFreeRTOSのヒープメモリー管理の機能を使っているので、適切なメモリ管理方法を設定しておく必要があります。
今回のサンプルプログラムではどれを選んでも問題ありませんが、実際の開発の時は適切な設定を行ってください。
- Pinout & Configurationsタブ→Middleware→FREERTOS→Configuration→Config Parameter
- Memory Management schemeで適切な『heap_x』を選択してください
割り込みハンドラの設定
割り込みハンドラの設定については下記の記事で書いていますので、そちらを参照してください。
スレッドの作成
スレッドはデフォルトで作られるdefaultTaskをそのまま使います。
設定は以上なので、コードを自動生成してください。
メモリープールの作成
ここからはコードを書いていきます。まずはメモリープールに入れる構造体と、メモリープールの名前を定義しましょう。
main.c:メモリープールに入れる構造体とメモリープールの名前
/* USER CODE BEGIN PV */ typedef struct LEDConfig { uint32_t interval; uint32_t count; } LEDConfig; osPoolId LEDConfigPoolID; /* USER CODE END PV */
これらの情報を使ってメモリープールを作成します。
main.c:メモリープールの作成
/* USER CODE BEGIN 2 */ osPoolDef(LEDConfigPool, 16, LEDConfig); LEDConfigPoolID = osPoolCreate(osPool(LEDConfigPool)); /* USER CODE END 2 */
poPoolDefでメモリープールの宣言をしています。第1引数にメモリープールの名前を指定します。第2引数はメモリーブロックの数です。第3引数はメモリープールに入れるデータ構造を指定します。
osPoolCreate()でメモリープールを作成します。引数には先ほど宣言したメモリープールを指定してあげます。
ボタン押下時の処理を実装
ボタン押下時、メールキューにLEDの点滅設定を送信します。
main.c:ボタン押下時の割込みハンドラ
/* USER CODE BEGIN 4 */ static uint32_t index; void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { LEDConfig *conf = osPoolAlloc(LEDConfigPoolID); conf->interval = 500 * index; conf->count = 20 / index; osMessagePut(LEDQueueHandle, (uint32_t)conf, 0); index++; if (index > 2) { index = 1; } } /* USER CODE END 4 */
osPoolAlloc()でメモリーブロックを1つ確保して、そのメモリーブロックのポインタをメッセージキューに送信しているだけです。
後はデータ受信処理部を実装すれば完成です。defaultTaskスレッドでLEDの点滅設定を受信し、その設定に従ってLEDを点滅させます。
main.c:defaultTaskスレッドのデータ受信処理
void StartDefaultTask(void const * argument) { /* USER CODE BEGIN 5 */ /* Infinite loop */ for(;;) { osEvent event = osMessageGet(LEDQueueHandle, osWaitForever); if (event.status == osEventMessage) { LEDConfig *conf = (LEDConfig*)event.value.p; for (uint16_t i = 0; i < conf->count; i++) { HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); osDelay(conf->interval); } osPoolFree(LEDConfigPoolID, conf); } } /* USER CODE END 5 */ }
メッセージキューから取得したポインタを経由して、データ共有を実現しています。
最後にpoPoolFree()でメモリーブロックを解放することを忘れないようにしましょう。
プログラムの作成は以上です。実際に動かしてLEDが点滅することを確認してみてください。
まとめ
STM32のFreeRTOSのメモリープールの使い方は以上です。使い方自体はとても簡単だと思います。
実際の開発の際に、適切なヒープの管理方法を設定しておくことだけは忘れないようにしましょう。