電子ペーパー GDEH0154D27 を動かし調整し描画速度などを測定して遊んだメモ
ふとしです。
Rust + 電子工作勉強の一環として、適当にモジュールを買って、Rust でライブラリを書いて動かすということをしています。
今回は電子ペーパー GDEH0154D27 を Raspberry Pi Zero で動かして遊んだので日記にします。
とりあえず動かしてみるためのさまざま
- 現物: 1.54インチ e-Paper ディスプレイモジュール(白黒) [GDEH0154D27] - スイッチサイエンス
- 公式マニュアル
- 設定値のうち VCOM と LUT は Good display から知らされると書いてありますが、どこにもそのようなページを見つけることができませんでした。(ので下部に記載しました)
- 公式サンプルコード
- readme.txt には図つきで使用するピンの記載があります
GDEH0154D27 を動かしてみる上でいちばん苦労したのはこの公式マニュアルと公式サンプルコードの入手で、Google からのサイト検索でようやくみつけることができました。
サンプルコードを動かして配線の正しさを確認すれば、パラメーターを調整してなにがどうなっているかを実機を通して観察できるようになります。
描画の流れ
初期化を除いた描画ごとのフローは以下のようになります。
- 描画で使う RAM の範囲を送信する
- 描画で使う RAM 位置のカウンター開始位置を送信する
- 画像データを送信する
- 画像の反映オプションを送信する
- 画像を反映する命令を送信する
- 描画が終わるまで待つ
- 1 にもどる
画像データの形式および RAM に関する値
この電子ペーパーでは 2 色しか扱わないので、送信する画像データもそれにあわせて最適化されています。2 色のデータの最適化には流派があるようですが、この電子ペーパーでは 1 行 8 列を 1 byte として送信します。
たとえば 24 * 2 の画像では以下のように扱い、6 bytes のデータとして送信します。
******** ******** ********
******** ******** ********
同様に RAM に関する値を送信する場合の x 座標は x >> 3
した値となります。
問題になる局面
全画面を描画する際には問題ありませんが、画面の一部を描画しなおす場合は 8 の倍数の範囲を必ず含めなければなりません。
例えばなんらかの計測値の数字のみを描画しなおす場合でも、単位部分が範囲に含まれる場合には忘れずに送信データに含める必要があります。
マニュアルにのっていない定数
VCOM と LUT はサイトなどで見つけられなかったため、サンプルコードのものが公式であるとみなしています。
const VCOM: u8 = 0xA8;
const LUT_FULL_UPDATE: [u8; 30] = [0x66, 0x66, 0x44, 0x66, 0xAA, 0x11, 0x80, 0x08, 0x11, 0x18, 0x81, 0x18, 0x11, 0x88, 0x11, 0x88, 0x11, 0x88, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0xAF, 0xFF, 0xFF, 0x2F, 0x00];
const LUT_PARTIAL_UPDATE: [u8; 30] = [0x10, 0x18, 0x18, 0x28, 0x18, 0x18, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x11, 0x22, 0x63, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00];
描画速度
この電子ペーパーでは使用する LUT を送信して切りかえることで描画をフルアップデートかパーシャルアップデートかに設定できます。
- フルアップデートは毎回画面が白黒反転し完全に描画しなおします (おそい)
- パーシャルアップデートは反転せず前回の描画跡がうっすらと残ります (はやい)
(なお、LUT はサンプルコードに添付されている他、独自に調整したものを公開しているサイトもあるようです)
電子ペーパー (GDEH0154D27) の描画速度を雑に測定した。まず、
— ふとし (@mmmpa) August 10, 2020
パーシャルアップデートだと 510ms
フルアップデートだと 3600ms
程度が固定で必要で、後は転送するデータ量に応じてさらに時間がかかる。動画は転送面積をふやしていってるんだけどデータ量に応じて
16 * 9 -> 32ms
32 * 18 -> 72ms pic.twitter.com/xA0hcKnxoa
描画速度うちわけ
画像によって変化する部分としない部分があります。
ほぼ固定値 (画像反映時)
アップデート形式により以下の時間がほぼ固定でかかります。
形式 | 時間 |
---|---|
フルアップデート | 3600ms |
パーシャルアップデート | 500ms |
画像によって可変 (画像送信時)
それに加え、画像のデータ量に応じた時間がかかります。以下はテストでライフゲームを送信した時の値です。各辺が 2 倍になっていくので、データ量は 4 倍になっていっています。
面積 | 時間 |
---|---|
16 * 9 | 32ms |
32 * 18 | 72ms |
64 * 36 | 205ms |
128 * 72 | 758ms |
全画面の場合は以下のようになります。
面積 | 時間 |
---|---|
200 * 200 | 3220ms |
つまり
全画面再描画かつフルアップデートだと 3600 + 3220 で 7 秒近くかかってアニメーション用途には使えません。
一方 64 * 36 かつパーシャルアップデートなら 500 + 72 で 0.6 秒程度となり、比較的アニメーションに耐える描画速度と言えるでしょう。秒あたりで計測値が変わるようなものの表示なら大丈夫かもしれません。
まとめ
以下は電子ペーパーを操作する部分と、1 byte に 8 ピクセル詰め込むために書いたおれおれクレートです。
Raspberry Pi Zero で動かしたモジュール 2 発目がこの電子ペーパーでしたが、データの送信形式など、バブリーなウェブプログラミングとは違った点が様々にあり、勉強になりました。
また、Rust はこのような用途にも非常に相性がよく書いてて非常に快適でした。もっと Rust を書けるようになりたいですね。