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

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

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