異なる場所での不気味な動作

ポートEのピンを制御できるレジスタは、BSRRだけではありません。ODRレジスタもピンの値を変更できます。 さらに、ODRを使って、ポートEの現在の出力状態を取得できます。

ODRについては、下記に書かれています。

Section 11.4.6 GPIO port output data register - Page 239

次のプログラムを試してみましょう。

#![allow(unused)]
#![no_main]
#![no_std]

fn main() {
use core::ptr;

#[allow(unused_imports)]
use aux7::{entry, iprintln, ITM};

// Print the current contents of 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)
        );
    }
}

        // 北のLEDの(赤)を点灯
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << 9);

    unsafe {
        // A magic addresses!
        const GPIOE_BSRR: u32 = 0x4800_1018;

        // 東のLEDの(緑)を点灯
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << 11);

        // Turn on the "North" LED (red)
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << 9);
        iprint_odr(&mut itm);

        // 北のLEDのを消灯
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << (9 + 16));

        // Turn off the "North" LED
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << (9 + 16));
        iprint_odr(&mut itm);

        // 東のLEDのを消灯
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << (11 + 16));
        iprint_odr(&mut itm);
    }

    loop {}
}
}

このプログラムを実行すると、次の出力が得られます。

$ # itmdump's console
(..)
ODR = 0x0000
ODR = 0x0200
ODR = 0x0a00
ODR = 0x0800
ODR = 0x0000

副作用!実際の値を変更することなしに、複数回同じアドレスを読み込んでいるにも関わらず、毎回BSRRに書き込んだ値に変化していることがわかります。