M5StackとM5CameraでWiFi, UDPによる動画転送を長時間連続安定動作させる実験

M5StackとM5CameraでWiFi,UDPで長時間安定して動画転送できた M5Stack

長時間連続稼働させるとフリーズする問題について

M5StackやESP32で、外部デバイスと通信する時、1分間に1度送受信するくらいならば長時間動かしても24時間以内でフリーズすることは滅多に無いかも知れません。
でも、今回はイメージセンサOV2640からのカメラ画像データを、ESP32がDMA(Direct Memory Access)で絶え間なく連続受信させていて、その多量の画像データをWiFi UDPで、M5Stackへ高速で連続転送しています。
1秒間に10回?くらい、画像データ1フレーム(200pixel x 2byte x 148 pixel = 59.2KB)を飛ばしています。
今まで私が過去にプログラミングしたものの中で最も高速で大量の連続WiFi通信です。
そして、受信側M5StackのLCDディスプレイに動画で24時間以上フリーズせずに表示し続けることができるかというところが今回の問題点です。

実は、前回の記事では8時間経過後にフリーズすることがわかったんです。
そして、なぜか、M5Camera側のUDP送信だけがフリーズしたんです。
M5Camera側のUDP受信は正常に動作していました。
Arduino IDEのCore Debug Levelをverboseにしても、シリアルモニタに何もエラー表示が出ませんでした。
これは謎だらけだったんです。

ESP32のWiFi送信アンプの温度超過かも?

このフリーズについて、Twitterでつぶやいていると、 @Seg_Faul さんや、@tnkmasayuki さんからESP32の無線送信アンプの温度超過が問題かもというヒントを頂きました。

M5StackもM5Cameraもボティーがそれ程熱くなっていないから、それは違うのではないかと思いました。
でも、確かに今まで私が作ってきた電子工作やプログラミングの中で、WiFiでデータを無線送信する量と頻度は圧倒的に多く、格段にチップを発熱させているだろうと想像できたので、ESP32のCPU温度をモニターしながら長時間稼働実験してみました。

Arduino core for the ESP32プログラミングでは、残念ながらWiFi送信アンプの温度のモニターはできませんでしたが、幸いにCPUの温度を返す関数がありました。
以下の関数です。

temperatureRead();

これの使い方は後で述べますが、リアルタイムでESP32のCPU温度をモニターできて、都合が良いです。
それでまず判ったことは、WiFi UDP受信側のM5StackのCPU温度が65℃を超えるとフリーズすることが判りました。
これは、なんと、送信側ではなく、受信側のM5Stack側のCPUがフリーズしました。

ん? でもおかしいぞ???

M5Camera側のWiFi UDP送信側のCPU温度はそんなに上がっていないぞ・・・?
送信側の方が圧倒的にCPUの負荷は大きいはずなのに・・・、なぜ?

そして、不思議なことが起こりました。
WiFi UDP受信側でCPU温度モニターを利用して、65℃近辺になったら送信側のM5CameraにWiFi通信停止コマンドを送って、UDP送信をストップするようにしました。
ところが、なぜか受信側M5StackのCPU温度が上がり続けたんです。
そして、65℃を超過してフリーズしてしまいました。
送信側で、udp.stop(); を実行してもダメでした。

意味わからん!

これは、どうやらESP32のWiFiの送受信に関しては、裏で常に動いているプログラムがあって、送信ストップしても常に裏で送受信し続けているようです。
これについては正直言って私は良く知りませんので、原因は突き止められませんでした。

そして、M5StackやM5CameraのESP32のCPU温度は、部屋の気温にかなり左右されるということも分かりました。

今年の10~11月の気温が高めで部屋のエアコンを入れたり切ったりしていたので、その都度、ESP32のCPU温度が影響を受けていました。
部屋に暖房を入れて、M5CameraやM5Stackを動作させると、あっという間にCPU温度が65℃を超えてフリーズしました。

以上からお分かりの通り、CPU発熱によるフリーズを防ぐ方法はただ一つ?!

冷却ファンを使う事!

かな? という個人的結論に至りました。
プログラミングで間引き通信をしたり、定期的に休ませてCPU発熱を抑えながら連続運転するという方法もありますが、今回の実験ではフルパワー動作でどこまでできるかということの実験です。
それなら冷却ファン一択かなと思います。

残念ながら、M5Stackにはオプションの冷却ファンモジュールというものは単体で売っていませんでした。
冷却ファンの対処方法については有効な手段がありました。
これについては後で紹介します。

さて、M5StackとM5Camera側に冷却ファンを付けて、CPU温度は60℃以下にキープしたとして、実は、それでも8時間経過後にWiFi UDPの送信側だけがフリーズしてしまったんです。
ということは、WiFi送信アンプの温度超過だけではないことが判りました。

ウォッチドッグタイマ動作を無効にしたことが原因かも?

CPU温度以外の要因となると、ウォッチドッグタイマ動作を無効にしていることかな? と疑いました。
実は、前回記事のプログラミングでは、M5CameraのイメージセンサOV2640からDMA制御で受け取る画像データを受け取る場合、ウォッチドッグタイマ(WDT)を無効にしないと、スムースな動画として表示させることができませんでした。
ウォッチドッグタイマ動作を無効にする関数はこれです。

