FreeRTOS タスク

タスクの実装は以下のように、戻り値はなく、void型のポインターを引数に取ります。タスクは無限ループとして実装し、終了する場合は明示的にタスクをDeleteします。


void ATaskFunction( void *pvParameters );
 
void ATaskFunction( void *pvParameters ){
    while(1){
        // do something
    }
}

GR-ROSEはシングルコアのため、同時に一つのタスクしか実行されません。実行しているときの状態を"Running"、実行していないときは複数の状態(State)として、 "Blocked"、 "Ready"、 "Suspended"があります。

タスクは最も優先順位の高いものから実行され、優先順位が同じ場合は順番に実行されます。優先順位が低いタスクを実行中に、優先順位が高いタスクが"Ready"になった場合は、実行するタスクがスイッチされます。

タスクの中でvTaskDelay()やdelay()、あるいはQueueを待つような処理を実行したとき、"Blocked"状態になります。もし優先順位の低いタスクが"Ready"となっていた場合は、"Running"状態になります。

GR-ROSEのSDKでは、優先順位を7段階(0から6)で指定できます。setupやloopが実行されるmainタスクの優先順位は3となっています。以上を踏まえて一つサンプルを掲載します。


#include <Arduino.h>
#include "FreeRTOS.h"
#include "task.h"
 
void task1(void *pvParameters);
void task6(void *pvParameters);
 
void setup(){
  Serial.begin(9600);
  delay(3000); // wait for display serial monitor
  xTaskCreate( task1, "TASK1", 512, NULL, 1, NULL );
  xTaskCreate( task6, "TASK6", 512, NULL, 6, NULL );
}
 
void loop(){
  static uint32_t ctime = millis();
  if((millis() - ctime) > 5000){
    delay(1000); // entering Block State
  }
}
 
void task1(void *pvParameters){
  while(1){
    Serial.println("task1 running");
    delay(1000); // entering Blocked State
  }
}
void task6(void *pvParameters){
  while(1){
    Serial.println("task6 running");
    delay(1000); // entering Blocked State
  }
}

上記のサンプルは優先度1のtask1と、優先度6のtask6を生成しています。それぞれ1秒毎にシリアル出力をするタスクです。5秒経つと、優先度3のloopでdelay()が実行され"Blocked"状態になります。

実行すると以下のようにシリアルモニターに表示されます。setupでtask1とtask6が生成されますが、5秒間はloopよりも優先度が高いtask6のみが実行されます。5秒後はloopでdelay()を実行し、"Blocked"状態になるため、task1も実行されるようになっていることが分かります。

task6 running
task6 running
task6 running
task6 running
task6 running
task6 running
task1 running
task6 running
task1 running
task6 running
task1 running
task6 running
task1 running

タスクをDeleteするサンプルを示します。1秒毎に周期タスクが実行されますが、5回実行したときにvTaskDeleteを実行し、タスクをDeleteしています。タスクは概要に示す通り、HEAPメモリを消費しますので、不要なときはDeleteしましょう。


#include <Arduino.h>
#include "FreeRTOS.h"
#include "task.h"
 
void periodic(void *pvParameters);
TaskHandle_t periodicHandle = NULL;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(1000);
   
  xTaskCreate(periodic, "PERIODIC", 512, NULL, 2, &periodicHandle);
}
 
void loop() {
  // put your main code here, to run repeatedly:
  delay(1);
}
 
void periodic(void *pvParameters) {
  while (1) {
    static int count = 0;
    Serial.println(count);
    delay(1000);
    count++;
    if(count == 5){
      vTaskDelete( periodicHandle );
    }
  }
}