Knurling Sessions 2020Q4 をやる (4) 〜ディスプレイ〜

はじめに

knurling-rs では Ferrous Systems が、スポンサー向けに組込み Rust の教材 knurling-session を提供しています。

github.com

knurling-session では、3ヶ月ごとに1つのテーマを取り上げています。 最新のもの以外は、公開されています。スポンサーになると最新のものも見れます。 また、スポンサーが増えると、knurling-rs に割く時間が増やせるため、ツールの改善や教材の整備が増えることが期待できます。 興味を持ったらスポンサーしましょう!

現在公開されている knurling-session の 2020 Q4 をやっていきます。 2020 Q4 は、nRF52840-DK と CO2 センサーを使ったプロジェクトです。

2020 Q4 のレンダリングされているドキュメントはこちら。

session20q4.ferrous-systems.com

前回、CO2 センサドライバを作成して、defmt で出力しました。

tomo-wait-for-it-yuki.hatenablog.com

今回は、CO2センサから読み取った値をディスプレイに表示します。 Knurling Sessions では Waveshare 4.2 inch ePaper ディスプレイを使っていますが、とりあえず手元にあった SSD1331 でやってみることにしました。

f:id:tomo-wait-for-it-yuki:20210501204734p:plain
Waveshare 4.2 inch b&w ePaper Display

f:id:tomo-wait-for-it-yuki:20210501204919p:plain
SSD1331

embedded-graphics を使っているので、なんとかなるだろう、と踏みました。 ePaper ディスプレイが 300x200 のサイズに対して、SSD1331 は 96x64 なので、サイズは調整が必要です。 また、ePaper ディスプレイは白黒なのに対して、SSD1331 は RGB フルカラーなので色の使い方も調整します。

Hello, e-Paper Display!

ピンアサインだけ一応ドキュメントに合わせた以外はほぼ独自で書きました。

Cargo.toml に ssd1331 crate と embedded-graphics crate を追加します。

ssd1331 = "0.2.3"
embedded-graphics = "0.6.2"

初期化はこのような感じです。

use ssd1331::{DisplayRotation::Rotate0, Ssd1331};

#[cortex_m_rt::entry]
fn main() -> ! {
    // ...
    let din = pins_1.p1_01.into_push_pull_output(Level::Low).degrade();
    let clk = pins_1.p1_02.into_push_pull_output(Level::Low).degrade();
    let _cs = pins_1.p1_03.into_push_pull_output(Level::Low);
    let dc = pins_1.p1_04.into_push_pull_output(Level::Low);
    let mut rst = pins_1.p1_05.into_push_pull_output(Level::Low);

    let spi_pins = spim::Pins {
        sck: clk,
        miso: None,
        mosi: Some(din),
    };
    let spi = Spim::new(board.SPIM3, spi_pins, spim::Frequency::K500, spim::MODE_0, 0);

    let mut display = Ssd1331::new(spi, dc, Rotate0);
    display.reset(&mut rst, &mut timer).unwrap();
    display.init().unwrap();

    // ...
}

とりあえず 1 pixel 書いてみます。 ssd1331 は flush() メソッドを呼び出さないとディスプレイに描画が始まらないので注意です。

    display.set_pixel(10, 20, 0xf00);
    display.flush().unwrap();

Display Sensor Data

さて、いよいよ大詰めです。 ここでは、動的に文字列をディスプレイに表示する方法が説明されています。

arrayvec::ArrayString を使います。ArrayString は長さが固定の文字列として使えます。 次のような感じで、SCD30 から読み取った浮動小数点数を文字に変換します。

let mut buf = ArrayString::<[_; 12]>::new();
write!(&mut buf, "{:.2} {}", value, unit).expect("Failed to write to buffer");

文字サイズと文字の表示位置を調整して…

f:id:tomo-wait-for-it-yuki:20210501202831p:plain
SCD30 で読み取った値を SSD1331 に表示

f:id:tomo-wait-for-it-yuki:20210501202934p:plain
ちょっと小さいけど良い感じに表示できている

さいごに

少々機材が高いですが、基礎から学ぶ組込みRust を読んだ方なら、すんなりできるのではないでしょうか。 probe-run や defmt といったツールのできがよく、良いディベロッパー経験を得られます。