disableCore0WDT(); //core 0 のWDT無効

そして、DMA動作はESP32のCPU core 0で連続稼働させていました。

そこで、ウォッチドッグタイマ(WDT)を有効にして、無限ループ内にdelay(1); を入れて、WDTを定期的にリセット動作するようにしました。

そうすると、フレームレートが3fpsくらいに落ちて、M5Stack側の動画表示がカクカクしてしまいました。

でも、これで冷却ファンも含めて連続稼働させると、24時間稼働しても問題ありませんでした。
WiFi UDP送信のフレームレートによるかも知れませんが、ウォッチドッグタイマ動作は有効にすべきかな? と思うようになりました。
実際、後で紹介するコードでWDT有効にして動作させると、具合が良かったです。

WiFi UDP 大量データ連続送受信で使うCPU core は0か1か、どちらが良い?

先ほど述べたように、M5StackやM5CameraのESP32のWiFi関連プログラムは、裏でCPU core 0で動作していることのようです。
すると、前回記事のプログラミングでは、M5CameraのイメージセンサOV2640からの画像データDMA制御は、CPU core 0で行っていました。
そうすると、何かしらの動作のバッティングが考えられました。

そこで、イメージセンサとのDMA制御はCPU core 1のメインloop内で制御し、WiFi UDP送受信は CPU core 0 で動作させることにしました。

でも、メインloop()関数内でDMA制御させると、ウォッチドッグタイマが有効になっている為に、動画表示のフレームレートが上がりません。

Twitterで、@tnkmasayukiさんと@wakwak_kobaの情報から、CPU core 1 のloop()関数内は、デフォルトでウォッチドッグタイマ動作無効となっていることが判明しました。
ずーっとWDT有効と思い込んでいました。
大変失礼しました。
(2019/12/18)

 

それで、いろいろ調べているうちに、Arduino core for the ESP32のsdkconfig.hに以下の定義を見つけました。

#define CONFIG_CAMERA_CORE1 1

これはv1.0.4の場合です。
CONFIG_CAMERA_COREという定義はこの1行だけしか無いので、個人的な想像では、Arduino coreの開発チームがカメラデバイスのDMA制御はcore 1でやった方が良い、という判断かな?・・・と思いました。(たぶん・・・。)

情報誌Interface 2020年1月号の記事の記事によると、DMAはcore 1が良いらしい

よくお世話になっているマイコン関連情報誌、CQ出版社のInterface 2020年1月号では、ESP32やM5Stack関連の情報が今までになく豊富で濃い内容になっていて、個人的にお勧めです。

Interface(インターフェース) 2020年 01 月号
CQ出版
¥1,180(2024/04/18 21:37時点)

特に、107ページ第3部 第4章
「ESP32リアルタイム処理の研究」
を注意深く読んでみてください。
今回の問題の解決の糸口が書かれています。
この記事は今の私にとっては正にピッタリの記事でした。
ESP32 のcore 0とcore 1で速度比較されていて、とてもよく解りますね。

これによると、シビアなタイミング処理はcore 1(APP_CPU)で動作させた方が良いとのことでした。

このことから、シビアなDMA制御をcore 1のメインloopで処理し、WiFi UDPはcore 0で制御した方が良いという判断になりました。

ウォッチドッグタイマを有効にすると、イメージセンサDMA制御のフレームレートが下がってしまう?

では、ウォッチドッグタイマを有効にして、DMA制御をメインloop内でやるとして、フレームレートを上げるにはどうしたらよいか、いろいろ試行錯誤しました。
ウォッチドッグタイマ監視をするためには、ループ内に最低delay(1)を入れねばなりません。

前回記事のプログラミングでは、ESP32-Cameraライブラリを解体して、VSYNC(垂直同期)信号については独自にポーリングでGPIOレベルを検知していました。
これでは、delay(1)が入るとレベル検知が間に合いません。

そこで、基本に立ち返って、本家のESP32-Cameraライブラリを再度見直してみると、やはりVSYNC(垂直同期)信号は「割り込み」制御されていました。

私は、DMA制御だけを「割り込み」にしていて、VSYNCはポーリングで良いかなと思っていましたが、それは間違いだったみたいですね。

ということで、ESP32-Cameraライブラリに習って、VSYNC(垂直同期)信号も「割り込み」制御にしたら、見事! 画像表示のフレームレートが上がりました!!!

delay(1)が入ってウォッチドッグを動作させていても、「割り込み」制御については別タスクで行われるらしいですね。

これで「割り込み」制御というものの有効性がハッキリ理解できました。
プロの組み込み開発者からすれば当たり前のことかも知れませんけど・・・。

コメント

  1. macsbug より:
    • mgo-tec mgo-tec より:

      macsbugさん

      コメントいただき、ありがとうございます。

      そのファンは以前Twitterで情報を頂いたんですが、その時は単体では売っていませんでした。
      今はもう単体で売っているんですね。
      私はAliexpressは使ったことが無いので、いつかAmazonかスイッチサイエンスさんで販売してほしいなぁ・・・と願って待っています。
      いつも有益な情報ありがとうございます。
      m(_ _)m

タイトルとURLをコピーしました