複数のレジスタを読む
IRA_REG_M
レジスタを読むことは、I2Cプロトコルの理解を試すには良いものでした。
しかし、レジスタの内容はおもしろみのない情報です。
今回は、実際のセンサの測定値がわかる磁力計のレジスタを読みます。
6つの連続したレジスタが関係しており、そのレジスタは0x03
番地のOUT_X_H_M
から始まります。
前のプログラムを、これら6つのレジスタを読むように修正します。ほんの少しの修正だけで済みます。
磁力計に要求するアドレスを、IRA_REG_M
からOUT_X_H_M
に変更します。
#![allow(unused)] fn main() { // 読みたい`OUT_X_H_M`レジスタのアドレスを送信します i2c1.txdr.write(|w| w.txdata().bits(OUT_X_H_M)); }
1バイトだけではなく、6バイトを要求します。
#![allow(unused)] fn main() { // RESTARTをブロードキャストします // 磁力計のアドレスをR/WビットをReadに設定して、ブロードキャストします i2c1.cr2.modify(|_, w| { w.start().set_bit(); w.nbytes().bits(6); w.rd_wrn().set_bit(); w.autoend().set_bit() }); }
1バイトだけ読むのではなく、バッファを埋めます。
#![allow(unused)] fn main() { let mut buffer = [0u8; 6]; for byte in &mut buffer { // レジスタの内容を受信するまで待ちます while i2c1.isr.read().rxne().bit_is_clear() {} *byte = i2c1.rxdr.read().rxdata().bits(); } // STOPをブロードキャストします(`AUTOEND = 1`なので自動です) }
データのスループットを減らすための遅延と共に、これらをループ内にまとめると、次のようになります。
#![deny(unsafe_code)] #![no_main] #![no_std] #[allow(unused_imports)] use aux14::{entry, iprint, iprintln, prelude::*}; // スレーブアドレス const MAGNETOMETER: u8 = 0b001_1110; // 磁力計レジスタのアドレス const OUT_X_H_M: u8 = 0x03; const IRA_REG_M: u8 = 0x0A; #[entry] fn main() -> ! { let (i2c1, mut delay, mut itm) = aux14::init(); loop { // STARTをブロードキャストします // 磁力計のアドレスをR/WビットをWriteに設定して、ブロードキャストします i2c1.cr2.write(|w| { w.start().set_bit(); w.sadd().bits(MAGNETOMETER); w.rd_wrn().clear_bit(); w.nbytes().bits(1); w.autoend().clear_bit() }); // 次のデータを送信できるようになるまで、待ちます while i2c1.isr.read().txis().bit_is_clear() {} // 読みたい`OUT_X_H_M`レジスタのアドレスを送信します i2c1.txdr.write(|w| w.txdata().bits(OUT_X_H_M)); // 前のバイトが送信されるまで待ちます while i2c1.isr.read().tc().bit_is_clear() {} // RESTARTをブロードキャストします // 磁力計のアドレスをR/WビットをReadに設定して、ブロードキャストします i2c1.cr2.modify(|_, w| { w.start().set_bit(); w.nbytes().bits(6); w.rd_wrn().set_bit(); w.autoend().set_bit() }); let mut buffer = [0u8; 6]; for byte in &mut buffer { // レジスタの内容を受信するまで待ちます while i2c1.isr.read().rxne().bit_is_clear() {} *byte = i2c1.rxdr.read().rxdata().bits(); } // STOPをブロードキャストします(`AUTOEND = 1`なので自動です) iprintln!(&mut itm.stim[0], "{:?}", buffer); delay.delay_ms(1_000_u16); } }
これを実行すると、毎秒新しい6バイトの配列がitmdump
のコンソールに表示されるはずです。
配列内の値は、ボードを動かすと変化するはずです。
$ # itmdump terminal
(..)
[0, 45, 255, 251, 0, 193]
[0, 44, 255, 249, 0, 193]
[0, 49, 255, 250, 0, 195]
しかし、これらのバイト列は、それほど意味がありません。実際の測定値に変換しましょう。
#![allow(unused)] fn main() { let x_h = u16::from(buffer[0]); let x_l = u16::from(buffer[1]); let z_h = u16::from(buffer[2]); let z_l = u16::from(buffer[3]); let y_h = u16::from(buffer[4]); let y_l = u16::from(buffer[5]); let x = ((x_h << 8) + x_l) as i16; let y = ((y_h << 8) + y_l) as i16; let z = ((z_h << 8) + z_l) as i16; iprintln!(&mut itm.stim[0], "{:?}", (x, y, z)); }
これで、より見やすくなるはずです。
$ # `itmdump terminal
(..)
(44, 196, -7)
(45, 195, -6)
(46, 196, -9)
これは、磁力計のXYZ軸で分解された地球磁場です。
次のセクションでは、これらの数字を理解する方法を学びます。