Wio Terminal で Knurling Sessions 2020Q4

はじめに

ここ数日、Knurling Sessions 2020Q4 をリファレンスボード (nRF52840-DK) でやっていました。

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

今回は、Wio Terminal を使って同じ内容 (CO2 センサから読み取った値をディスプレイに表示) をやってみます。

配線

I2C1_SDA / I2C1_SCL / 3.3V / GND をスルーホール用テストワイヤで接続します。 probe-run と defmt を使うために、JLink を接続しています。

実行結果

f:id:tomo-wait-for-it-yuki:20210503210005p:plain
奥にあるのが CO2 センサ

f:id:tomo-wait-for-it-yuki:20210503203548p:plain
defmt のログ

余談

実装時に1回ピンアサインを間違って、panic しましたが、probe-run (panic-probe) のおかげで、バックトレースが出力されたので、一瞬でデバッグできました。 やったね。

おわりに

大体半日もかからずに移植できました。 CO2 センサがちょっと高価ですが、基礎から学ぶ 組込みRust 後のお楽しみとしてどうでしょうか。

Wio Terminal で probe-run / defmt

はじめに

『基礎から学ぶ 組込みRust』では追加機材が不要な cargo hf2 を使ってファームウェアを書き込み、UART で文字を出力しました。 組込み Rust ではその他にも便利なツールがあります。 今回はそのうちの、probe-run と defmt を Wio Terminal で使ってみます (両方 knurling-rs の成果物です) 。

github.com

Runs embedded programs just like native ones

github.com

defmt ("de format", short for "deferred formatting") is a highly efficient logging framework that targets resource-constrained devices, like microcontrollers.

注意

本記事の内容を試すには、JLink か DAPLink かのデバッグアダプタを Wio Terminal に接続している必要があります。 Seeeduino XIAO を用いた DAPLink デバッグアダプタの環境構築は、基礎から学ぶ 組込みRust のサポートサイトに手順を掲載しています。

github.com

f:id:tomo-wait-for-it-yuki:20210503140523p:plain
JLink 接続

サンプルプロジェクトと実行方法

下に Wio Terminal で probe-run / defmt を試すためのサンプルプロジェクトを用意しました。

github.com

事前準備

probe-run をインストールします。

$ cargo install probe-run

Linux の場合は、libudev と libusb もインストールします。

sudo apt install libudev libusb

実行方法

Wio Terminal をデバッグアダプタと接続している状態で、プロジェクトを clone して、cargo run するだけです。

$ git clone https://github.com/tomoyuki-nakabayashi/wio-terminal-probe-run.git
$ cd wio-terminal-probe-run
$ cargo run

実行結果は次のようになります。

     Running `probe-run --chip ATSAMD51P19A --speed 100 target/thumbv7em-none-eabihf/debug/wio-terminal-probe-run`
  (HOST) INFO  flashing program (12.92 KiB)
  (HOST) INFO  success!
────────────────────────────────────────────────────────────────────────────────
       0 INFO  Hello, world!
└─ wio_terminal_probe_run::__cortex_m_rt_main @ src/main.rs:11
  (HOST) WARN  program has used at least 195528 bytes of stack space, data segments may be corrupted due to stack overflow
stack backtrace:
   0: lib::inline::__bkpt
        at ./asm/inline.rs:13
   1: __bkpt
        at ./asm/lib.rs:49
   2: wio_terminal_probe_run::exit
        at src/lib.rs:29
   3: wio_terminal_probe_run::__cortex_m_rt_main
        at src/main.rs:12
   4: main
        at src/main.rs:10
   5: ResetTrampoline
        at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:547
   6: Reset
        at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:550
   7: __DEFMT_MARKER_TIMESTAMP_WAS_DEFINED
   8: Reset
        at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:497
error: the stack appears to be corrupted beyond this point

実行時のログは、タイムスタンプ (サンプル実装は1ずつインクリメントされるただのカウンタ)、ログレベル、ソースコード上の位置付きで出力されます。

       0 INFO  Hello, world!
└─ wio_terminal_probe_run::__cortex_m_rt_main @ src/main.rs:11

bkpt 命令を呼び出したり、プログラムが panic するとバックトレースを出力します。

