過日YouTubeでツールラボというチャネルを知りました。
徘徊してみるとarduinoでFreeRTOSを動かすトピックがありまして・・・コレだ!と飛びついた次第↓
こちらはYouTubeと連携したhpでYouTubeはこちら↓
このチャンネルはとても解説が丁寧で教材も簡潔明瞭でナレーションも解説図も良く練られていて大変解りやすいのでありました(拍手)。
話を戻すとarduinoでFreeRTOSを導入出来るのはarduino(AVR8)と他にもsamd(CortexM0+系)他がある様です(ESP32系もありますよね)。そういう訳でarduinoでFreeRTOSが動かせるのであればと・・・久々に中華arduino nanoを買ってしまいました。最近のはMiniBではなくてUSB-Cの様で併せてUSB-Cケーブルも調達。中華らしく(最近は多い様ですが)CH340ですがFTDIデバイスに見えるのでarduino ideからは普通に認識される様になった様です(昔は駄目の場合もあった様な・・・)。

基板逆で読みにくいのですがLEDは上からL(13),PWR,TX,RXです(一般的な構成)。
目的のFreeRTOSはライブラリマネージャでFreeRTOSで出てくるのでFreeRTOSをインストール

上図のとおりsamd21,samd51版もある様です(xiao(samd21),wio terminal(samd51等)その際はseeed製品ではそれ用のツールライブラリ導入要。
環境整備も出来たのでFreeRTOSのサンプルをコンパイルしてみます。
#include <Arduino_FreeRTOS.h>
// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogRead( 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(115200);
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(
TaskBlink
, "Blink" // 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(
TaskAnalogRead
, "AnalogRead"
, 128 // Stack size
, NULL
, 1 // Priority
, NULL );// Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}void loop()
{
// Empty. Things are done in Tasks.
}/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.Most Arduinos have an on-board LED you can control. On the UNO, LEONARDO, MEGA, and ZERO
it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN takes care
of use the correct LED pin whatever is the board used.
The MICRO does not have a LED_BUILTIN available. For the MICRO board please substitute
the LED_BUILTIN definition with either LED_BUILTIN_RX or LED_BUILTIN_TX.
e.g. pinMode(LED_BUILTIN_RX, OUTPUT); etc.
If you want to know what pin the on-board LED is connected to on your Arduino model, check
the Technical Specs of your board at https://www.arduino.cc/en/Main/Products
This example code is in the public domain.modified 8 May 2014
by Scott Fitzgerald
modified 2 Sep 2016
by Arturo Guadalupi
*/// initialize digital LED_BUILTIN on pin 13 as an output.
pinMode(LED_BUILTIN, OUTPUT);for (;;) // A Task shall never return or exit.
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay( 500 / portTICK_PERIOD_MS ); // wait for one second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
vTaskDelay( 500 / portTICK_PERIOD_MS ); // wait for one second
}
}void TaskAnalogRead(void *pvParameters) // This is a task.
{
(void) pvParameters;
/*
AnalogReadSerial
Reads an analog input on pin 0, prints the result to the serial monitor.
Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.This example code is in the public domain.
*/for (;;)
{
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
vTaskDelay(1000 / portTICK_PERIOD_MS); // one tick delay (15ms) in between reads for stability
}
}

上図のとおりタスクは2つ(TaskBlink,TaskAnalogRead)でxTaskCreate()で各タスクを定義(所謂TCB)して、各タスクはvoid TaskBlink()みたいな形で記述する様です。早速arduino ideで動かしてみると、

画面右中がserialprintされたa0ポートのADC(何も繋いてないので適当な値が出ている)arduino上で13のledが500ms周期で点滅しております。
arduinoでFreeRTOSが動くとは上記YouTubeチャネルで初めて知りました(恥ずかし)のですがリスキリング的な意味でFreeRTOSを触ってみようかと思ったりします。
今回引用させて頂いたツールラボチャンネルは大変解りやすいので個人的にはお勧めです:)
20251212 16:02追記:FreeRTOS(samd21)を導入し、seeed xiao(samd21g18)でサンプルを動かしてみました。

