あみらぼ

電子工作がメインのDIYもの作り雑記

ESP32-WROVERでLCDモジュールを使う!

さて、前回前々回でESP32-WROVERの使えるピンの確認と、(無理やり)自動書き込みができるようになったので、やっと本格的にWROVERを使うためのテストをしていきます。

 

まず、WROVERを使い始めた理由ですが、ゆくゆく作りたいもののために、まずLCDモジュールで画面をヌルヌル表示したい!という目的があったからです。

ただ、突然FFC接続のLCDモジュール単体を買っても、画面が出る前に挫折しそうな気がしたので、まずは練習用として、激安のArduinoシールドとしてのLCDモジュール基盤を買いました。

f:id:amilabo:20200306095735j:plain

  • 2.8インチ320x240 TFT液晶
  • 抵抗膜式タッチスクリーン付き
  • SDカードスロット付き
  • 3.3v用液晶モジュール直結の端子付き
  • 8bitパラレル接続(高速化のため、あえて非SPIを選択)
  • 1200円ぽっきり!

これだけの機能でこの価格であれば、練習用としては十分ですし、横の液晶モジュール直結の端子を使えれば、そのまま本番用にも使えそうです。(後々、様々な理由でこのLCDモジュールは本番用には使えないという事がわかるのですが…)

 

順番が前後しますが、WROVERを買う前に、このLCDシールドを買って、Arduino uno(の互換品)でテストをしていました。サンプルコードでは、画面全体の単色塗りつぶしに1fps程度かかっていましたが、最適化をいろいろして、最終的にarduino unoにシールドとして載せるのと、シリアル通信を行うのを諦めて、PORTBレジスタ1発書きで8ビットを送れるようにしたことで、15fps程度まで高速化する事に成功しました。

更に高速化する余地はまだ少しありそうでしたが、そうした所で、自分としてはarduino uno上ではこのLCDの使い道がありません。arduino側で描画用にLCDの全画素を保持するには、320x240x2=150KBのRAMが必要なのに対して、atmega328pのRAM容量はたったの2KBです。なので、毎フレーム全画素書き換えられても、できる事は、意味のない色やグラデーションを表示する事程度です。atmega328pで使う場合は、あくまで必要な個所を部分的にちょこっとずつ書き換えていく、という使い方になりそうです。そもそも、atmega328pはテストをするために使ったので、使い方がある程度わかったので十分です。そこで、全画素書き換えを実用にするため、WROVERを使い始めた、という次第です。

 

WROVERのSRAM512KBなので、全画素のバッファ(これからはVideoRAM:VRAMと呼ぶことにします)を、SRAM上に十分とれそうです。そのバッファを毎フレームクリア&描画して、LCDモジュールへの全画素転送!、を最低30fps、できたら60fpsで動かす事が当面の目標です。

まずは、理論値の計算ですが、16Mhzのatmega328pで15fps程度出せたので、240MhzのESP32では、単純計算で225fps出せそうです。どちらかというと、ESP32が早すぎてLCDモジュール側の受信速度の方がボトルネックになりそうです。LCDモジュールのドライバICのdatasheetによると、最短書き込みサイクルは66nsのようなので、8ビットパラレル転送だと、限界は約94fpsになります。16ビットパラレル転送の場合はその2倍の約188fpsになりそうです。ESP32側でさすがに16ピンは使いたくないので、8回路DラッチのICなんかを使えば、ピンを1本追加するだけで、16ビットパラレル転送ができそうです。その場合、1フレームの転送にかかる時間は1/188=5.3ms、60fpsを達成するのに必要な時間が、16.6msなので、転送に5.3msかかっても、11.3msは描画する時間に使えますね。8ビットパラレル転送でも6ms程度は描画時間がとれそうですし、VRAMをダブルバッファにして転送と描画をデュアルコアで別々にやれば、どんな場合も描画に16.6ms使えるので、60fpsでヌルヌル動かすの目標は結構余裕そうですね。と、思っていました…。

 

で、実装をを初めていきます。このLCDシールドの魅力的な所は、LCDモジュール直結の端子が用意されているところです。ここに、WROVERの各端子を繋げば、実質LCDモジュールを直接使ったようなテストが可能そうです。

f:id:amilabo:20200306105921j:plain


こんなピンアサインですが、RST端子が出ていません!

まぁ、コレは買う前から調べてわかっていたことで、RST端子は起動時に使う程度で、描画の高速化等とは無関係そうなので、RST端子は無理やりはんだ付けで引き出すか、シールドのピンに繋いでとりあえず使う事にします。

ただ、ここでちょっと不安に思い始めたことがあります。RST端子が無いことから、本当にこの端子を使ったテストがされているのか??ということです。Arduino側からの5Vを、双方向バスバッファのICで3.3Vに変換しているようなので、上記の端子は、LCDモジュールに直結されているだけではなく、バスバッファICの出力にもつながっていそうです。基盤を見ても両面が見えない事やICの裏に隠れた配線が見えないので、なんとかこの基盤らしい回路図が無いかを調べて、それらしいものを見つけました。

 

f:id:amilabo:20200306110924j:plain

悪い予感が的中です。

念のためテスターも使って確認しましたが、上記の端子はやはりLCDモジュールだけではなく、バスバッファの出力にも繋がっています。何がマズいかというと、バスバッファICの出力は入力に何かが繋がっているかいないかに関わらず、0Vか3.3Vが出力されているのです。なので、ここに外部からHIGHやLOWを出力したところで、LCDモジュールにその信号は伝わりません。それどころか、外部からの出力がそのまま3.3Vや0Vと直結される事で、回路がショートした状態となり、大電流が流れ、WROVERが一瞬でお亡くなりになってもおかしくないです。配線する前に調べておいて本当に良かった…。一応、読み込みの際にバスバッファの方向を変えるためにRDとDIRが接続されているので、RDをLOWにしておけばDB0~DB7は何とか使えそうです。一方で、下のバスバッファICのDIRやOE、VCCは固定で結線されてしまっているので、どうしようもありません。なので、CS、RS、WR、WDを使おうと思ったら、このICを剥がして、(0.65mmピッチの端子に)配線を行う必要がありそうです。少なくとも、手はんだで導線をはんだ付けする等は、間違いなく無理ゲーです。

DB0~DB7はWROVERと直結して、CS、RS、WD、RSTはしょうがないのでバスバッファを経由して接続しようかとも思いましたが、先程の計算にあるとおり、DBとWD等は、66nsとかのレベルでの時間の精度が要求されるので、バスバッファによる信号の遅延がかなり影響しそうで、その辺でバグがでると検証などが超絶大変そうなのでやめておいた方がよさそうです。

しかたないので、全端子、arduinoシールドの端子を使ってバスバッファを経由してLCDモジュールと接続する事にしました。バスバッファの遅延も、全端子がほぼ共通の時間で遅延するなら、恐らく問題にならないでしょう、という事で。

f:id:amilabo:20200306113006j:plain

結局、期待していたLCDモジュール直結用の端子は何だったのでしょうか?恐らく、配線はしてあるものの、実際にその端子を使ったテスト等はきっとしていないのではないかと思います。先に書いた通り、この端子を使うと、繋いだ側の機器が死亡する可能性があるので要注意です。WROVER単体なら、500円程度の損害で済むかもしれませんが、またあの配線をやるとなるとうんざりしますし、お高い開発キットなんかだと、そうとうショックを受けて絶望する気がします。

 

とにかく、事故る前に問題を発覚できたのは不幸中の幸いという事で。LCDとWROVERを繋ぐだけの話でかなり長くなってしまったので続きは次回