stack backtrace:
   0: lib::inline::__bkpt
        at ./asm/inline.rs:13
   1: __bkpt
        at ./asm/lib.rs:49
   2: wio_terminal_probe_run::exit
        at src/lib.rs:29
   3: wio_terminal_probe_run::__cortex_m_rt_main
        at src/main.rs:12
   4: main
        at src/main.rs:10
   5: ResetTrampoline
        at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:547
   6: Reset
        at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:550
   7: __DEFMT_MARKER_TIMESTAMP_WAS_DEFINED
   8: Reset
        at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:497
error: the stack appears to be corrupted beyond this point

少し解説

Cargo.toml

panic 時に probe-run 経由でバックトレースを出力する panic-probe を使うことができます。

panic-probe = "0.2.0"

defmt は、Cargo.toml に次の設定を追加します。features はこういうものだ、と思って下さい。

defmt = "0.2.0"
defmt-rtt = "0.2.0"

[features]
default = [
  "defmt-default",
]

defmt-default = []
defmt-trace = []
defmt-debug = []
defmt-info = []
defmt-warn = []
defmt-error = []

.cargo/config

probe-run と defmt を使うためにリンクオプションを2つ追加します。

[target.thumbv7em-none-eabihf]
rustflags = [
  "-C", "link-arg=-Tlink.x",
  "-C", "link-arg=--nmagic", # 追加
  "-C", "link-arg=-Tdefmt.x", # 追加
]
# runner を probe run に
runner = "probe-run --chip ATSAMD51P19A --speed 100"

src/lib.rs

アプリケーションから使えるように、lib.rs に部品をまとめておきます。

#![no_std]

use core::sync::atomic::{AtomicUsize, Ordering};

use defmt_rtt as _; // global logger
use panic_probe as _;
use wio_terminal as _;

use panic_probe as _;

// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
#[defmt::panic_handler]
fn panic() -> ! {
    cortex_m::asm::udf()
}

// defmt のタイムスタンプを実装します
// タイマを使えば、起動からの時間を表示したりできます
static COUNT: AtomicUsize = AtomicUsize::new(0);
defmt::timestamp!("{=usize}", {
    // NOTE(no-CAS) `timestamps` runs with interrupts disabled
    let n = COUNT.load(Ordering::Relaxed);
    COUNT.store(n + 1, Ordering::Relaxed);
    n
});

/// Terminates the application and makes `probe-run` exit with exit-code = 0
pub fn exit() -> ! {
    loop {
        cortex_m::asm::bkpt();
    }
}

src/main.rs

後は使うだけです。

#![no_std]
#![no_main]

use wio_terminal_probe_run;

use wio_terminal as wio;
use wio::entry;

#[entry]
fn main() -> ! {
    defmt::info!("Hello, world!");
    wio_terminal_probe_run::exit()
}

制限

次の issue に挙げられている通り、現在は speed を 100 khz にしないとうまく動きません。 そのため、少し動作が遅く感じます。

github.com

おまけ

probe-run は probe-rs を活かして実装されています。 probe-rs ではオプションの機能として、FTDI のデバッグアダプタをプローブする機能が実装されています。 そのうち、probe-run でも使えるようになるかもしれませんね。

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 といったツールのできがよく、良いディベロッパー経験を得られます。

Knurling Sessions 2020Q4 をやる (3) 〜CO2センサドライバ〜

はじめに

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

前回、Lチカ終わらせたので、いよいよ CO2 センサ (SCD30) ドライバを書いていきます。

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

Hello, Sensor!

まずは、CO2 センサの配線です。スルーホール用のテストワイヤ使ってみました。

f:id:tomo-wait-for-it-yuki:20210501171508p:plain
CO2センサの接続

SCD30 は、I2C インタフェースで制御します。 I2C ドライバのオブジェクトを作成して、SCD30 ドライバのオブジェクトを初期化します。

    let scl = pins.p0_30.degrade().into_floating_input();
    let sda = pins.p0_31.degrade().into_floating_input();
    let twi_pins = twim::Pins{ scl, sda };
    let i2c = Twim::new(board.TWIM0, twi_pins, twim::Frequency::K100);
    let mut scd30 = SCD30::init(i2c);

