レジスタを読む

では理論を実践してみましょう!

まず加速度計(accelerometer)と磁力計(magnetometer)それぞれのスレーブアドレスを知る必要があります。その情報はLSM303AGRのデータシートの39ページにあります。

  • 0011001 が加速度計のアドレス
  • 0011110 が磁力計のアドレス

アドレスは上位7ビットだけで表されることを思い出してください。8番目のビットは読み込みか書き込みかを指定するビットとなります。

次に読み出しのためのレジスタが必要です。多くのI2Cチップはデバイスを識別するためのレジスタを持っています。というのも、何千もの(あるいは何百万もの)I2Cチップが流通しているわけですから、同じアドレスを持つ別製品が製造されていてもおかしくないからです。(結局のところ、アドレスはたったの7ビット幅なのですから。)このデバイスIDレジスタを利用することで、たまたま同じアドレスを持った別のチップではなく、本当にLSM303AGRと通信していることを確認することができるのです。データシート(46と61ページを参照)にあるように、LSM303AGRはアドレス0x0fWHO_AM_I_A(Aは加速度計を指す)、アドレス0x4fWHO_AM_I_M(Mは磁力計を指す)というふたつのレジスタを提供しており、それぞれにはデバイス特有の値が入っています。

ここまできたらあとはソフトウェアです。つまり、microbitHALのどのAPIを使うか、です。ところがnRFチップのデータシートを読み通してみると、nRFチップはI2Cペリフェラルを持っていないことに気がつくでしょう。ですが幸いなことに、I2Cと互換性のあるTWI (Two Wire Interface)、またはTWIMと呼ばれるペリフェラルがあります。(UARTとUARTEのように、チップによって名称が違うのです。)

ではmicrobitクレートのtwi(m) モジュールのドキュメンテーションとこれまでに集めた情報を参考にしながら、ふたつのデバイスIDを読み取ってプリントするコードを書きましょう。このようなものになるはずです。

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

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

use microbit::hal::prelude::*;

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

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

const ACCELEROMETER_ADDR: u8 = 0b0011001;
const MAGNETOMETER_ADDR: u8 = 0b0011110;

const ACCELEROMETER_ID_REG: u8 = 0x0f;
const MAGNETOMETER_ID_REG: u8 = 0x4f;

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


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

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

    let mut acc = [0];
    let mut mag = [0];

    // First write the address + register onto the bus, then read the chip's responses
    i2c.write_read(ACCELEROMETER_ADDR, &[ACCELEROMETER_ID_REG], &mut acc).unwrap();
    i2c.write_read(MAGNETOMETER_ADDR, &[MAGNETOMETER_ID_REG], &mut mag).unwrap();

    rprintln!("The accelerometer chip's id is: {:#b}", acc[0]);
    rprintln!("The magnetometer chip's id is: {:#b}", mag[0]);

    loop {}
}

これまでの説明を理解していれば、初期化の仕方を除き、コード自体は単純なはずです。初期化はUARTで見たものと似ています。コンストラクタにペリフェラル、通信に使うピン、バスを駆動する周波数を渡してやります。周波数は、ここでは100kHz(K100)とします。

Testing it

テストしましょう

いつものようにEmbed.tomlをお使いのMCU向けに修正し、以下を実行してこのプログラムをテストしましょう。

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

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