離れた場所での不気味な作用
BSRR は Port E のピンを制御できる唯一のレジスタではありません。ODR レジスタでも
ピンの値を変更できます。さらに、ODR では Port E の現在の出力
状態も取得できます。
ODR については次に記載されています:
11.4.6 節 GPIO ポート出力データレジスタ - 239 ページ
このプログラムを見てみましょう。このプログラムの鍵
となるのは fn iprint_odr です。この関数は ODR の現在の
値を ITM コンソールに表示します
#![no_main]
#![no_std]
use core::ptr;
#[allow(unused_imports)]
use aux7::{entry, iprintln, ITM};
// odr の現在の内容を表示する
fn iprint_odr(itm: &mut ITM) {
const GPIOE_ODR: u32 = 0x4800_1014;
unsafe {
iprintln!(
&mut itm.stim[0],
"ODR = 0x{:04x}",
ptr::read_volatile(GPIOE_ODR as *const u16)
);
}
}
#[entry]
fn main() -> ! {
let mut itm= aux7::init().0;
unsafe {
// 魔法のアドレスたち!
const GPIOE_BSRR: u32 = 0x4800_1018;
// ODR の初期内容を表示する
iprint_odr(&mut itm);
// "North" LED(赤)を点灯する
ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << 9);
iprint_odr(&mut itm);
// "East" LED(緑)を点灯する
ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << 11);
iprint_odr(&mut itm);
// "North" LED を消灯する
ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << (9 + 16));
iprint_odr(&mut itm);
// "East" LED を消灯する
ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << (11 + 16));
iprint_odr(&mut itm);
}
loop {}
}
このプログラムを実行すると
$ cargo run
(..)
Breakpoint 1, registers::__cortex_m_rt_main_trampoline () at src/07-registers/src/main.rs:22
22 #[entry]
(gdb) continue
Continuing.
itmdump のコンソールには次のように表示されます:
$ # itmdump のコンソール
(..)
ODR = 0x0000
ODR = 0x0200
ODR = 0x0a00
ODR = 0x0800
ODR = 0x0000
副作用です! 実際には変更していない同じアドレスを複数回読み取っているにもかかわらず、
BSRR に書き込まれるたびにその値が変化することがわかります。