SCD30 ドライバも自作します。 データシートを見て、firmware version を取得するコードを書きます。

pub struct SCD30<T: Instance>(Twim<T>);

impl<T> SCD30<T> where T: Instance {
    pub fn init(i2c: Twim<T>) -> Self {
        SCD30(i2c)
    }

    pub fn get_firmware_version(&mut self) -> Result<[u8; 2], Error> {
        let command: [u8; 2] = [0xd1, 0x00];
        let mut rd_buffer = [0u8; 2];

        self.0.write(DEFAULT_ADDRESS, &command)?;
        self.0.read(DEFAULT_ADDRESS, &mut rd_buffer)?;

        let major = u8::from_be(rd_buffer[0]);
        let minor = u8::from_be(rd_buffer[1]);

        Ok([major, minor])
    }
}

これで firmware version が取得できるようになります。

       0 INFO  Firmware Version: 3.66

Start Measuring

データシートを見ながら、SCD30 ドライバにメソッドを追加していきます。 今回作成する SCD30 ドライバは、70 行くらいで、それほど複雑ではありません。

impl<T> SCD30<T> where T: Instance {
    pub fn start_continuous_measurement(&mut self, pressure: u16) -> Result<(), Error> {
        let mut command: [u8; 5] = [0x00, 0x10, 0x00, 0x00, 0x00];
        let argument_bytes = &pressure.to_be_bytes();
        command[2] = argument_bytes[0];
        command[3] = argument_bytes[1];

        let mut crc = Crc::<u8>::new(0x31, 8, 0xff, 0x00, false);
        crc.update(&pressure.to_be_bytes());
        command[4] = crc.finish();

        self.0.write(DEFAULT_ADDRESS, &command)?;

        Ok(())
    }

    pub fn data_ready(&mut self) -> Result<bool, Error> {
        let command: [u8; 2] = [0x02, 0x02];
        let mut rd_buffer = [0u8; 3];

        self.0.write(DEFAULT_ADDRESS, &command)?;
        self.0.read(DEFAULT_ADDRESS, &mut rd_buffer)?;

        Ok(u16::from_be_bytes([rd_buffer[0], rd_buffer[1]]) == 1)
    }

