ESP32でマルチタスクを行う為の、とりあえずここまで判った事 by freeRTOS 10タスク目 [ESP32]
現在実用ガイドを読みながら編集中、、、書いて有る事を信用しない様に!
http://www.profdong.com/elc4438_spring2016/USINGTHEFREERTOSREALTIMEKERNEL.pdf
ESP32はRTOSができるらしい、、、
2.4 WORKING WITH LARGE DATAについて解説
データキューの項目の最後に、大きなデータの扱いについてちょっと書かれている。
しかしここで言っている事は別段大きなデータだけで発生する話ではない。タスク間でデータの通信をしたり、メモリを共有する際には必ず出てくる話。
まず、データキューを使って大きなデータを転送するのはあまりお勧めではない感じで書かれている。
とは言えデータキューはA/Dコンバーターのデータを別のタスクに転送するなどの目的にはとてもいい感じで使える。
しかしSDカードなんかは、1byte単位でSDカードにアクセスするよりも、512byte単位でアクセスした方が遥かに効率が良い。
ブロック単位でデータを取り扱う時、どうすれば効率良く、しかも安全に転送可能か?
データをコピーして相手に渡す場合と、参照渡しの場合について考えてみる。
(1) データをコピーして渡す
長所は、複製ができるのでその複製をどんなにいじっても元のデータには影響しない。相互に影響を及ぼさない。
短所は、一時的でもデータ領域が2倍必要となり、また大きなデータであればメモリ/メモリ間コピーが大量に発生し、CPUへの負担になる事もある。
データキューは、キューに書く時と、読む時の2回コピーが行われる。
PCの様にCPUパワーがやたらとあってメモリも大盛りであれば、データコピーの負荷なんてまったく気にしないであろう。しかし組み込みではCPUパワーもメモリも限られるので、その辺は考えどころである。
(2) データのポインターを渡す(参照渡し)
長所は、最低限の交換で大きなデータを取り扱える。
短所は、メモリそのものは共有している為に、お互いにその領域にアクセスする手順を決めて置かなければ、間違ったデータを相手に渡してしまう。
ちょうどここでやった例である。
http://hamayan.blog.so-net.ne.jp/2018-02-20
この例では参照渡しを使ったが、データを正しく扱う手順が間違っていたために、受け取る側がデータを使う前に内容が破壊された。
〇大きなデータを通信する1つの例
いろいろな方法で可能だと思うが、1つの例として、
(1) データを送る側がHEAP領域から領域を取得する。
(2) データを送る側は取得した領域のポインターを、データキューで相手に転送する。
(3) データを受け取る側はデータキューからポインターを受け取る。
(4) データを受け取った側は、その領域が不要になったら、HEAP領域に返す。
※データを送った側は、送った後は決してその領域を触らない事。
※決してスタック(自動変数)を相手に渡さない事。
https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/ESP32freeRTOS_TASK_ID_010
http://www.profdong.com/elc4438_spring2016/USINGTHEFREERTOSREALTIMEKERNEL.pdf
ESP32はRTOSができるらしい、、、
2.4 WORKING WITH LARGE DATAについて解説
データキューの項目の最後に、大きなデータの扱いについてちょっと書かれている。
しかしここで言っている事は別段大きなデータだけで発生する話ではない。タスク間でデータの通信をしたり、メモリを共有する際には必ず出てくる話。
まず、データキューを使って大きなデータを転送するのはあまりお勧めではない感じで書かれている。
とは言えデータキューはA/Dコンバーターのデータを別のタスクに転送するなどの目的にはとてもいい感じで使える。
しかしSDカードなんかは、1byte単位でSDカードにアクセスするよりも、512byte単位でアクセスした方が遥かに効率が良い。
ブロック単位でデータを取り扱う時、どうすれば効率良く、しかも安全に転送可能か?
データをコピーして相手に渡す場合と、参照渡しの場合について考えてみる。
(1) データをコピーして渡す
長所は、複製ができるのでその複製をどんなにいじっても元のデータには影響しない。相互に影響を及ぼさない。
短所は、一時的でもデータ領域が2倍必要となり、また大きなデータであればメモリ/メモリ間コピーが大量に発生し、CPUへの負担になる事もある。
データキューは、キューに書く時と、読む時の2回コピーが行われる。
PCの様にCPUパワーがやたらとあってメモリも大盛りであれば、データコピーの負荷なんてまったく気にしないであろう。しかし組み込みではCPUパワーもメモリも限られるので、その辺は考えどころである。
(2) データのポインターを渡す(参照渡し)
長所は、最低限の交換で大きなデータを取り扱える。
短所は、メモリそのものは共有している為に、お互いにその領域にアクセスする手順を決めて置かなければ、間違ったデータを相手に渡してしまう。
ちょうどここでやった例である。
http://hamayan.blog.so-net.ne.jp/2018-02-20
この例では参照渡しを使ったが、データを正しく扱う手順が間違っていたために、受け取る側がデータを使う前に内容が破壊された。
〇大きなデータを通信する1つの例
いろいろな方法で可能だと思うが、1つの例として、
(1) データを送る側がHEAP領域から領域を取得する。
(2) データを送る側は取得した領域のポインターを、データキューで相手に転送する。
(3) データを受け取る側はデータキューからポインターを受け取る。
(4) データを受け取った側は、その領域が不要になったら、HEAP領域に返す。
※データを送った側は、送った後は決してその領域を触らない事。
※決してスタック(自動変数)を相手に渡さない事。
https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/ESP32freeRTOS_TASK_ID_010
volatile SemaphoreHandle_t sema; volatile xQueueHandle que; struct DATA_QUEUE_STRING_MESAGE { const char *msg; unsigned long size; }; void setup() { Serial.begin( 115200 ); Serial.print( "FreRTOS Test. " ); Serial.printf( "ESP32 Chip Revision: %d\r\n\r\n" , ESP.getChipRevision() ); // Create semaphore. sema = xSemaphoreCreateBinary(); // xSemaphoreGive( semaPhotoShot ); /* give the count for semaPhotoShot */ // Create data queue. que = xQueueCreate( 5, sizeof(struct DATA_QUEUE_STRING_MESAGE) ); /* */ xTaskCreatePinnedToCore( recieveTask, "", configMINIMAL_STACK_SIZE * 2, NULL, 2, NULL, 1 ); } void loop() { static int count = 0; /* wait semafor */ xSemaphoreTake( sema, portMAX_DELAY ); /* transmit message through data queue. */ struct DATA_QUEUE_STRING_MESAGE *queMsg = new struct DATA_QUEUE_STRING_MESAGE; String str = "data queue transmit/recieve test. " + String( count++ ) + "\r\n"; char *msg = new char[ str.length() ]; memcpy( msg, str.c_str(), str.length() ); queMsg->msg = msg; queMsg->size = str.length(); xQueueSendToBack( que, (const void *)&queMsg, 0 ); vTaskDelay( pdMS_TO_TICKS( 1 * 1000UL ) ); /* about 1 seconds. */ } /*************************************************************************/ /* task */ /*************************************************************************/ void recieveTask( void *execParam ) { while( 1 ) { xSemaphoreGive( sema ); struct DATA_QUEUE_STRING_MESAGE *queMsg; xQueueReceive( que, (void *)&queMsg, portMAX_DELAY ); Serial.write( (const uint8_t *)queMsg->msg, queMsg->size ); delete[] queMsg->msg; delete queMsg; } }
ITRONプログラミング入門 H8マイコンとHOSで始める組み込み開発
- 出版社/メーカー: オーム社
- 発売日: 2005/04/23
- メディア: Kindle版
リアルタイムOSと組み込み技術の基礎―実践μITRONプログラミング (TECHI (Vol.17))
- 作者: 高田 広章
- 出版社/メーカー: CQ出版
- 発売日: 2004/02
- メディア: 単行本
2018-02-21 13:56
nice!(0)
コメント(0)
コメント 0