離れた場所での不気味な作用
OUT は、ポート P0 のピンを制御できる唯一のレジスタではありません。OUTSET レジスタも
ピンの値を変更できますし、OUTCLR も同様です。ただし、OUTSET と OUTCLR では
ポート P0 の現在の出力状態を取得することはできません。
OUTSET は Product Specification に次のように記載されています。
6.8.2.2 項。OUTSET - 145 ページ
次のプログラムを見てみましょう。このプログラムの要となるのは fn print_out です。この関数は、
OUT の現在の値を RTT コンソールに出力します(examples/spooky.rs)。
#![no_main]
#![no_std]
use core::ptr;
#[allow(unused_imports)]
use registers::{entry, rprintln};
// Print the current contents of P0.OUT
fn print_out() {
const P0_OUT: u32 = 0x5000_0504;
let out = unsafe { ptr::read_volatile(P0_OUT as *const u32) };
rprintln!("P0.OUT = {:#08x}", out);
}
#[entry]
fn main() -> ! {
registers::init();
unsafe {
// A bunch of magic addresses!
const P0_OUTSET: u32 = 0x5000_0508;
const P0_OUTCLR: u32 = 0x5000_050C;
// Print the initial contents of OUT
print_out();
// Turn on the top LED row
ptr::write_volatile(P0_OUTSET as *mut u32, 1 << 21);
print_out();
// Turn on the bottom LED row
ptr::write_volatile(P0_OUTSET as *mut u32, 1 << 19);
print_out();
// Turn off the top LED row
ptr::write_volatile(P0_OUTCLR as *mut u32, 1 << 21);
print_out();
// Turn off the bottom LED row
ptr::write_volatile(P0_OUTCLR as *mut u32, 1 << 19);
print_out();
}
loop {
core::hint::spin_loop();
}
}
このプログラムを実行すると、次のように表示されます。
$ cargo embed
# cargo-embed's console
(..)
15:13:24.055: P0.OUT = 0x000000
15:13:24.055: P0.OUT = 0x200000
15:13:24.055: P0.OUT = 0x280000
15:13:24.055: P0.OUT = 0x080000
15:13:24.055: P0.OUT = 0x000000
副作用です!実際には変更していない同じアドレスを何度も読み取っているにもかかわらず、
OUTSET または OUTCLR に書き込むたびに、その値が変化していることがわかります。