    pub fn read_measurement(&mut self) -> Result<SensorData, Error> {
        let command: [u8; 2] = [0x03, 0x00];
        let mut rd_buffer = [0u8; 18];

        self.0.write(DEFAULT_ADDRESS, &command)?;
        self.0.read(DEFAULT_ADDRESS, &mut rd_buffer)?;

        let co2 = f32::from_bits(u32::from_be_bytes([rd_buffer[0], rd_buffer[1], rd_buffer[3], rd_buffer[4]]));
        let temperature = f32::from_bits(u32::from_be_bytes([rd_buffer[6], rd_buffer[7], rd_buffer[9], rd_buffer[10]]));
        let humidity = f32::from_bits(u32::from_be_bytes([rd_buffer[12], rd_buffer[13], rd_buffer[15], rd_buffer[16]]));

        let data = SensorData{ co2, temperature, humidity };
        Ok(data)
    }

ここまでできると、defmt 経由で計測結果を出力します。

f:id:tomo-wait-for-it-yuki:20210501171053p:plain
CO2

Red Alert!

CO2 センサ、RGB LED、ブザーを組み合わせてプログラムを作成します。

Knurling Sessions 2020Q4 をやる (2) 〜基本編〜

はじめに

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

前回、環境構築したので、LED やボタン使う基本からやっていきます。

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

Hello World

nRF52840-DK ボード上の L チカからです。

コードは1_hello_extended.rs のような感じで、どこかで見たのと同じような感じだなぁ、となるかと思います。

External RGB LED

お次は、RGB LED を使って、様々な色で LED を点灯します。 3つ口のある LED というだけなので、それほど通常の L チカと違う感じではありません。

https://akizukidenshi.com/catalog/g/gI-02476/

が、サクッと家のどこかに埋まっている RGB LED を発掘できなかったので、nRF52840-DK の LED を3つ使って代替しました。

Internal Temperature Sensor

nRF52840 に搭載されている内蔵温度計の温度を defmt を使って出力します。 別途 UART がいらないので、ここは非常に体験が良いです。

3_temperature.rs

More about Methods

ここまでで作ったものをリファクタリングします。 この、どのピン選んでも動くようにジェネリックな型にするの良いですね。 (組込み Rust 本でもやりたかったのですが、お蔵入りになってます)

- struct LEDState {
-     r: P0_03<Output<PushPull>>,
-     b: P0_04<Output<PushPull>>,
-     g: P0_28<Output<PushPull>>,
- }
+ struct LEDColor {
+     r: Pin<Output<PushPull>>,
+     b: Pin<Output<PushPull>>,
+     g: Pin<Output<PushPull>>,
+ }

初期化も次のよな感じで、GPIO ピンのモードをジェネリックパラメータにして、どんなモードのピンでも関数の引数に指定できるようになっています。

pub fn init<Mode>(led_red: Pin<Mode>, led_blue: Pin<Mode>, led_green: Pin<Mode>) -> LEDColor {

    LEDColor {
        r: led_red.into_push_pull_output(Level::High),
        b: led_blue.into_push_pull_output(Level::High),
        g: led_green.into_push_pull_output(Level::High),
    }
}

Adding User - Input

ボタン入力を受け付けるやつです。 ボタンを押している間、LED が点灯するプログラムを作成します。 組込み Rust 本執筆中は読んでなかったのですが、やっぱ同じような過程を経るものですねぇ。

Adding User Input - Advanced

もう少し真面目にボタンが押された瞬間を受け付けます。 次のような型を定義して、立ち上がりエッジを検出します。

struct Button {
    pin: Pin<Input<PullUp>>,
    was_pressed: bool,
}

ボタンが押されたら、温度を表示する単位を変換するコードを作成します。

Bringing it all Together

RGB LED と、温度とボタンを組み合わせたプログラムを作成します。 組み合わせだけなので、新しいことはないです。

次回とうとうお高い CO2 センサが登場します。

Knurling Sessions 2020Q4 をやる (1) 〜環境構築〜

はじめに

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

ハードウェア

ferrous-systems.com

主要なもの - nRF52840-DK (¥6,000くらい) - Mouser とか Digikey とかマルツで購入できます - SCD30 CO2 センサ (¥6,000くらい) - Digi-Key

あと、ePaper ディスプレイが挙げられていますが、いくつか SPI / I2C 接続可能なディスプレイデバイスを持っているので、それで代用することにします (embedded-graphics 使っているので大丈夫なはず) 。

ケーブル類など - RGB LED / 220Ω 抵抗器3つ - なくても nRF52840-DK の LED で代用可能 - ジャンパワイヤ - ピンヘッダ

ツール

cargo install でインストールします。

cargo install cargo-generate
cargo install probe-run
cargo install flip-link

Linux

USB ドライバと udev の設定をします。

sudo apt-get install libudev-dev libusb-1.0-0-dev

udev は knurling-session の手順では、JLink の Product ID が異なる場合があります。

$ cat /etc/udev/rules.d/50-knurling.rules
# udev rules to allow access to USB devices as a non-root user

# nRF52840 Development Kit
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", TAG+="uaccess"

nRF52840-DK を接続して、lsusb で Product ID を確認して、udev rule を書き換えるとうまく動きます。 私の場合は、0105 でした。

$ lsusb
Bus 001 Device 012: ID 1366:0105 SEGGER J-Link
sudo udevadm control --reload-rules

これで準備完了です。

『基礎から学ぶ 組込みRust』を書きました

はじめに

2021年4月20日、『基礎から学ぶ 組込みRust』(C&R研究所) を出版します。Rust の文法から組込み Rust でファームウェアを作成するところまでを、片手で持てる (多分!まだ持ったことないけど!) 1 冊の本にまとめた、喉から手が出るほど (私が) 求めていた書籍です。 先日、無事入稿を果たしたので、今の気持ちを徒然なるまま綴ったのが、このエントリです。

基礎から学ぶ 組込みRust

基礎から学ぶ 組込みRust

一番始めに言いたいこととしては、今現在、「組込み Rust がプロダクションレディか?」、と問われると、「ほとんどのプロジェクトに対してそうではない」というのが私個人の見解です。セーフティクリティカルな分野では、機能安全をはじめとする認証の問題があり、そんなにおいそれとプログラミング言語変更できないことも承知しています。

でも、その上で言いたい!
プログラミング言語は進化していて、Rust は本当に良いプログラミング言語です!私は組込み製品開発で Rust を使いたいと強く望みます。 C/C++ の他にもう1つくらい、選択肢があっても良いと思いませんか?思いますね!思いましょう!
Rust を有力な選択肢とするためにはエコシステムの発展が欠かせません。そのためには関わる人口を増やさねば!と考えたわけです。そんなおり、今回の書籍執筆のお話をいただいて、本当に価値ある書籍を書けるかどうか不安に思いながらも、本書を執筆するにいたりました。

普段から Rust を書いている方は、これを機に組込み Rust にも興味持って頂けると嬉しいです。 本業が組込みの方は、とりあえず仕事で使うかどうかは置いておいて、最近話題になってるけどどんなもんかな、という気持ちで触ってもらえると幸いです。 けっこう既存のドキュメントにはない、コードリーディングとトライ&エラー繰り返して習得したこと、いっぱい書きました。

あと、冒頭でお知らせしておきたいのは、非常に残念なことながら、本書のカバー内容ではプロユースできるレベルには到達できません。そういう期待を持って本書に興味を持ってくださった方は、ごめんなさい!今後にご期待下さい。

私と Rust

私が Rust を学び始めたのは、3年前からで、比較的新参者と言えるでしょう。当初から C/C++ 以外で組込みで使える言語ないかなぁ、というモチベーションでした。 Rust の入門を済ませて、組込み Rust のドキュメント3本 (The Embedded Rust Book, Discovery, Embedonomicon) を夢中で読み、「これはイケる!」という結論になりました。

当時は、今よりさらに組込み Rust やっている人が少なくて、まず仲間を増やすことが第一歩だな、と考えたことを覚えています。 先述の組込み Rust ドキュメントの和訳が存在していなかったため、まずリーチできる日本語の情報源を増やそう、ということで、2018年の年末からドキュメントの和訳を開始しました。おおよそ半年かけて3本のドキュメントを和訳しました。

この頃、ブログでも積極的に組込み Rust のエントリを書き、Interface のイベントやったり、第1回技書博で組込み/ベアメタルRustクックブック出したりしていました。

そして記念すべき、Interface 2020年5月号 に組込み Rust の特集が掲載され、少しずつ活動の芽が出てきている感じがしていました。

その後、私事ですが、次男が産まれたことで少し活動の時間が取りにくくなり、なんやかんやしている間に本書の執筆をすることになりました (雑。

これは内緒なのですが、実践Rustプログラミング入門に組込みの章があって、組込み Rust の認知度が上がるの良いぞぉ、と思う半面、先を越された!と本気で悔しがっておりました。

書籍執筆の経緯

まさかこんなに早く組込み Rust を題材にした書籍を出版する機会が訪れるとは思ってもみませんでした。 現在担当してくださっている方から、Rust の基礎を解説する書籍執筆の依頼を受けました。

この時点で内心ウキウキでしたが、1つものすごい不安がありました。それは、「Rust の基礎を解説する書籍」の執筆依頼だったことです。 正直、組込み Rust という特定分野ですらあやしいのに、Rust の基礎を解説するのに私という人選が良いとは思えなかったわけです。 なので、組込み Rust に関してだったら書けると思うけど、本当に Rust の基礎が必要なら不適任です、という返信をしました。 この時点で、「多分お断りだろうなぁ…」と8割方諦めていました。

先方から、「組込み Rust でええよ」(関西弁ではなかったですが) 、という予想外の返答が返ってきたので、心底驚きました。 この機会を逃すと次がいつになるかわかったものではないな、という打算もあり、Rust の文法から組込み Rust を扱う、という企画で執筆依頼を受けました。

Wio Terminal を選んだ理由

企画の当初から、Rust の文法解説から始めて、最終的にターゲットボードでアプリケーションを作る、という流れで話を進めていました。 そこで、ネックになったのが、ターゲットボード何にするか?です。
Discovery book だと STM32F3Discovery を採用しているのですが、現在だと少し入手性が悪くなっており、ドキュメントの内容終わった後も何して遊んで良いものか、という感想を持っていました。 (Discovery book は micro:bit 使うバージョンへの書き換えが進行中です)

そこで、当面は入手性が良さそうで、遊びがいがあって、安くて (3,000円くらい)、GDB デバッグできるもの、という条件で探していました。 遊びがい、という意味では、画面欲しいよね、と思ってました。やっぱわかりやすく遊べるので。embedded-graphics クレートの存在も知っていたので、対応するドライバがあるやつで探していると、意外と STM32 の評価ボードは高かったりで難航していました…。

当時、まだ共著じゃなかった井田さんに良いボードない?って質問したところ、Wio Terminal を紹介されました。 Wio Terminal は色々デバイスが載っているわりに、4,000円弱で手に入って、ちょっと改造すれば GDB デバッグもできます。 本の内容一通りやった後でも、色々遊べそうということもあり、Wio Terminal をターゲットにすることにしました。

Wio Terminal と Rust でいくなら、井田さんも書こうよ、という話をして、このあたりで引きずり込みました。

f:id:tomo-wait-for-it-yuki:20210329203923p:plain
かにさんを Wio Terminal に描写して遊びます

基礎から学ぶ組込みRust の良いところ

Rust の (最低限の) 文法から、組込み Rust のアプリケーション開発まで1冊の本にまとまっていることです。 この範囲を1冊でカバーしている本は、いまのところないはずです。 特に、embedded-hal トレイトの解説や BSP クレートを使ったアプリケーション作成方法は、あまりまとまった情報がないので、それが書かれているのは1つの特徴です。

ただ、Rust に入門する目的では、本書に掲載している文法の章を読むより、The Rust Programming Language 読んだり、他の入門書読む方が良いです。 またページ数の都合上、ドライバ書いたり、ブートストラップ書いたり、組込み Rust のリアルタイムフレームワーク RTIC を使ったりする内容は書けませんでした (無念じゃー!) 。

もう1つ重要な良いところがあります。 それは、私がしばらくは embedded-hal を取り扱った入門書を書かなくて済むことです! とにかく組込み Rust の認知度をあげるための活動を第一に行っていたわけですが、そのために自分が Rust を書く時間が少なくなっていました。 書籍発売で1つの区切りもでき、今後は自分が何か作りながら、その過程をまとめて公表できればなぁ、と思います。

書籍の想定読者と内容

組込みも Rust もあまり知らない状態からでも読めるようにしたつもりです。 しかし、どちらかの入門が済んでいる方が読みやすいと思います。どちらかというと、Rust の入門が済んでいる方が良いと思います。

C/C++/Rust 未経験者が本書を読んでどう感じるか、は未知数ですが、ちょっと色々話がつながらないところが出てくるのか、と思ってます。

回路図も参照しながら、こうデバイスがつながっているから、実装がこうなっているんだよ、という解説も書きました。 本書を読み終わった後でも、Wio Terminal 上の本書で取り扱っていないデバイス動かしたり、別のボード使うときに雰囲気だけでも読めると捗るはずです。 回路について、詳細な解説はしていません。なので回路図を見たことない方も気負わず読めると思います。

本書内で扱うデバイスは次の通りです。

  • LEDとボタン / GPIO
  • シリアル通信 / UART
  • タイマ / 割り込み
  • ブザー / PWM
  • 光センサ / ADC
  • 加速度センサ / I2C
  • 液晶ディスプレイ / SPI

無線はまだ動かないので、今後にご期待下さい!

サポートサイト

本書のサポートサイトです。本書について質問があれば、Issue にて受け付けています。また、本書で使うハードウェア一覧を掲載していますので、ぜひ発売日までにハードウェアを入手して、本の購入とともに Wio Terminal で遊んでいただければ幸いです。

目次を節レベルまで掲載していますので、ご購入の参考にして下さい。

GitHub - tomoyuki-nakabayashi/Embedded-Rust-from-Basics: 中林智之、井田健太が執筆した『基礎から学ぶ 組込みRust』 (C&R研究所) のサポートサイトです。