壁ツェーン

オンギャーの思考回路

Sipeed Maixduino と OLED モジュール (SSD1331) を使って漢字を表示する

mstdn.maud.io 性懲りもなく今度は Sipeed Maixduino を買ってしまいました。

Sipeed Maixduino とは

Sipeed Maixduino は、平たく表現すると「RISC-V アーキテクチャー搭載の Arduino Uno フォームファクターのマイコンボード」というところになるでしょうか。 詳しいスペックなどはスイッチサイエンスの商品ページを見るなどしていただきたいんですが、とにかく安いの一言に尽きます。

www.switch-science.com

ちなみに Maixduino の他に Maix Bit というのもあって、こちらには Kendryte K210 が生で乗っています。では Maixduino はどうなっているのかというと、 Sipeed オリジナル?の Sipeed M1 モジュールというものが乗っているようです。 正直周辺モジュールや機械学習よりも RISC-V という観点で K210 を目当てにしているのであれば、Maix Bit のほうを買ってもいいかと思われます。僕はそのうちそっちも買う予定です。どうせ命令セットは RV64GC ですし、SDKも同じものが使えます。

しかしなあ……。Arduino Uno フォームファクターの宿命みたいなもので、あの形に合わせられると強制的に GPIO の数が微妙な感じになってしまいがちです。尤も、外側にピンヘッダーを大量に生やすという Nucleo みたいな戦略もなくはないですが……。

SSD1331 とは

SSD1331 は、96x64 のフルカラー OLED ディスプレイモジュールです。 OLED というだけあって、このサイズでも 1450 円もします。ていうか SSD1331 というのはコントローラー IC の名前だと思うんですが、これを含めた姉妹品はなぜか SSD1331 という名前で販売されているようです。

Amazon の商品ページ

電子工作でカラーディスプレイがほしい!というときによく挙がるのは QVGA サイズぐらいの TFT LCD モジュールですね。あれらの多くは SPI と数本の GPIO で制御できるようになっているので、RAM が心許ないマイコンでも気軽に使えるようなものとなっています(バッファリングすると結局同じぐらいは必要になっちゃうけど)。僕もこれとは別に aitendo で買ったものを持っているんですが、どうにも扱いづらくてかなり長い間放置しているのが現状です。でけえし。

www.aitendo.com

SSD1331 はその点ではいささか小さすぎる気もしますが、ブレッドボードに乗り切るという点ではかなりイイです。

なにかやりたいね

さて買ったからには何か作りたいですね。別に実用的である必要はないので、サンプルプログラムみたいなものでいいでしょう。

Maixduino は付属のディスプレイ(こいつも QVGA ですね)を接続した状態で通電すると、MaixPy が起動するのと同時に Welcome to MaixPy! というメッセージが LCD に表示されます。 どうやら MicroPython 経由で LCD を操作できるようです。それなら標準 SDK でも表示できるはずだわな、と早速 PlatformIO の環境を用意してみたのですが……

制御方法が闇に包まれている

まず。これは中華方面にありがちなのですが、ドキュメントが不足しがちです。まあ採用されている IC などの型番などがわかればまだなんとかなるのですが、付属の LCD についてはそれすら記載されていません。 どうしろと。 Maixduino 用の Arduino core やサンプルプロジェクトのソースコードを漁った結果として、「これは恐らく ST7789 として扱うことのできるコントローラーIC が載っている」という結論に至りました。宣言的知識がないともいう。

まあ ST7789 で制御できるということがわかったのは良しとしましょう。次は肝心の制御インターフェースですが、インターネッツでよく解説されているのは SPI インターフェースが出ているモジュールに関するものです。 この Maixduino 付属のものはフラットケーブル接続です。嫌な予感がします。

先ほど発見した ST7789 の制御コードをよく見てみると、 SPI_FF_OCTAL なる識別子が目につきます。 K210 Standalone SDK のプログラミングマニュアルで検索すると、どうやらこれは 8-wire mode なるものと関係するらしいです。

8-wire mode?
8-wire?
Serial Peripheral Interface で 8-WIRE とは???????

ただのパラレルバスじゃねえか、というツッコミを 100 回ぐらいしたところで、改めて調べていくと、 K210 の SPI は全体に謎が多いことがわかりました。 謎が多いというか、明文化されていない仕様というか……。

K210 には FPIOA (Field Programmable IO Array) という機能があり、 数十本ある IO ポートに自由に機能を割り振れるというものです。マイコンボードにありがちな「特定のペリフェラルを使うのに特定のピンを使わなければならない」ということがなくなり、自由に配置できるのでこれは大変便利です。 が。 K210 の SPI を配置する際に MOSI MISO SDI SDO といったデータ線の名前では参照できず、 D0~D7 という名前で参照する必要があります。 問題はここからで、 D0 が MOSI で D1 が MISO になるということをサンプルからしか読み取ることができませんでした簡体字版のマニュアルとかには書いてあるのかもしれませんが、それはそれでどうなんだという気もします。

結局 8-wire mode SPI なるものの真相はわからずじまいです。 Parallel Peripheral Interface で PPI とでも名乗っておけばいいのに。もしくは MCU バス接続であるからして単に MCU とか。 最終的にこれがわからなかったので SSD1331 を使うことにしたというのが正しいです。

