STM32 FreeRTOS V2 メッセージキューを使う

STM32 FreeRTOS V2 メッセージキューを使う

今回は FreeRTOS Ver2 のメッセージキューについて説明します。

投稿時の開発環境を記しておきます。

PC:Windows10 OS
IDE: STM32CubeIDE Version1.6.0
Configurator: STM32CubeMX Version6.2.1
Board: STM32Nucleo-F401RE

メッセージキューとは

複数のスレッド間でデータの受け渡しを行いたい場合があります。
そんな時にメッセージキューを使います。

FreeRTOS V1 ではメールキューとメッセージキューがありました。
V2ではV1のメールキューをメッセージキューとして使うようになったようです。

構造体などのように大きなデータを送ることができます。

プロジェクトを作成する

IDEを起動し、File- New – STM32 Project を選択し、Target Selection ウィンドウが出たら Board Selector タブを選択し Boards List から NUCLEO-F401RE を選択し Next ボタンを押します。

Project 名に F401RtosV2MessageQueue と入力し、Finishボタンを押します。
Initialize all peripherals with their default Mode ? と聞いてくるので Yesを押します。

RTOSを使えるように設定する

Pinout & Configuration – Categories – Middleware – FREERTOS を選択し、

Mode の Interface で CMSIS_V2 を選択します。

その下の Configuration – Tasks and Queues タブを選択し、 まず上(Tasks)のAddボタンを押します。

New Task のウィンドウが出てくるので、そのまま OK ボタンを押します。

次にその下の Queues のAddボタンを押します。

New Queue のウィンドウが出てくるので、そのまま OK ボタンを押します。

これでタスク(スレッど)が2つつくられて、メッセージキューもひとつつくられます。

タイムベース ソースを変更する

Categories – System Core – SYS を選択し、SYS Mode and Configuration – Mode で

Timebase Source を Systick から TIM10 に変更しておきます。

(FreeRTOSでは Systick 以外を使うことが推奨されているからです)

ビルドしてエラーがないことを確認しておきます。

生成された関数を確認しておく

main.cのmain()関数内で、while()ループの少し手前に以下のコードがあることを確認しておきます。
コメントは省略しています。

myQueue01Handle = osMessageQueueNew (16, sizeof(uint16_t), &myQueue01_attributes);
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
myTask02Handle = osThreadNew(StartTask02, NULL, &myTask02_attributes);

今回は構造体を送ることにするので1行目を以下のように編集します。

myQueue01Handle = osMessageQueueNew (MSGQUEUE_OBJECTS, sizeof(MSGQUEUE_OBJ_t), &myQueue01_attributes);

第1引数はキューの数を指定します。
第2引数には構造体で使うメモリの大きさを指定します。

次に使用する構造体の宣言を行っておきましょう。
main()の手前あたりに以下の記述をおこないます。
(どんな構造体でも構いません。以下は一例です)

/* USER CODE BEGIN 0 */
#define MSGQUEUE_OBJECTS 16 //メッセージキューオブジェクトの数

typedef struct
{                                 //オブジェクトのデータ型
  uint8_t Buf [32];
  uint8_t Idx;
} MSGQUEUE_OBJ_t;
/* USER CODE END 0 */

最初にキューが、その後2つでスレッドがつくられていることがわかります。

設定するだけで、初期化コードを出力してくれるので便利ですね。

コーディングと動作確認

StartDefaultTask()でメッセージを送信し、StartTask02()で受信してみます。

送信側は以下のようにコーディングします。

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN 5 */
  /* Infinite loop */

  MSGQUEUE_OBJ_t msg = {};

  for(;;)
  {
    osDelay(1000);
    msg.Idx = 3;
    msg.Buf[0] = '7';
    osMessageQueuePut(myQueue01Handle, &msg, 0U, 0U);
  }
  /* USER CODE END 5 */
}

受信側は以下のようにコーディングします。

void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
  MSGQUEUE_OBJ_t msg = {};
  osStatus_t status;

  __IO int flg = 0;
  uint8_t c = 0;

  /* Infinite loop */
  for(;;)
  {
    status = osMessageQueueGet(myQueue01Handle, &msg, 0U, 0U);
    if (osOK == status)
    {
      if (msg.Idx == 3)
      {
        flg = 1;
      }
      else
      {
        flg = 0;
      }
      c = msg.Buf[0];
    }
  }
  /* USER CODE END StartTask02 */
}

送信には osMessageQueuePut()を、受信は osMessageQueueGet()を使います。
第1引数には osMessageQueueNew()でつくられた戻り値を指定します。
第2引数には 構造体のアドレスを指定します。

ビルドして実行する

ビルドしてエラーがないことを確認後、実行します。

StartTask02()のスレッドで1秒毎に送信した構造体データを受信できれば成功です。

FreeRTOS_V2カテゴリの最新記事