HN 日本語サマリー

← 一覧へ戻る
科学・技術

E-Paperパネルは壊れていない:リテインド・ステートがドライバーをバグのように見せる仕組み

E-Paper Panel Isn't Broken: How Retained State Makes Drivers Look Buggy (msj.prose.sh)

6 pointsby lukastyrychtr1 コメント

要約

電子ペーパー(E-Paper)ディスプレイのドライバー開発において、著者はリテインド・ステート(電源を切っても状態を保持する性質)が原因で発生する、一見バグのように見える問題を解決しました。E-Paperパネルだけでなく、そのコントローラーも状態を保持しており、リフレッシュ処理の中断などが原因でコントローラーがBUSY状態に固定されると、以降のコマンドが無視され、ドライバーがタイムアウトする現象が発生します。この状態はハードウェアリセットでは解消されず、電源の抜き差しのみでリセットされるため、デバッグを困難にします。

全文翻訳

電子ペーパーパネルは壊れていない:リテンションステートがドライバをバグっているように見せる仕組み

2026-08-24 · msj's blog


ある午後、電子ペーパーディスプレイのドライバにあった3つのバグを修正しようとした。しかし、それらは実際には存在しなかった。

そのドライバは、私がメンテナンスしている電子ペーパーディスプレイ用の no_std Rustフレームワークであるepdsiだった。RP2350で動作していた例をESP32-C3に移植していたのだ――ドライバクレートもパネルも同じだが、ボードが違った。本来なら20分で終わるはずの作業が、丸一日かかり、最終的に出荷したコードは、本質的には開始したコードと同じだった。

以下に、この問題を引き起こした失敗モードについて述べる。それはどこにも書かれていないと思うし、電子ペーパーを扱う人は誰でもいつかはこれに直面するだろうからだ。

誰も警告してくれないこと #

電子ペーパーは電源なしで画像を保持する。それがセールスポイントであり、この技術を使う理由そのものだ。すべてのデータシートがこれを最初に謳っている。

しかし、データシートが強調していないのは、コントローラーも状態を保持するということであり、その状態が常に無害であるとは限らないということだ。

リフレッシュの途中で中断する――モニターをCtrl-Cで終了する、ボードを再フラッシュする、チャージポンプが動作中に電源ケーブルを抜く――と、コントローラーはビジー状態のままラッチされる可能性がある。BUSY信号がアサートされたまま、完了しない操作を待ってしまうのだ。

ここでプログラムを再度実行する。ドライバはリフレッシュを発行し、BUSY信号を待つ。BUSY信号はすでにアサートされており、クリアされないため、待機はタイムアウトする。epdsiではこれは60秒だ。SSD1680では、1回のリフレッシュは3つのステージ――電源投入、更新、電源オフ――からなり、それぞれに独自の待機時間がある。つまり、1回の更新に3分かかることになり、私の例ではそれが6回実行された。

さらに悪いことに、これは自己増殖する。タイムアウトしたリフレッシュは、パネルを同じラッチされた状態のままにするため、次の実行も全く同じように失敗する。あなたは今、毎回同じ方法で失敗するシステムをデバッグしていることになり、これは決定的なバグのように感じられる。

そして、最も時間を費やした部分がある:ハードウェアリセットではクリアされない。ドライバの hard_reset はRSTピンをトグルし、パネルはそれを認識し、BUSY信号は正しくパルスする――しかし、根本的な状態は持続する。電源を取り除くことだけが、実際にそれをリセットする。

同じ問題の4つの顔 #

リテンションステートは自己申告しない。それは、あなたの現在の仮説に合うどんな衣装でも着る。ある午後、それはこれらすべてを生み出し、私はそれぞれを異なるバグとして診断した。

シフトしてクリップされたコンテンツ。書き込みが途中でカットされると、フレームバッファは半分転送されたままになる。パネルはその結果を忠実に表示する。

[画像: 2.13インチパネルに、コンテンツが右にシフトし、端でクリップされた状態で表示されている]

これは2.13インチのモノクロパネルだ。上部のヘッダーは正しいが、それ以下のすべてが約40ピクセル右にずれて端から消えている。これは、RAMウィンドウやストライドの計算ミスのように見える――そして私は最近RAMアドレス指定コードに触ったばかりだったので、すぐにそれを信じた。

中断された書き込みが、ノイズの帯を挟んで2回描画されたフレームを生成した、4.26インチパネルでの同じ失敗がこちらだ:

[画像: 4.26インチパネルに、ノイズの帯を挟んでフレームが左右に複製されて表示されている]

10ミリ秒で返ってくるリフレッシュ。パネルがコマンドを受け付けていないため、BUSY信号がアサートされず、待機処理はアイドルラインを見てすぐに返る。私はこれを競合状態として診断した――パネルがBUSY信号を上げる前にドライバがポーリングしているというものだ。私はその競合状態に対して3つの連続した修正を記述した。その競合状態は存在しない。

ハングアップしているように見えるリフレッシュ。ハングアップしているのではなく、タイムアウトしているのだ。しかし、3分間はターミナルを見ている者にとっては永遠と区別がつかないため、中断してしまう――そしてそれは、問題を引き起こしたのと同じ状況を再作成してしまう。

何も起こらない。コマンドは無視され、ディスプレイは変更されず、プログラムは正常に完了し、成功を報告する。

4つの症状、4つのもっともらしいドライババグ、1つの実際の原因。

どうして悪化させたか #

3つの間違い、どれも他人の書き込みなら明白だと思っただろう。

