概要
以前、M5Stackを搭載し、スマホから操作できるラジコンを作りました。
モーターを動作させる処理とLCD更新処理が同じループにいるため、操作遅延等を引き起こす可能性があったり、LEDをほわほわ光らせる制御を同時に行いたいとき等にかなり処理が煩雑になってしまいます。
M5StackはESP32が入っており、ESP32はデュアルコアかつFreeRTOSで動いているとのことなのでマルチタスクを実装してみようと思います。
参考記事
環境
- OS: MacOS Mojave
- エディタ:Visual Studio Code
- IDE: PlatformIO (VSCodeの拡張機能)
- マイコン: M5Stack GRAY
マルチタスクとは
複数のタスクを並行して処理すること。
複数のコアが乗っている場合、それぞれのコアで処理を並行して行うことができる。
1つのコアでマルチタスクをする場合はスレッドに分け、一つのタスクを一定時間処理し、次のタスクを一定時間処理し...みたいにすることで並列処理を行う。
タスク生成関数
参考記事にわかりやすく書かれていますが、xTaskCreatePinnedToCore
でマルチタスクを生成できる。
また、こちらに詳細に書かれています。
BaseType_t xTaskCreatePinnedToCore(
TaskFunction_t pvTaskCode,
const char *constpcName,
const uint32_t usStackDepth,
void *constpvParameters,
UBaseType_t uxPriority,
TaskHandle_t *constpvCreatedTask,
const BaseType_t xCoreID)
pvTaskCode
関数ポインタ
*constpcName
タスク名
usStackDepth
スタックサイズ(Byte)
*constpvParameters
タスクへ渡すパラメータ
uxPriority
タスクの優先度
数字が大きいほど優先度が高い
*constpvCreatedTask
タスクを参照するためのハンドラー
xCoreID
タスクを実行するコア(tskNO_AFFINITY
or 0
or 1
)
値がtskNO_AFFINITY
の場合、タスクはスケジューラーが勝手にコアを決めてくれる。
コア0はWiFiやBluetooth通信機能で使用されるので、機能を使用する場合は避けたほうがいいかも。
コア1はloop関数が実行されるコア
マルチタスクを実装
注意する点は
- 実行するタスク(関数)は終了してはいけない。無限ループを実装しましょう。これを見つけるまでに時間がかかりました...
- **タスクには
delay
関数をいれる。**入れないと待ち時間がなくタスクが切り替わりません。
このソースコードではコア1を指定しているのでコア1でスレッドを生成してマルチタスクが実行されているということになります。
loop
関数は呼び出し元で無限ループとなっているので終了しません。
#define M5STACK_MPU6886 // IMUの種類を指定
#include <Arduino.h>
#include <M5Stack.h>
#include "utility/MPU9250.h"
TaskHandle_t lcdTaskHandle = NULL;
float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;
float gyroX = 0.0F;
float gyroY = 0.0F;
float gyroZ = 0.0F;
float pitch = 0.0F;
float roll = 0.0F;
float yaw = 0.0F;
float temp = 0.0F;
// Task function
void lcdUpdateTask(void *args)
{
while (1) // マルチタスクの処理は終了してはいけない
{
M5.Lcd.setCursor(0, 60);
M5.Lcd.printf(" %5.2f %5.2f %5.2f ", pitch, roll, yaw);
M5.Lcd.setCursor(220, 82);
M5.Lcd.print(" degree");
M5.Lcd.setCursor(0, 120);
M5.Lcd.printf("Temperature : %.2f C", temp);
delay(10);
}
}
void setup()
{
// LCD設定
M5.begin();
M5.Lcd.setBrightness(100);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(WHITE, BLACK);
// IMU設定
M5.IMU.Init();
// マルチタスク処理実行
xTaskCreatePinnedToCore(lcdUpdateTask, "lcdTask", 4096, NULL, 1, &lcdTaskHandle, 1);
}
void loop()
{
// IMUのデータを取得
M5.IMU.getAhrsData(&pitch, &roll, &yaw);
M5.IMU.getTempData(&temp);
delay(1);
}