レジスタを読む
では理論を実践してみましょう!
まず加速度計(accelerometer)と磁力計(magnetometer)それぞれのスレーブアドレスを知る必要があります。その情報はLSM303AGRのデータシートの39ページにあります。
- 0011001 が加速度計のアドレス
- 0011110 が磁力計のアドレス
注 アドレスは上位7ビットだけで表されることを思い出してください。8番目のビットは読み込みか書き込みかを指定するビットとなります。
次に読み出しのためのレジスタが必要です。多くのI2Cチップはデバイスを識別するためのレジスタを持っています。というのも、何千もの(あるいは何百万もの)I2Cチップが流通しているわけですから、同じアドレスを持つ別製品が製造されていてもおかしくないからです。(結局のところ、アドレスはたったの7ビット幅なのですから。)このデバイスIDレジスタを利用することで、たまたま同じアドレスを持った別のチップではなく、本当にLSM303AGRと通信していることを確認することができるのです。データシート(46と61ページを参照)にあるように、LSM303AGRはアドレス0x0f
にWHO_AM_I_A
(Aは加速度計を指す)、アドレス0x4f
にWHO_AM_I_M
(Mは磁力計を指す)というふたつのレジスタを提供しており、それぞれにはデバイス特有の値が入っています。
ここまできたらあとはソフトウェアです。つまり、microbit
HALのどの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