STM32のFreeRTOSのカウンティングセマフォの使い方

STM32のFreeRTOSでカウンティングセマフォの使い方を、サンプルコードと合わせてわかりやすく解説します。

作成するプログラム

まずはゴールを確認しましょう。スレッドを3つ用意し、同時に2つまでのスレッドがLEDへの点滅操作を行うプログラムを作ります。この実行数を抑制するためにリソース数が2つのセマフォを使うことで実現します。

 

カウンティングセマフォを使ったプログラム

 

この図はThread1とThread2だけがセマフォの取得を成功し、LEDにアクセスしている様子を表しています。Thread1かThread2のいずれかの処理が終わればThread3がセマフォを取得し、LEDにアクセスできるようになります。

 

前提条件

前提条件は目次の記事を参照してください。

【サンプルあり】STM32のFreeRTOSの使い方まとめ

 

プログラムの作成

スレッドの作成

まずはスレッドを作成しましょう。今回は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のバイナリセマフォの使い方

目次:【サンプルあり】STM32のFreeRTOSの使い方まとめ

ソースコード:https://github.com/yuksblog/stm32_freertos