そういえば Longan Nano 買ったときも LCD の詳細がわからなくて唸ってたな……。頼むよ Sipeed 。

制御部分を書いていくぞ

最終的に Maixduino + SSD1331 という構成が決まったところで、プログラムを書いていきましょう。やった順に書いていきます。

1. microSD カードアクセス (FatFs)

まず Maixduino に搭載されているのは TF card slot であって断じて microSD card のそれではないんですが、使う側からしたら同じなので SD ということにしておきます。

SD カードといえば言わずと知れた ChaN 氏の FatFs です。これを組込みましょう。問題は Maixduino 用に書かなければならないデバイス用のグルーコードですが、サンプルの中にまんま FatFs を利用して SD カードにアクセスするものがありました。 Apache License 2.0 のようなので、ありがたくこれを使わせてもらうことにしましょう。ファイル列挙も問題なく成功したので good 。 まあこれが一番面倒なんだよな一般的には。

2. SSD1331 制御 (自作)

次に重要なのが SSD1331 です。これは普通に SPI と GPIO をデータシート通りに制御してあげればいいので問題ないでしょう。初期化の手順だけはちょっと面倒というか複雑なのでインターネッツの先人のコードを参考にしました。色フォーマットとコントラスト調整以外はほぼ共通になるっぽいですね。

SSD1331 の特筆事項として Graphic Accelaration Command の存在があります。直線や矩形の描画、画面上のコピーやスクロールを自前でやらなくても IC 側でやってくれるというものです。非常に便利なので対応しない手はありません。

単色とグラデーションを送信できたのでこれもパス。順調です。

3. JPEG デコード (TJpgDec)

とりあえずこの 2 つができれば画像を表示させるぐらいのことはできるので、手始めに JPEG 画像でも表示させてみましょう。 なぜ JPEG なのかというと、これまた ChaN 氏の TJpgDec という組み込み向けな JPEG デコーダーがあるからに他なりません。

これもちょっとグルー関数を書くだけであとはストリーミングでデコードしてくれます。便利な世の中になったものです。

mstdn.maud.io

4. PNG デコード (LodePNG)

JPEG ができたら次は PNG です。これが成功すればフォントの表示に大きく近付きます。PNG をデコードするといえば zlib/libpng ですが、これはコードサイズが大きくなってしますし何より Maixduino の環境ではビルドが通りません。

そこで別のライブラリを探すことにしました。 だいたいこういうものは embedded library とかのキーワードと一緒にググると見付かるものですが……オッ、 LodePNG というのがなかなか良さそう。各1ファイルに収まってシュリンクのオプションも豊富ときた。

なんだかんだでこれもそのままビルドが通ってしまいました。すげえな。

5. (Shift)JIS ⇔ Unicode 変換 (自作)

なぜこんなことする必要があるのかというと、画像データが提供されている日本語フォントは大体 JIS X 0208 で整列されているからです。 今回利用した k8x12 も例外ではなく、これを現代の UTF-8 な環境で使おうとすると一工夫必要です。

そこで、今回は以下のような手段をとることにしました。

  • フォント画像とは別に、JIS/Unicode の変換テーブルに相当するファイルを生成する。
  • Unicode コードポイントから JIS X 0208 の区点番号を引けるような構造のハッシュテーブルもどきを生成する。
  • このとき、 ASCII 範囲も対応する全角記号にマッピングしてしまう。さすがに半角で横幅 4px は無理。
  • 表示する際に、UTF-8 文字列からコードポイントを逆算し、変換テーブルを探索する。
  • 得られた区点番号はほぼそのままフォント画像ファイルの位置に対応するので、コピーするだけ!

……で、これ以上説明するが面倒になってしまったんですが、 Maixduino 側のコードはおよそこの辺になります。変換テーブル生成のコード(Rust)もそのうち push する予定です。

できました

以上を組み合わせたものがこちらになります。

mstdn.maud.io

感想

  • Sipeed 頼むからもうちょっと細かくドキュメント書いてくれ
  • Kendryte ももうちょっとドキュメント書いてくれ
  • カラーディスプレイに画像が表示されると楽しい!
  • カラーディスプレイに日本語が表示されると楽しい!

(追記) Sipeed と Kendryte に聞きたいことリスト

  • kflash で毎回書き込んでる ISP_PROG の正体が知りたい。zlib encoded な バイナリが bin2hex されてハードコードされているので中で何をしているのかさっぱりわからない。
  • K210 のメモリマッピングが欲しい。Flash が外付けなのはわかってるけど、実行時にどこにマッピングされるのかとかわかると嬉しい(有志が調査して出してくれているものはある)。
  • Flash からプログラムをどう読み出しているのか、もし SRAM などに配置しているならどう配置するのかが知りたい。
  • 結局 multi-wire SPI ってなんなのですか
  • というかレジスタ類の解説をちゃんとやっている ドキュメントを出してほしいです……(SDK のドキュメントだけだとわからないことが多すぎる)
  • Longan Nano のときもそうだったけど LCD のコントローラーを(互換でもいいので)明記してくれ