ESP32で円形POV(バーサライタ)を作る④(SDカードとマルチコアを使った動画表示編)

ESP32

ESP32で円形POVを作るシリーズの最終回、目標であるPOVでSDカードの動画を流します。

動画ファイルの形式について

前回の記事で連続したBMPファイルを連続して読み込むことに成功しました。そのため、今回もBMPファイルをたくさん用意してそれをパラパラ漫画のように表示する方式を取ります。
POVの特徴として、回転数=リフレッシュレートということがあります。つまり回転数以上のフレームレート(fps)は出ないこととなり、例えば毎秒20回転の時は20fpsかそれ以下になります。じゃあ、fpsが回転数よりも下がるのはどういう場合かというと、SDカードから1枚の画像を読み込む時間が1/回転数(秒)に満たない場合になり、ここで画像のデータサイズとSDカードの読み込みスピードがどれくらいかがポイントになります。画像のサイズが大きい場合やSDカードの読み込みスピードが遅い場合は画像を圧縮することで両方のスピードを上げることができます。圧縮はRGB565かjpgの形式で保存して読み込み、復号化することになります。(が、今回はBMPで十分余裕があるためやりません)

前回の記事↓

動画を変換するPythonプログラム

2回目の記事で画像ファイルを円形POV用に変換するプログラムを載せましたが、今回は動画ファイル(mp4)を変換するプログラムです。実行すると動画ファイルと同じ名前のフォルダが作成され、その中に「000000.bmp」から始まる連番BMPが保存されます。プログラム実行時に表示されるFPS(フレームレート)とFrame Count(フレーム数)は後ほどのArduinoプログラムで必要なのでメモしておきます。また、2回目と同様、「ガンマ補正値」「LEDの数」「動画ファイルのフォルダアドレス」「動画ファイル名(「.mp4」は入れない)」は環境に合わせて書き換えます。

今回お借りした動画

Arduinoプログラム

動画ファイル(連番BMP)が入っているフォルダ名は「BadApple_Color」、フレーム数は6578、FPSは30と元動画の情報を入力しています。6578/30 = 219秒 = 3分39秒の動画となります。

Arduinoプログラムの補足

基本的な流れは第3回の方を参照してください。ここでは変更した所を中心に補足の説明をします。

動画の読み込み

191-196行:回転の始点でSDカードの連番BMPを読み込みを開始することになるのですが、動画の再生を開始してから時間から現在のフレーム数を計算して次に読む画像の番号を算出しています(正確には次に読む画像の番号と前に読んだ画像の番号の差)。

145-149行:計算されたフレーム数から次のファイルを読みます。連番BMPなので、ファイル名を直接指定して開くこともできるのですがこれをするとフォルダ内のファイル名の検索の時間が発生し、後半の画像になるほど読み込みまでに時間がかかります。そのため、file.openNext()で次の番号のファイルを開くということを(次のフレームになるまで)連続して行うことでこの問題を解決しています。

SDカードの読み込み時間の検証。ファイル名をしていすると後半のファイルになるに連れてファイルを開く時間(FileOpen)が伸びている。

その他主な変更点

37,242-249行:前回、表示した画像が鏡写しになったので、その修正と回転方向(時計回り・反時計回り)の設定を追加しました。

165行:ウォッチドックタイマー(WDT)というものがあり、定期的にプログラムが動いているか監視しています。Core0ではこのWDTが働いており、While(1)で永久ループしている場合は定期的にdelay(1以上)を入れてその間にWDTに通信するということをしないとWDTエラーが発生してしまいます。Core1で動いているLOOPではWDTは働いていないようです。

256行:このyield()を入れないとCore1が動作しないため入れていますが、なぜうまく動かないのかは不明です。おそらく上記のWDTに絡んでいるように思われるのですが、WDTの関係のないCore1で発生し、しかもWDTへ影響しないと言われているyield()で解決するのかナゾです。分かる方いましたらコメントで教えてください。

動画の再生

回転が上がり切るまでの18秒付近までは(前回の回転数と次回の回転数が異なるため)画像が回転してしまいます。回転数がある程度安定してくると表示位置は固定されます。

時間計測

最後に描画時間についての結果です。「LED一個あたりの時間」は「一周あたりの平均時間」をLED数と分解能で割った値です。
LEDへデータを送るSendDataの時間とSDカードのデータを読み込むSDReadの時間が大きめになっているため、POVが高解像度化するとここら辺の時間がネックになります。SDReadについては画像の圧縮で解決できる上、読み込みが間に合わなくともフレームレートが落ちるだけなのですが、SendDataに関してはLEDのクロック性能で頭打ちになるので、より速いLEDを探すかLEDアレイを分割して信号をパラレルに送信する必要があります。ただパラレルで送信する場合はSPIが1つしか使えないので、SPIでなくダイレクトGPIO(10MHz)で接続する必要があり、5列以上繋げないとパラレルで高速化することはできません。

LED数:30 分解能:283
SPI:40MHz SD:24MHz
Initial
Core1
MemCopy
Core1
SendData
Core1
SDRead
Core0
Core1合計
一周あたりの平均時間[us]23876810,12413,68011,130
LED一個あたりの時間[ns]28901,1931,6111,311

コメント

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