STM32のFreeRTOSのメッセージキューの使い方

STM32のFreeRTOSでメッセージキューの使い方を、サンプルコードと合わせてわかりやすく解説します。

メッセージキューとメールキュー

メッセージキューの使い方の前に、CMSIS RTOSではメッセージキューとメールキューの2つのキューがあるので、それぞれの違いを簡単に説明しておきます。

 

  • メッセージキュー
    • int型かポインタ型の32ビットデータを送受信できるキュー
  • メールキュー
    • 32ビットを超えるデータを送受信できるキュー

 

単なるIDでやり取りできる場合はメッセージキューを使い、構造体などを使って複雑なデータのやり取りをしたい場合はメールキューを使う、という使い分けになるでしょう。

 

作成するプログラム

それでは今回のゴールを確認しましょう。今回はメッセージキューを使い、2つのスレッド間でデータの送受信を行います。PublisherスレッドはON/OFFデータを送信し、SubscriberスレッドはそのON/OFFデータに基づき、LEDを点灯・消灯します。

このプログラム作成を通してメッセージキューの使い方を覚えましょう。

 

メッセージキューを使ったプログラム

 

前提条件

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

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

 

プログラムの作成

スレッドの作成

まずはPublisherスレッドとSubscriberスレッドを作成します。STM32CubeIDEのDevice Configuration Tool(STM32CubeMX)を開いてスレッドを作成してください。

 

  • Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Tasks and Queue
  • 下記の2つのスレッドを作成してください

 

PublisherとSubscriberの設定

 

メッセージキューの作成

次はメッセージキューの作成です。

 

  • Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Tasks and Queue
  • QueuesのAddボタンをクリックして、Queueの設定画面を開いてください
  • 下記の図にある通りに入力し、OKボタンをクリックしてください

 

LEDQueueの設定画面

 

ここの設定項目が気になる方は下記の表をご覧になってください。気にせず、とにかく動かしたい方は読み飛ばしてくださいね。

 

項目 説明
Queue Name キューの名前。
Queue Size キューのサイズ。
Item Size

キューに入れるメッセージ1つ分のサイズ。

例えばuint16_tといったデータ型で指定します。

Allocation

メモリの確保の仕方。

Dinamicだと動的確保。

Staticだと静的確保。

Buffer Name バッファの名前。Staticを指定した時のみ使用。
Buffer Size バッファサイズ。自動設定されます。
Control Block Name コントロールブロックの名前。Staticを指定した時のみ使用。

 

スレッドとキューの作成ができたらコードを生成してください。

 

Publisherスレッドを実装する

ここからは実際にコードを書いていきます。

まずはPublisherスレッドの中身を作ります。Publisherスレッドでは、定期的にON/OFFデータをメッセージキューに入れるだけです。

 

main.c:Publisherスレッド

void PublisherFunc(void const * argument)
{

  /* USER CODE BEGIN 5 */
  uint16_t led = 0;
  /* Infinite loop */
  for(;;)
  {
    if (led == 0) {
      led = 1;
    } else {
      led = 0;
    }
    osMessagePut(LEDQueueHandle, led, 0);
    osDelay(1000);
  }
  /* USER CODE END 5 */ 
}

 

osMessagePut()でメッセージを送信しています。第1引数はメッセージキューのIDで、コード自動生成で定義されたものを指定しています。第2引数でメッセージを渡します。第3引数は送信タイムアウトの設定で、今回は一切待たないようにしました。

 

Subscriberスレッドを実装する

続いてSubscriber側を作ります。SubscriberスレッドはメッセージキューからON/OFFデータを取り出し、その値に基づいてLEDを点灯・消灯するだけです。

 

main.c:Sunscriberスレッド

void SubscriberFunc(void const * argument)
{
  /* USER CODE BEGIN SubscriberFunc */
  /* Infinite loop */
  for(;;)
  {
    osEvent event = osMessageGet(LEDQueueHandle, 0);
    if (event.status == osEventMessage) {
      if (event.value.v == 0) {
        HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
      } else {
        HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
      }
    }
  }
  /* USER CODE END SubscriberFunc */
}

 

osMessageGet()でイベントを取得しています。第1引数でメッセージキューのIDを指定しています。第2引数は受信タイムアウトの設定で、今回は0なので一切待っていません。

osMessageGet()の返り値であるosEventにイベントの各種情報が含まれています。statusは処理の結果が入っており、これを使ってメッセージが受信できたことを確認しています。valueにはイベントの値、つまりメッセージ自身が入っています。valueは共用体になっていて、value.vだとuint32_t、value.signalsだとint32_t、values.pだとポインタ型で取得できます。

 

プログラムの作成は以上です。実際に動かしてLEDが点滅することを確認してみてください。

 

まとめ

STM32のFreeRTOSを使ったメッセージキューの使い方は以上です。そんなに難しいところはなかったと思います。APIもCMSIS RTOSに準拠していて安心して使えますね。

 

メッセージキューはint型とポインタ型でしか送受信できませんが、もっと大きなデータを使いたい場合はメールキューを使ってください。

 

関連:STM32のFreeRTOSのメールキューの使い方

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

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