まづ、FreeRTOS(samd21)を導入しておきます。
それからサンプルを開き、led(13)の点滅を追加して・・・

上図中、88行目が動作確認用に追加したled点滅。TaskBにディスパッチする度にled(13)を反転するいつものコード。
//**************************************************************************// FreeRtos on Samd21// By Scott Briscoe//// Project is a simple example of how to get FreeRtos running on a SamD21 processor// Project can be used as a template to build your projects off of as well////**************************************************************************#include <FreeRTOS_SAMD21.h>//**************************************************************************// Type Defines and Constants//**************************************************************************#define ERROR_LED_PIN 13 //Led Pin: Typical Arduino Board//#define ERROR_LED_PIN 2 //Led Pin: samd21 xplained board#define ERROR_LED_LIGHTUP_STATE HIGH // the state that makes the led light up on your board, either low or high// Select the serial port the project should use and communicate over// Some boards use SerialUSB, some use Serial//#define SERIAL SerialUSB //Sparkfun Samd21 Boards#define SERIAL Serial //Adafruit, other Samd21 Boards//**************************************************************************// global variables//**************************************************************************TaskHandle_t Handle_aTask;TaskHandle_t Handle_bTask;TaskHandle_t Handle_monitorTask;//**************************************************************************// Can use these function for RTOS delays// Takes into account processor speed// Use these instead of delay(...) in rtos tasks//**************************************************************************void myDelayUs(int us){vTaskDelay( us / portTICK_PERIOD_US );}void myDelayMs(int ms){vTaskDelay( (ms * 1000) / portTICK_PERIOD_US );}void myDelayMsUntil(TickType_t *previousWakeTime, int ms){vTaskDelayUntil( previousWakeTime, (ms * 1000) / portTICK_PERIOD_US );}//*****************************************************************// Create a thread that prints out A to the screen every two seconds// this task will delete its self after printing out afew messages//*****************************************************************static void threadA( void *pvParameters ){SERIAL.println("Thread A: Started");for(int x=0; x<100; ++x){SERIAL.print("A");SERIAL.flush();myDelayMs(300);}// delete ourselves.// Have to call this or the system crashes when you reach the end bracket and then get scheduled.SERIAL.println("Thread A: Deleting");vTaskDelete( NULL );}//*****************************************************************// Create a thread that prints out B to the screen every second// this task will run forever//*****************************************************************static void threadB( void *pvParameters ){SERIAL.println("Thread B: Started");while(1){SERIAL.println("B");SERIAL.flush();myDelayMs(1000);digitalWrite(13,!digitalRead(13));}}//*****************************************************************// Task will periodically print out useful information about the tasks running// Is a useful tool to help figure out stack sizes being used// Run time stats are generated from all task timing collected since startup// No easy way yet to clear the run time stats yet//*****************************************************************static char ptrTaskList[400]; //temporary string buffer for task statsvoid taskMonitor(void *pvParameters){int x;int measurement;SERIAL.println("Task Monitor: Started");// run this task afew times before exiting foreverwhile(1){myDelayMs(10000); // print every 10 secondsSERIAL.flush();SERIAL.println("");SERIAL.println("****************************************************");SERIAL.print("Free Heap: ");SERIAL.print(xPortGetFreeHeapSize());SERIAL.println(" bytes");SERIAL.print("Min Heap: ");SERIAL.print(xPortGetMinimumEverFreeHeapSize());SERIAL.println(" bytes");SERIAL.flush();SERIAL.println("****************************************************");SERIAL.println("Task ABS %Util");SERIAL.println("****************************************************");vTaskGetRunTimeStats(ptrTaskList); //save stats to char arraySERIAL.println(ptrTaskList); //prints out already formatted statsSERIAL.flush();SERIAL.println("****************************************************");SERIAL.println("Task State Prio Stack Num Core" );SERIAL.println("****************************************************");vTaskList(ptrTaskList); //save stats to char arraySERIAL.println(ptrTaskList); //prints out already formatted statsSERIAL.flush();SERIAL.println("****************************************************");SERIAL.println("[Stacks Free Bytes Remaining] ");measurement = uxTaskGetStackHighWaterMark( Handle_aTask );SERIAL.print("Thread A: ");SERIAL.println(measurement);measurement = uxTaskGetStackHighWaterMark( Handle_bTask );SERIAL.print("Thread B: ");SERIAL.println(measurement);measurement = uxTaskGetStackHighWaterMark( Handle_monitorTask );SERIAL.print("Monitor Stack: ");SERIAL.println(measurement);SERIAL.println("****************************************************");SERIAL.flush();}// delete ourselves.// Have to call this or the system crashes when you reach the end bracket and then get scheduled.SERIAL.println("Task Monitor: Deleting");vTaskDelete( NULL );}//*****************************************************************void setup(){pinMode(13, OUTPUT);SERIAL.begin(115200);delay(1000); // prevents usb driver crash on startup, do not omit thiswhile (!SERIAL) ; // Wait for serial terminal to open port before starting programSERIAL.println("");SERIAL.println("******************************");SERIAL.println(" Program start ");SERIAL.println("******************************");SERIAL.flush();// RTOS also Needs to know if high/low is the state that turns on the led.// Error Blink Codes:// 3 blinks - Fatal Rtos Error, something bad happened. Think really hard about what you just changed.// Probably ran out of heap.// 1 blink - Stack overflow, Task needs more bytes defined for its stack!// Use the taskMonitor thread to help gauge how much more you needvSetErrorLed(ERROR_LED_PIN, ERROR_LED_LIGHTUP_STATE);// sets the serial port to print errors to when the rtos crashes// if this is not set, serial information is not printed by defaultvSetErrorSerial(&SERIAL);// Create the threads that will be managed by the rtos// Sets the stack size and priority of each task// Also initializes a handler pointer to each task, which are important to communicate with and retrieve info from tasksxTaskCreate(threadA, "Task A", 256, NULL, tskIDLE_PRIORITY + 3, &Handle_aTask);xTaskCreate(threadB, "Task B", 256, NULL, tskIDLE_PRIORITY + 2, &Handle_bTask);xTaskCreate(taskMonitor, "Task Monitor", 256, NULL, tskIDLE_PRIORITY + 1, &Handle_monitorTask);// Start the RTOS, this function will never return and will schedule the tasks.vTaskStartScheduler();// error scheduler failed to start// should never get here
{SERIAL.println("Scheduler Failed! \n");SERIAL.flush();delay(1000);}}//*****************************************************************// This is now the rtos idle loop// No rtos blocking functions allowed!//*****************************************************************void loop(){// Optional commands, can comment/uncomment belowSERIAL.print("."); //print out dots in terminal, we only do this when the RTOS is in the idle stateSERIAL.flush();delay(100); //delay is interrupt friendly, unlike vNopDelayMS}//*****************************************************************
seeed XIAO(samd21g18)は昔買っていたのですが・・・行方不明につき秋月で購入@950円

左の丸い物体は最近のXIAOの容器の様です。下というか裏というかにピンヘッダが入っています。前の袋よりコスト掛かっていそうですが梱包事故防止の為か否かは不明。

シリアルモニタの出力。TaskAは100回ループすると自殺(taskをdeleteする)コードなので画面真ん中付近に「Thread A: Deleting」のメッセージが入っています。
FreeRTOSはRTOSですがプリエンプションもサポートしているので昔の(ITRONの様な)タスクが全責任を持ってコンテキスト切り替えを行わなくてもシステムタイマでプリエンプションが発生するので固まる可能性が少ないので精神的に楽というかガチガチのリアルタイム性能を求めない用途にはその方が有難いというか・・・
arduinoもFreeRTOSが動くとそれなりの実用性が出てくるというか楽にプログラムが組めるのでとても助かります。arduinoはハードウェアをデバイスレベルで抽象化してくれてるので楽で良いです(楽する事しか考えていない:)。
20251212 21:39追記:YouTube動画ですが(アフィリエイトの可能性:)seeed XIAOファミリを紹介したコンテンツです。この手のモノがジジイばかりなのは・・・余暇活用?