STM32のFreeRTOSでカウンティングセマフォの使い方を、サンプルコードと合わせてわかりやすく解説します。
作成するプログラム
まずはゴールを確認しましょう。スレッドを3つ用意し、同時に2つまでのスレッドがLEDへの点滅操作を行うプログラムを作ります。この実行数を抑制するためにリソース数が2つのセマフォを使うことで実現します。
この図はThread1とThread2だけがセマフォの取得を成功し、LEDにアクセスしている様子を表しています。Thread1かThread2のいずれかの処理が終わればThread3がセマフォを取得し、LEDにアクセスできるようになります。
前提条件
前提条件は目次の記事を参照してください。
プログラムの作成
スレッドの作成
まずはスレッドを作成しましょう。今回は3つのスレッドを使うので3つ作ります。
- Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Tasks and Queues
- 下記の設定を参考にスレッドを3つ作成してください
プライオリティが全て同じでないと動かないのでよく確認してください
カウンティングセマフォの有効化
FreeRTOSではカウンティングセマフォを使う場合、OSの設定として有効化が必要です。
- Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Config Parameters
- USE_COUNTING_SEMAPHORESをEnabledに変更してください
カウンティングセマフォの作成
カウンティングセマフォを作ってみましょう。
- Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Timers and Semaphores
- Counting SemaphoresのAddボタンをクリックして、カウンティングセマフォの設定画面を開いてください
- 下記の図のように入力して、OKボタンを押してください
ここの設定項目が気になる方は下記の表をご覧になってください。気にせず、とにかく動かしたい方は読み飛ばしてくださいね。
項目 | 説明 |
Semaphore Name | セマフォの名前。 |
Count | セマフォのリソースの数。 |
Allocation |
メモリ確保の方法。 Dynamicだと動的生成。 Staticだと静的生成。 |
Control Block Name | コントロールブロックの名前。Staticの時のみ使用。 |
設定が終わったらコードを自動生成してください。
スレッドの実装
コードの自動生成ができたらスレッドを実装していきましょう。どのスレッドも、セマフォを取得し、取得できたら一定時間点滅を行い、終わったらセマフォをリリースするだけです。それぞれのスレッドで点滅の間隔が異なるため、実行されるスレッドの組み合わせによって、点滅方法が変わります。
例としてはあまりよろしくありませんが、スレッドの実行数がセマフォによって抑制されることは十分確認できるかと思います。
main.c:Thread1
void Thread1Func(void const * argument) { /* USER CODE BEGIN 5 */ /* Infinite loop */ for(;;) { if (osSemaphoreWait(CountingSemHandle, osWaitForever) == osOK) { for (uint16_t i = 0; i < 10; i++) { HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); osDelay(200); } } osSemaphoreRelease(CountingSemHandle); osThreadYield(); } /* USER CODE END 5 */ }
main.c:Thread2
void Thread2Func(void const * argument) { /* USER CODE BEGIN Thread2Func */ /* Infinite loop */ for(;;) { if (osSemaphoreWait(CountingSemHandle, osWaitForever) == osOK) { for (uint16_t i = 0; i < 10; i++) { HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET); osDelay(50); } } osSemaphoreRelease(CountingSemHandle); osThreadYield(); } /* USER CODE END Thread2Func */ }
main.c:Thread3
void Thread3Func(void const * argument) { /* USER CODE BEGIN Thread3Func */ /* Infinite loop */ for(;;) { if (osSemaphoreWait(CountingSemHandle, osWaitForever) == osOK) { for (uint16_t i = 0; i < 10; i++) { HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET); osDelay(100); } } osSemaphoreRelease(CountingSemHandle); osThreadYield(); } /* USER CODE END Thread3Func */ }
osSemaphoreWait()とosSemaphoreRelease()でセマフォの操作を行うのは、バイナリセマフォと同じです。
osThreadYield()は、スレッドの処理を停止し、他のスレッドに実行権を移すすために使用します。
プログラムの作成は以上です。実際に動かしてLEDの点滅方法が変わることを確認してみてください。点滅方法が変われば、実行されているスレッドが切り替わっているということです。
まとめ
STM32のFreeRTOSのカウンティングセマフォの使い方は以上です。FreeRTOSの設定が必要な点以外はバイナリセマフォと使い方が同じなので、特に問題はないかと思います。
関連:STM32のFreeRTOSのバイナリセマフォの使い方