ドライバを使う

5章ですでに触れたとおり、embedded-halが提供する抽象化のおかげで、プラットフォームに依存することなくハードウェアとやりとりするコードを書くことができます。実際に、7章と8章でこれまでに使用したメソッドはすべてembedded-halが定義するトレイトから来ていました。ここで私たちも初めてembedded-halのトレイトを利用してみましょう。

Rustがサポートする(そして将来サポートするであろう)すべての組込みプラットフォームに別々のLSM303AGR用ドライバを開発しなくてはならないとしたら、それはまったくもって無駄なことです。それを避けるために、embedded-halトレイトを実装したジェネリック型を消費するコードを書き、プラットフォームに依存しないドライバを作ります。幸運なことに、その作業はすでにlsm303agr クレート内でなされています。ですから加速度計、磁力計の値を読み取るのは、(少しばかりドキュメンテーションを読むことを除けば)基本的にプラグアンドプレイです。実際に、crates.ioのページを見れば、Raspberry Pi向けにではありますが、加速度計のデータを読み取るのに必要な情報はすべて書いてあります。あとはそれを私たちが使うチップ向けに修正するだけです。

use linux_embedded_hal::I2cdev;
use lsm303agr::{AccelOutputDataRate, Lsm303agr};

fn main() {
    let dev = I2cdev::new("/dev/i2c-1").unwrap();
    let mut sensor = Lsm303agr::new_with_i2c(dev);
    sensor.init().unwrap();
    sensor.set_accel_odr(AccelOutputDataRate::Hz50).unwrap();
    loop {
        if sensor.accel_status().unwrap().xyz_new_data {
            let data = sensor.accel_data().unwrap();
            println!("Acceleration: x {} y {} z {}", data.x, data.y, data.z);
        }
    }
}

embedded_hal::blocking::i2cトレイトを実装したオブジェクトのインスタンス生成方法は前のページで確認しましたから、修正は簡単なはずです。

#![deny(unsafe_code)]
#![no_main]
#![no_std]

use cortex_m_rt::entry;
use rtt_target::{rtt_init_print, rprintln};
use panic_rtt_target as _;

#[cfg(feature = "v1")]
use microbit::{
    hal::twi,
    pac::twi0::frequency::FREQUENCY_A,
};

#[cfg(feature = "v2")]
use microbit::{
    hal::twim,
    pac::twim0::frequency::FREQUENCY_A,
};

use lsm303agr::{
    AccelOutputDataRate, Lsm303agr,
};

#[entry]
fn main() -> ! {
    rtt_init_print!();
    let board = microbit::Board::take().unwrap();


    #[cfg(feature = "v1")]
    let i2c = { twi::Twi::new(board.TWI0, board.i2c.into(), FREQUENCY_A::K100) };

    #[cfg(feature = "v2")]
    let i2c = { twim::Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100) };

    // ドキュメンテーションからのコード
    let mut sensor = Lsm303agr::new_with_i2c(i2c);
    sensor.init().unwrap();
    sensor.set_accel_odr(AccelOutputDataRate::Hz50).unwrap();
    loop {
        if sensor.accel_status().unwrap().xyz_new_data {
            let data = sensor.accel_data().unwrap();
            // printの代わりにRTTを使用します
            rprintln!("Acceleration: x {} y {} z {}", data.x, data.y, data.z);
        }
    }
}

前のページでやったように、以下のコマンドでこのプログラムを試すことができます。

# For micro:bit v2
$ cargo embed --features v2 --target thumbv7em-none-eabihf

# For micro:bit v1
$ cargo embed --features v1 --target thumbv6m-none-eabi

さらに、もしmicro:bitを(物理的に)動かしてみれば、画面にプリントされる加速度計の値が変化するのを確認できるでしょう。