【求む、AVR強者】ATmega8 × RustでLCDが文字化けする怪を解決できなかった話


敗北宣言、そして情報提供のお願い

前回のLチカ成功から一転、LCD(1602)の壁に跳ね返されました。 結果としてC言語に回帰して解決はしたのですが、今後の「Rustマイコン道」のためにも、なぜダメだったのかを記録しておきます。もし原因に心当たりがある方がいれば、ぜひ教えてください。

発生した現象

hd44780-driver を使い、4bitモードで接続。 期待した文字列ではなく、常に「■■■■」や謎のカタカナが並ぶ文字化け状態に。

当時のコード(抜粋)

let mut lcd = Hd44780::new_4bit(
pins.d4.into_output(), // RS
pins.d5.into_output(), // E
pins.d0.into_output(), // D4
pins.d1.into_output(), // D5
pins.d2.into_output(), // D6
pins.d3.into_output(), // D7
&mut delay,
);

lcd.reset();
lcd.clear();
lcd.set_display_mode(DisplayMode {
display: Display::On,
cursor: Cursor::Off,
blink: Blink::Off,
});
lcd.write_str("Hello Rust!");

疑っているポイント

1. クロック周波数の不一致

Cargo.toml や環境変数で指定している AVR_CPU_FREQUENCY_HZ と、実際にATmega8が動作しているクロック(内部RC 1MHz / 8MHzなど)が食い違っているせいで、delay の精度が死んでいる可能性。

2. 4bitモードの初期化タイミング

HD44780のデータシートにある「電源投入後の待機時間」や「3回コマンドを送る」シーケンスが、ドライバ側で意図通りに動いていない?

3. 最適化によるタイミング崩れ

opt-level = "z" でビルドした際、必要なウェイト時間がコンパイラに削られてしまっている?

結局、C言語(avr-gcc)では動いた

同じ配線のまま、C言語で _delay_ms() を使いながら丁寧に初期化を書くと、あっさり表示されました。 「Cで動くならハードの問題ではない」ことは確定していますが、Rustでスマートに動かせなかったのが心残りです。


もし「これ、あの設定が抜けてるよ!」という点に気づいた方がいれば、SNSで教えていただけると泣いて喜びます。