LoginSignup
16
17

ArduinoでFreeRTOSを使ってみる(1) 一番単純なプログラム

Last updated at Posted at 2020-10-18

マリオカートハッキングが流行っていて、久しぶりにSTM32のことを思い出しました。
STM32で大規模プログラムを書くために必要なFreeRTOSを、まずはArduinoで勉強してみます。

FreeRTOSとは

オープンソースの組み込み用リアルタイムOS。
非常に軽量(6K~12KB)であることと、複数のマイコン(Arm、AVR(Arduino)、PICなど)に対応していることが特徴的。
2017年にAmazonに買収されているため、AWSとの密な連携が可能となる。

FreeRTOSの公式ドキュメント (https://docs.aws.amazon.com/ja_jp/freertos/latest/userguide/what-is-freertos.html) には、アーキテクチャとして以下の図が掲載されている。MQTTやBLEなどの通信ライブラリやAWS関連の機能があるのが心踊る。
(※ただしこれはFreeRTOSの全体図であり、Arduinoで使えるのはおそらくFreeRTOS Kernelの部分だけ(?)だと思われる。要調査。)
image.png

ArduinoにFreeRTOSをインストールして遊ぶ

インストールする方法

こちらの記事 (https://qiita.com/infinite1oop/items/aac04a70c1ed71cb83cc) を参考に、ライブラリマネージャからFreeRTOSをインストール。簡単。FreeRTOSライブラリのインストールが完了すると、Arduinoのファイル>スケッチ例からFreeRTOSのサンプルプログラムが選択できるようになる。

マルチタスクをやってみる

2つのタスクを約1秒おきに実行するプログラム

シリアル出力で「A」と表示する<タスクA>と「B」と表示する<タスクB>だけのプログラムを作った。

FreeRTOS_task.ino
#include <Arduino_FreeRTOS.h>

void TaskA( void *pvParameters );
void TaskB( void *pvParameters );

// the setup function runs once when you press reset or power the board
void setup() {
  
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
  }

  // Now set up two tasks to run independently.
  xTaskCreate(
    TaskA
    ,  "TaskA"   // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  2  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL );

  xTaskCreate(
    TaskB
    ,  "TaskB"
    ,  128  // Stack size
    ,  NULL
    ,  1  // Priority
    ,  NULL );

}

void loop()
{
  // Empty. Things are done in Tasks.
}

void TaskA(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    Serial.print('A');
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
  }
}

void TaskB(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  for (;;)
  {
    Serial.println('B');
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
  }
}

サンプルプログラムの「Blink_AnalogRead.ino」を修正して作った。
setup()の中でxTaskCreate関数を呼んでタスクを生成し、loop()には何も書かずに各タスクに処理を書くのが基本構成。
優先度が高いタスクは、vTaskDelay()を使用して、待ち状態を意図的に作る必要がある。

上のプログラムをシリアルモニタで見てみる。
キャプチャ.PNG
だいたい1秒おきにAとBが出力されている。Aの方が優先度が高いので、ちゃんとAが先に実行されている。

上記のプログラムでは、タスクAが実行して1秒待つ→その間にタスクBが実行される→タスクAが実行される、という構成のため、タスクAの処理時間だけ1秒間隔がずれてしまっている。50ms~100msくらいずれているので、組み込みの世界では致命的になりかねない。次は「できる限り正確に」1秒周期で実行するタスクを実行するする方法について書きたい。

16
17
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
16
17