Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

離れた場所での不気味な作用

OUT は、ポート P0 のピンを制御できる唯一のレジスタではありません。OUTSET レジスタも ピンの値を変更できますし、OUTCLR も同様です。ただし、OUTSETOUTCLR では ポート P0 の現在の出力状態を取得することはできません。

OUTSETProduct 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 に書き込むたびに、その値が変化していることがわかります。