0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FreeRTOSのvTaskResumeは、タスクのどこから再開するのか(結論: suspendしたところから)

Posted at

vTaskSuspend() で suspend となったタスクを vTaskResume() で再開すると、どこから再開するのか?という素朴な疑問を確認しました。

検証環境:

  • ボード: Wio LTE JP Version (STM32F405RG)
  • FreeRTOS: Arduino_FreeRTOS_Library 11.1.0

結論

suspend したところから再開します。タスクの先頭からの再開ではありません。

※ 挙動や目的を考えると、当たり前と言えば当たり前ですが。

コードと結果

  • pushToQueueTask popFromQueueTask startAndStopTask という3つのタスクを作成
  • pushToQueueTask からキューを通して popFromQueueTask へカウントデータを1秒毎に送信、受信側でデータを表示
  • startAndStopTask が不定期(1.0秒~2.5秒毎)に pushToQueueTask を suspend/resume している
where_is_resuming_from.ino
#include <WioLTEforArduino.h>
#define CONSOLE SerialUSB
#include <STM32FreeRTOS.h>
#include <STM32FreeRTOSConfig_extra.h>  // ref: https://qiita.com/ma2shita/items/88036fa3a75ffa684ec2

WioLTE Wio;
TaskHandle_t pushToQueueTask_h = NULL;
QueueHandle_t xQueue;
struct QUEUE_PAYLOAD {
  uint8_t data;
};

void pushToQueueTask(void *pvParameters) {
  CONSOLE.println("(pushToQueueTask) init.");
  QueueHandle_t q = (QueueHandle_t)pvParameters;
  struct QUEUE_PAYLOAD q_payload;
  for (;;) {
    for (uint8_t i = 0; i < 100; i++) {
      q_payload.data = i;
      xQueueSend(q, &q_payload, portMAX_DELAY);
      vTaskDelay(pdMS_TO_TICKS(1000));
    }
  }
}

void popFromQueueTask(void *pvParameters) {
  QueueHandle_t q = (QueueHandle_t)pvParameters;
  struct QUEUE_PAYLOAD q_payload;
  for (;;) {
    xQueueReceive(q, &q_payload, portMAX_DELAY);
    CONSOLE.printf("(popFromQueueTask) q_payload.data: %d\r\n", q_payload.data);
  }
}

void startAndStopTask(void *pvParameters) {
  for (;;) {
    if (eTaskGetState(pushToQueueTask_h) == eSuspended) {
      CONSOLE.println("(startAndStopTask) vTaskResume()");
      vTaskResume(pushToQueueTask_h);
    } else {
      CONSOLE.println("(startAndStopTask) vTaskSuspend()");
      vTaskSuspend(pushToQueueTask_h);
    }
    vTaskDelay(pdMS_TO_TICKS(random(10, 26)*100));
  }
}

void setup() {
  CONSOLE.begin(9600);
  delay(2000);
  Wio.Init();

  xQueue = xQueueCreate(1, sizeof(QUEUE_PAYLOAD));
  xTaskCreate(popFromQueueTask, nullptr, 1024, xQueue, 1, nullptr);
  xTaskCreate(pushToQueueTask, nullptr, 1024, xQueue, 1, &pushToQueueTask_h);
  xTaskCreate(startAndStopTask, nullptr, 1024, nullptr, 1, nullptr);
  vTaskStartScheduler();

  for (;;) __asm__("wfi");
}

void loop() {
  // Unnecessary Impl.
}

結果は以下の通りです。
init は xCreateTask() の直後1回のみ。以降は suspend したところから resume しています。

(pushToQueueTask) init.
(startAndStopTask) vTaskSuspend()
(popFromQueueTask) q_payload.data: 0
(startAndStopTask) vTaskResume()
(popFromQueueTask) q_payload.data: 1
(popFromQueueTask) q_payload.data: 2
(popFromQueueTask) q_payload.data: 3
(startAndStopTask) vTaskSuspend()
(startAndStopTask) vTaskResume()
(popFromQueueTask) q_payload.data: 4
(popFromQueueTask) q_payload.data: 5
(startAndStopTask) vTaskSuspend()
(startAndStopTask) vTaskResume()
(popFromQueueTask) q_payload.data: 6
(popFromQueueTask) q_payload.data: 7

タスクの初期処理をしたければ vTaskDelete/xCreateTask を使う

タスクを初期処理から動かしたければ、vTaskDelete()でタスクを削除し、xCreateTask() でタスクを作ることで実現できます。

startAndStopTask() を、以下のように差し替えます。

void startAndStopTask(void *pvParameters) {
  for (;;) {
    if (eTaskGetState(whereIsResumingFromTask_h) == eDeleted) {
      CONSOLE.println("(startAndStopTask) xTaskCreate");
      xTaskCreate(pushToQueueTask, nullptr, 1024, xQueue, 1, &pushToQueueTask_h);
    } else {
      CONSOLE.println("(startAndStopTask) vTaskDelete");
      vTaskDelete(pushToQueueTask_h);
    }
    vTaskDelay(pdMS_TO_TICKS(random(10, 26)*100));
  }
}

結果は以下の通り。

(pushToQueueTask) init.
(startAndStopTask) vTaskDelete
(popFromQueueTask) q_payload.data: 0
(startAndStopTask) xTaskCreate
(pushToQueueTask) init.
(popFromQueueTask) q_payload.data: 0
(popFromQueueTask) q_payload.data: 1
(popFromQueueTask) q_payload.data: 2
(startAndStopTask) vTaskDelete
(startAndStopTask) xTaskCreate
(pushToQueueTask) init.
(popFromQueueTask) q_payload.data: 0
(popFromQueueTask) q_payload.data: 1
(startAndStopTask) vTaskDelete
(startAndStopTask) xTaskCreate
(pushToQueueTask) init.
(popFromQueueTask) q_payload.data: 0
(popFromQueueTask) q_payload.data: 1
(startAndStopTask) vTaskDelete

このままだと、xTaskCreate の引数設定が冗長なので、関数で共通化したほうが良いかもしれません。

EoT

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?