MicroPythonのREPLをTFT LCDに出力する


昨日、小型TFT LCDのST7735、MicroPython用ドライバにスクロール機能を追加しましたが、その目的はこのLCDでFBConsoleを動かしてみることです。

FBConsoleは、MicroPythonのフレームバッファクラスのディスプレイデバイスに、MicroPythonのターミナルを出力するためのクラスです。
これまでもOLEDのSSD1306Raspberry Piの画面にターミナルを表示するために使ってきました。

実際には、FBConsoleはフレームバッファに限らず、以下のAPIを持つグラフィックディスプレイであれば利用可能です。

・fill(self, color) --- 画面をcolorで塗りつぶす(画面消去用)
・fill_rect(self, x, y, w, h, color) --- 塗りつぶした矩形を描く(行消去用)
・scroll(self, dx, dy) --- dyピクセル縦スクロールする(横スクロールは不要)
・hline(self, x, y, w, color) --- 水平線を描く(カーソル表示用)
・text(self, c, x, y, color) --- 1文字描く

ST7735ドライバには、これまでスクロール機能が欠けていたのですが、前回追加しましたので必要条件は満たしています。

ただ、関数の形式がこのドライバと上記のAPIで若干異なっています。
たとえば上記のAPIではXY座標はそれぞれ別のパラメータで渡しているのに対して、ST7735ドライバは(X,Y)というタプルで渡すようになっています。

そこで、両者の橋渡しをするラッパークラスを作ってみました。
コードは、以下のFBConsoleのリポジトリに置いてあります。

FBConsole/ST7735fb.py at master · boochow/FBConsole

処理内容はAPIの差分吸収と、スクロール関連の計算です。
FrameBufferクラスは、スクロールは実際にフレームバッファ上のデータをコピーします。

一方、ST7735では一種の座標変換をするだけで、データは移動しません。
REPLで画面最下行で改行すると、1行分スクロールして、画面最下行を消去するという処理が必要になります。
画面最下行の領域を表す座標は、FrameBufferクラスでは常に一定ですが、ST7735ではスクロールの設定値に合わせて変化します。
このため、スクロール値を記憶して、画面上の座標を実際の座標(アドレス)に変換しています。

使い方は以下のようになります。
前回と同じく、ESP32での例です。結線も同じです。


まず、普通にTFT LCDドライバのオブジェクトを作成します。

次に、スクロールの設定をします。
ST7735Sのフレームバッファは縦162ピクセル、実際に表示できるのは160ピクセルなので、
トップとボトム1ピクセルずつ(スクロールしていない状態のときは表示されないピクセル)をスクロール領域から除外します。
そして、これをラッパークラスST7735fbでくるみます。

そして、さらにそれをFBConsoleに渡します。
最後にos.dupterm()を呼び出してREPLを出力させます。

duptermを終了するときは、dupterm(None)を実行します。

なお、FBConsoleから使用するには文字表示の速度が遅かったので、これもST7735ドライバ側で改善しました。
改善前は、フォントデータのドット一つ一つについて、オンなら1ピクセル描画、という処理をしていたので遅かったのですが、これを1文字分のイメージを作成してまとめてLCDに転送するように変更しました。
高速というわけではないのですが、REPL程度ならまあまあ使える速度になりました。

また、MicroPythonのFrameBufferで文字表示するときに使われている「petme128」というフォントを使えるようにしました。
これもFBConsole/petme128.pyとしてFBConsoleのリポジトリに置いてあります。

コメント