2018年9月28日金曜日

mbed OS 5のThread

mbed OS 5のThreadについて以下の記事を参考にしました。

Docs › Reference › RTOS › RTOS overview
https://os.mbed.com/docs/v5.9/reference/rtos.html

Docs › Reference › RTOS › Thread
https://os.mbed.com/docs/v5.9/reference/thread.html

Mbed OS 5のRTOSはMutexやSemaphoなど小難しいものがありますが、Thread間でメモリなどのリソースを競合せずに共有するための仕組みで、使わなくて済むならそれに越したことはありません。

というわけで、まずはThreadだけ試してみました。

Docs › Reference › RTOS › Thread」のExampleをNucleo F446RE用に多少書き換えました。

ブレッドボード配線図

Thread example


#include "mbed.h"
 
DigitalOut led1(D2);
DigitalOut led2(D3);
Thread thread;
 
void led2_thread() {
    while (true) {
        led2 = !led2;
        wait(1);
    }
}
 
int main() {
    thread.start(led2_thread);
    
    while (true) {
        led1 = !led1;
        wait(0.5);
    }
}

led1の点滅はメイン・ループで行われ、led2の点滅は生成したスレッドで行われます。おおざっぱにいうと、メインループとは独立して、生成したスレッドが勝手にled2を点滅させているイメージです。

Thread example with callbacks

引数を1つ取るコールバック関数を使った例です。引数によってThreadの開始の仕方(State)を変えられます。この例ではどのLEDを点滅させるかを、Threadの開始時に指定しています。


#include "mbed.h"

Thread thread;
DigitalOut led1(D2);
DigitalOut led2(D3);

volatile bool running = true;

// Blink function toggles the led in a long running loop
void blink(DigitalOut *led) {
    while (running) {
        *led = !*led;
        wait(1);
    }
}

// Spawns a thread to run blink for 5 seconds
int main() {
    thread.start(callback(blink, &led1));
    wait(10);
    running = false;
    thread.join();
 
    thread.start(callback(blink, &led2));
    wait(10);
    running = false;
    thread.join();
 
}

LED1が10秒間(5回)点滅したあと、LED2が10秒間(5回)点滅し、プログラムは終了します。thred.join()はLEDを点滅させるスレッドが終了するのを待ちます。

OLED表示とADC読み取りをThread化


実験中のNucleo DCOでやっているOLED表示とADC読み取りをThread化し、DAC出力はTickerのままでテストしました。

DAC出力は波形生成を行っていてタイミングにシビアで、RTOSを使った場合ミリ秒単位(最大1kHz)でしか制御できないため、マイクロ秒単位で制御できるTickerを使用しています。

ブレッドボード配線図

メインループでのポーリング(mbed-cli)
https://github.com/ryood/Mbed_OS_5_Thread/tree/master/mbed/Thread_Test03

メインループ内でADC読み取りとOLED表示を逐次処理して、TickerでDACからサイン波を出力しています。

ADC読み取りとOLED表示をThread化(mbed-cli)
https://github.com/ryood/Mbed_OS_5_Thread/tree/master/mbed/Thread_Test04

ADC読み取りとOLED表示をThread化し、Thread::set_priority()でADC読み取りの優先順位を高、OLED表示を低に設定しました。

優先順位は以下の通りです。

0 波形生成  Ticker
1 ADC読み取り Thread(priority:高)
2 メインループ Thread(priority:普通) LED点灯
3 OLED表示 Thread(priority:低)

ADC読み取りとOLED表示のタイミング

メインループでのポーリング

ch1:D3(OLED表示) ch2:D4(ADC読み取り)

それぞれの処理の最初と最後でピンの出力をH/Lしています。OLED表示(赤色)に0.133秒かかってその後にADC読み取り(黄色)が一瞬行われています。

この場合ADC読み取りはOLED表示の完了を待つため、サンプリング周期が長くなり、POTを回すと出音が段階的な変化になりました。口でいうと「ポ、ポ、ポ、ポ・・・」という感じ。

Thread化

ch1:D3(OLED表示) ch2:D4(ADC読み取り)

Thread化した場合、OLED表示(赤色)がHになっている間にもADC読み取り(黄色)が行われています。こちらはPOTを回すとなめらかに変化しました。口でいうと「プーーーーーーン」という感じ。

波形生成Tickerのタイミング


メインループでのポーリング

ch1:D2(波形生成) ch2:D4(ADC読み取り)

Thread化

ch1:D2(波形生成) ch2:D4(ADC読み取り)

Thread化した場合、ADC読み取り(黄色)の間隔が詰まっています。どちらの場合も波形生成のTicker割り込み(赤色)が優先されていて、50kHzのサンプリングレートがキープできています。

DAC出力波形


メインループでのポーリング

ch1:D2(波形生成) ch2:A2(出力波形)

Thread化

ch1:D2(波形生成) ch2:A2(出力波形)

ch1のデジタル波形がオシロ内で干渉してサイン波の表示が汚くなっていますが、1kHzのサイン波が出力できています。

メモ:


Tickerの様に使えるRtosTimerは非推奨になり、EventQueueが推奨されています。←機能が多いのでちょっとめんどくさそう。

https://os.mbed.com/docs/v5.9/reference/rtostimer.html

0 件のコメント:

コメントを投稿