OLEDをMicroPythonのコンソールにしてみた


MicroPythonのosモジュールにはduptermという機能があり、これを使うとREPLで使われている標準の入出力チャネルをUART以外のデバイスへ複製することができます。
duptermのパラメータにオブジェクトを与えると、そのオブジェクトでREPLへの入出力ができるようになります。
オブジェクトはwriteとreadintoの2つのメソッドだけ持っていれば、duptermに使用できます。

writeでフレームバッファに描画するオブジェクトを作れば、フレームバッファ互換のOLEDやRaspberry Piの画面などのデバイスをREPLの出力先として使えそうです。
そこで、Raspberry PiのMicroPythonにduptermのサポートを追加し、duptermでフレームバッファに出力するためのクラスを作成してみました。

dupterm自体はMicroPythonに実装が含まれています(extmod/uos_dupterm.c)。ヘッダファイルはextmod/misc.hです。
出力については、標準の文字列出力関数(mp_hal_stdout_tx_strn)の内部で、duptermへ送りたい文字列をmp_uos_dupterm_tx_strnで送れば動作します。
入力を受け付ける場合は、入力側の処理(mp_uos_dupterm_rx_chr)も行う必要がありますが、今回はとりあえず省略しました。

次に、フレームバッファをduptermの出力先にするためのクラスですが、これはMicroPythonで作成しました。
I2C接続のOLED(SSD1306)を出力先にする場合の使い方はこんな感じです。

I2Cのクロックがデフォルトの100KHzだとかなり遅いので、1MHzに設定しています。
FBConsoleというのが今回作成したクラスです。

さすがに、128×64ドットの画面ではコンソールに使うにはちょっと狭いですが、たとえば

console.cls();console.x=10;console.y=5;print("Hey!")

こんな感じでOLEDの好きな場所にprint文で出力することもできます。

duptermをやめる場合は

os.dupterm(None)

を実行します。

FBConsoleクラスの中身は以下の通りです。
必須のメソッドはwrite(buf)とreadinto(buf, nbytes)の2つですが、readintoは何もせずNoneを返すのみです。

7/4追記:uio.IOBaseのサブクラスとなるよう変更しました。uio.IOBaseはmpconfigport.hでMICROPY_PY_IO_IOBASEを有効にすることで使えるようになります。)
11/11追記改良版を作成しました。)
writeはバイト列を受け取ってフレームバッファへ文字として描画します。
基本的に1文字ずつ出力し、画面がいっぱいになったら1行分スクロールするだけです。
そのほか、エスケープシーケンスやバックスペースの処理を行っています。

フレームバッファに汎用的に使えるようにしようとしましたが、OLEDは

  • show()を呼ばないと表示されない
  • widthとheightが属性としてアクセスできる

といったあたりがフレームバッファとは異なるので、OLED専用の処理をtry~exceptで行うようにしています。

コメント