モダンOSのお砂場(35) Mbed OS6、Threadを使ってみる、STM32

Joseph Halfmoon

前回はEventQueueを使った2つの仕事の並行処理例でした。今回はThreadを使ってほぼ同じ仕事を書き直してみます。プライオリティがないEventQueueと比べると、Threadはプラオリティ制御もできて、クリティカルな制御が可能なのだと思います。RTOSのカーネルのお陰。RTOS的にはこちらの方が「本流」でしょうか。

Mbed OSではArm純正のWeb環境にもお世話になっておりますが、今回もPC上の以下の環境でビルドしています。

VSCode + PlatformIO

冒頭のアイキャッチ画像に上記環境でのプロジェクトウイザードでの設定画面を掲げました。

ビルドの速さという点であると、Arm純正のWeb環境はとっても高速です。あっという間にビルドが終わりオブジェクトがダウンロードできるようになります。それに対して上記環境(PlatformIO)でのMbedOSの初回ビルドは全てのライブラリをコンパイルして環境を整えるところから始まるのでとても時間がかかります。一方、PlatformIOは、オブジェクトのアップロード、シリアル・モニタ、デバッグなどをまとめて面倒みてくれるのでとても楽。まあ、お好み次第、併用も可というところですかね。

Mbed OS6、スレッドに関するドキュメント

FreeRTOSでは task と呼ばれていた処理単位は、Mbed OS6 では Thread です。どちらもCPU資源のイメージを内包した処理単位だと思います。PC上でProcess/Threadというとメモリ空間的には明確な違いがありますが、こちらは仮想記憶などないマイコン上での実装です。メモリ的な差がどこまであるのかはソース読んでないので不明。状態遷移については異なるものの、似ていると言えば似ている気もします(個人の感想です。)

Mbed OS6のThreadに関するドキュメントは以下です。

Arm Mbed  Thread

サンプルソースコード

前回のイベントキューを使って、「プリエンプティブでない」「イベントドリブンな」マルチタスクをやってみたコードをもってきて、「プリエンプティブ」なThreadで書き換えました。

やっている仕事そのものは、2端子の「ビット・バンギング」です。周期的にオン・オフを繰り返すだけ。その周期を外部のオシロで測定すれば、ソフトウエアで設定している周期がどのくらい「守られている」のかが分かるという塩梅。

Threadは本当はプライオリティとか、割り当てるスタックサイズとか調整できるのですが、今回は成り行きのままデフォルトです。

また本来はクリティカルなThread処理とはそぐわない STDIOつかった printfをmain()関数内で使ってしまっています。

なお、MbedOS6では、main()関数もまたThreadとして制御できるみたいです。この辺、RTOSのスケジューラを起動するとmain()には二度と帰ってこないFreeRTOSとはmain()の扱いが異なるみたい。

#include <mbed.h>
#include <stdio.h>
using namespace std::chrono_literals;

DigitalOut led1(LED1);
DigitalOut pa_6(PA_6);
DigitalOut pa_7(PA_7);
Thread threadPA6;
Thread threadPA7;


void togglePA6() {
  while (true) {
    pa_6 = !pa_6;
    ThisThread::sleep_for(1ms);
  }
}

void togglePA7() {
  while (true) {
    pa_7 = !pa_7;
    ThisThread::sleep_for(2ms);
  }
}

int main() {
  threadPA6.start(togglePA6);
  threadPA7.start(togglePA7);
  while(1) {
    printf("Mbed OS %d.%d Thread Sample PGM 000.\n",MBED_MAJOR_VERSION, MBED_MINOR_VERSION);
    led1 = !led1;
    ThisThread::sleep_for(5s);
  }
}
実行結果

オシロスコープでみたPA6端子(C1黄色)とPA7端子(C2青色)の「ビットバンギング」の様子です。今回は、前回より周期を短くしてPA6は1msトグル、PA7は2msトグルとしています。トグルなので観測される周期はその倍の筈。実際、値はピッタリでした。なかなか。

Measure
ただ、観察していると5秒に1度ほど、上記の綺麗な周期が乱れる瞬間があるように思われました。main()関数に制御が戻って、以下のOSバージョンを含むグリーティングメッセージを送出する瞬間じゃないかと想像します。クリティカルなハードウエアの制御をする場合にはSTDIOなど使わんほうが良いでしょうな。それともプライオリティを下げたら反応変わるか?

STDIO
Thread使って一応マルチで動作できたみたいです。次はプライオリティなど使っても少し細かく制御してみたいと思います。

モダンOSのお砂場(34) Mbed OS6、EventQueueを使ってみる へ戻る

モダンOSのお砂場(36) Mbed OS6、InterruptInを使う。STM32 へ進む