汚染されたデータから推論し続けた。実行が中断されていることは知っていた。それにもかかわらず、その後の結果から結論を導き出した。ある時点でパネルの状態を正しく疑い、電源サイクルを試みるべきだと自分に言い聞かせ、理論と一致しない結果を得た――そして理論を放棄したのではなく、理論が間違っていると結論づけた。

嘘をつく診断ツールを構築した。より細かいタイミングを得るために、ドライバ自身の refresh を呼び出す代わりに、コントローラーのトリガーシーケンスを手作業で作成した。それは9つの測定値を報告し、すべて正確に100ミリ秒だった。私はそれをデータとして読んだ:

1--- A: full frame, Full mode (0xF7) ---
2    power-on  (0xE0): BUSY released after 100 ms
3    update    (0xF7): BUSY released after 100 ms
4    power-off (0x83): BUSY released after 100 ms

それらはアイドルライン上のノイズだった。コードはパネルを全く駆動していなかった。それを露呈させたのはログではなく――ログは完全に妥当に見えた――ディスプレイが全く変化しないことに気づいたことだった。

ソフトウェアが作業場所だったので、ソフトウェアに固執した。既知の良好なサードパーティ製コードが、ずっとそこにあった。ずっと後になるまでそれを使おうとしなかった。

実際に効果があったこと #

3つのテクニック、それぞれが数時間の憶測を単一の実験に集約させた。

複数のボードで標準的なサードパーティ製コードを実行する。同じアダプターとパネルを使い、4つの異なるマイクロコントローラーに標準的なArduino GxEPD2デモをフラッシュした。3つは完璧に動作したが、1つはノイズを生成した。その単一の実験が、私のドライバではなくボードレベルの問題であることを証明した――コード分析に何時間も費やしたにもかかわらず、到達できなかった結論だった。後で別のパネルで同じトリックを繰り返し、同様にクリーンな結果を得た。

既知の測定値に対してインストゥルメントを検証する。信頼できるベースライン――このパネルでのフルリフレッシュには3891ミリ秒かかる――を得たら、100ミリ秒を報告するどんな診断も自己矛盾していることが明らかになる。そのベースラインは、「興味深い結果」を瞬時に「私のツールは嘘をついている」に変える。必要になる前にそれを確立せよ。

ログではなく、ディスプレイを見る。ファームウェアは、達成できなかった成功を喜んで報告する。パネルはできない。この後書いたすべての診断は、紛れもないもの――真っ黒、次に真っ白――を描画したため、ハードウェア自体が質問に答えた。

プロトコル #

これは今、私のリポジトリで必須の読み物となっている:

電源サイクルし、一度実行し、中断せず、それから判断せよ。ボードの電源がオフの状態でFPCを接続・切断せよ。

魅力的ではないが、丸一日を節約できたはずだ。いくつかの補足。

中断された実行、またはそれに続く実行からは、電源を取り除くまで推論しないこと。リセットではなく、電源だ。

参照タイミングを知る。偏差はベースラインに対してのみ認識可能だ:

パネルフルリフレッシュ部分リフレッシュ
4.26インチモノクロ約3.9秒約1.0秒
2.13インチモノクロ約3.9秒約1.0秒
1.54インチトリカラー約14秒約14秒

4,000バイトのフレームを4MHzのSPIで転送するには8ミリ秒かかる。データ転送が問題になることは本質的にないため、誘惑的な仮説のファミリー全体が排除される。

カラーパネルは遅く、それは物理法則だ。トリカラーおよびクアッドカラーパネルには高速波形がない――着色顔料はより重い粒子であり、移動させるには完全な波形が必要だ。すべての更新に数秒かかる。私の1.54インチトリカラーの例では、6回の更新がそれぞれ約14秒かかる:90秒間画面がフリーズしたように見えるが、すべて正しい。これは、完璧に動作していた実行を中断させる最も可能性の高い原因だ。

一般化できる部分 #

これが20分ではなく丸一日かかった理由は、電子ペーパーが異常に難しいからではない。それは、私の対象と私のインストゥルメントの両方が私に嘘をつく可能性があったシステムをデバッグしており、私はそのうちの1つしかチェックしていなかったからだ。

パネルは実行をまたいで状態を保持することで嘘をついたため、すべての実験が前回から汚染された。私の診断ツールは、実際には起こらなかった操作に対して妥当な数値を報告することで嘘をついた。ソフトウェアだけではどちらのケースも区別できない――だからこそ、修正は物理的なものだった:電源を引き抜き、画面を見る。

リテンションステートを持つものをデバッグしている場合――ディスプレイ、EEPROM、永続的な設定を持つラジオ、チャージポンプを持つもの――前の実験が、それを証明するまで現在の実験に影響を与えていると仮定せよ。そして、測定値があなたを驚かせたときは、コードを書き直す前に定規をチェックせよ。

[画像: 失敗写真と同じXIAO ESP32-C3とePaperドライバボードが、今度は2.13インチのクアッドカラーパネルを黒、白、赤、黄で正しくレンダリングしている]

これは、上記の2つの失敗写真と同じボードとアダプター――Seeed ePaper Driver Board上のXIAO ESP32-C3――で、4色すべてを意図した通りにレンダリングしている。ちなみに、ドライバは全く変更する必要はなかった。


epdsi はcrates.ioとGitHubで入手可能――SSD1680/1681/1677、UC8253、JD79661、ED2208、およびPervasive DisplaysのCOGをカバーする、no_std、embedded-hal 1.0準拠の電子ペーパーディスプレイ用ドライバフレームワーク。Cortex-M、RISC-V、Xtensaにわたるハードウェアで検証済み。