ESP32でマルチタスクを行う為の、とりあえずここまで判った事 by freeRTOS 8タスク目 [ESP32]
今回は実用ガイドからではなく、うっかり話
1タスク目( http://hamayan.blog.so-net.ne.jp/2018-02-16 )のこの例題
xTaskCreatePinnedToCoreでタスクを生成する時のタスク優先度を2以上にしないとうまく起動時引数が渡せなかった問題、あれを考えてみた。
もし生成するタスクの優先度が1であったら、、、
ESP Arduinoのsetupやloopは1つのタスクとして動いており、タスク名はloopTaskで優先度は1である。
つまりxTaskCreatePinnedToCoreでタスクを生成しているのは優先度が1のタスクである。
複数のタスクが同一の優先度を持つ時、同一の優先度を持つタスクの間でラウンドロビンが行われる。
実行時引数は一旦変数executeParameterに代入され、その変数へのポインターがledBlinkTaskに渡される。
つまり参照渡しである。もしledBlinkTaskがこの変数を使う前に内容が書き換えられてしまったら、、、そして実際にそれが起きてしまった。
loopTaskがledBlinkTaskを登録する関数を実行した場合、スケジューラーが起動して次にRUNNINGに入るタスクを決める。しかしloopTaskとledBlinkTaskは同一優先度であったので次のタイムスライスまでラウンドロビンは行われず、そのままloopTaskは実行される。executeParameterは自動変数であるから、場合によっては破棄される事も、再利用される事もある。
結果、起動時引数は破壊された。
ledBlinkTaskの優先度が2以上であれば、ledBlinkTaskを登録した時にスケジューラーによってledBlinkTaskはRUNNINGに遷移されるので、そのままexecuteParameterの内容を受け取れた。
優先度に依存しない様に正しく起動時引数を渡す為には、変数executeParameterをコンスタントな変数としておけば良い。
いや、いっその事以下の様にも、、、
10年経って自分のプログラムを見て、「なにやっているんだ?」ってならなければ。
1タスク目( http://hamayan.blog.so-net.ne.jp/2018-02-16 )のこの例題
TaskHandle_t taskHandle[1]; /* typedef void * TaskHandle_t; */ const int ledPin = 2; void setup() { Serial.begin( 115200 ); /* configure led blink task. */ unsigned long executeParameter = 1000UL; /* delay time */ xTaskCreatePinnedToCore( ledBlinkTask, /* task name */ "ledBlinkTask", /* task name string */ 1024, /* stack size */ &executeParameter, /* execute parameter */ 2, /* task priority : 0 to 24. 0 is lowest priority. */ &taskHandle[0], /* タスクハンドルポインタ */ 1 /* core ID */ ); } void loop() { Serial.println( "hello world." ); delay( 1000 ); } /* led blink */ void ledBlinkTask( void *execParam ) { unsigned long dly = *(unsigned long *)execParam; pinMode( ledPin, OUTPUT ); digitalWrite( ledPin, LOW ); /* turn off led. */ while( 1 ) { digitalWrite( ledPin, ( digitalRead(ledPin) ) ? LOW : HIGH ); /* toggle led. */ delay( dly ); } }
xTaskCreatePinnedToCoreでタスクを生成する時のタスク優先度を2以上にしないとうまく起動時引数が渡せなかった問題、あれを考えてみた。
もし生成するタスクの優先度が1であったら、、、
ESP Arduinoのsetupやloopは1つのタスクとして動いており、タスク名はloopTaskで優先度は1である。
つまりxTaskCreatePinnedToCoreでタスクを生成しているのは優先度が1のタスクである。
複数のタスクが同一の優先度を持つ時、同一の優先度を持つタスクの間でラウンドロビンが行われる。
実行時引数は一旦変数executeParameterに代入され、その変数へのポインターがledBlinkTaskに渡される。
unsigned long executeParameter = 1000UL; /* delay time */ ・ ・ ・ &executeParameter, /* execute parameter */
つまり参照渡しである。もしledBlinkTaskがこの変数を使う前に内容が書き換えられてしまったら、、、そして実際にそれが起きてしまった。
loopTaskがledBlinkTaskを登録する関数を実行した場合、スケジューラーが起動して次にRUNNINGに入るタスクを決める。しかしloopTaskとledBlinkTaskは同一優先度であったので次のタイムスライスまでラウンドロビンは行われず、そのままloopTaskは実行される。executeParameterは自動変数であるから、場合によっては破棄される事も、再利用される事もある。
結果、起動時引数は破壊された。
ledBlinkTaskの優先度が2以上であれば、ledBlinkTaskを登録した時にスケジューラーによってledBlinkTaskはRUNNINGに遷移されるので、そのままexecuteParameterの内容を受け取れた。
優先度に依存しない様に正しく起動時引数を渡す為には、変数executeParameterをコンスタントな変数としておけば良い。
static const unsigned long executeParameter = 1000UL; /* delay time */ ・ ・ ・ (void *)&executeParameter, /* execute parameter */
いや、いっその事以下の様にも、、、
(void *)1000, /* execute parameter */ ・ ・ ・ unsigned long dly = (unsigned long)execParam;
10年経って自分のプログラムを見て、「なにやっているんだ?」ってならなければ。
const int ledPin = 2; void setup() { Serial.begin( 115200 ); pinMode( ledPin, OUTPUT ); digitalWrite( ledPin, LOW ); /* turn off led. */ #if 1 /* configure led blink task. */ // static const unsigned long execParam1 = 257UL; xTaskCreatePinnedToCore( ledBlinkTask, /* task name */ "ledBlinkTask 01", /* task name string */ 1024, /* stack size */ (void *)257, /* execute parameter */ // (void *)&execParam1, /* execute parameter */ 1, /* task priority : 0 to 24. 0 is lowest priority. */ NULL, /* task handle pointer */ 1 /* core ID */ ); #endif #if 1 // static const unsigned long execParam2 = 149UL; xTaskCreatePinnedToCore( ledBlinkTask, /* task name */ "ledBlinkTask 02", /* task name string */ 1024, /* stack size */ (void *)149, /* execute parameter */ // (void *)&execParam2, /* execute parameter */ 1, /* task priority : 0 to 24. 0 is lowest priority. */ NULL, /* task handle pointer */ 1 /* core ID */ ); #endif } void loop() { } /* led blink */ void ledBlinkTask( void *execParam ) { unsigned long dly = (unsigned long)execParam; // unsigned long dly = *(unsigned long *)execParam; Serial.print( "dly = " ); Serial.println( dly,DEC ); while( 1 ) { digitalWrite( ledPin, ( digitalRead(ledPin) ) ? LOW : HIGH ); /* toggle led. */ delay( dly ); } }
ITRONプログラミング入門 H8マイコンとHOSで始める組み込み開発
- 出版社/メーカー: オーム社
- 発売日: 2005/04/23
- メディア: Kindle版
リアルタイムOSと組み込み技術の基礎―実践μITRONプログラミング (TECHI (Vol.17))
- 作者: 高田 広章
- 出版社/メーカー: CQ出版
- 発売日: 2004/02
- メディア: 単行本
2018-02-20 22:39
nice!(0)
コメント(0)
コメント 0