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

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

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

Section 11.4.6 GPIO port output data register - Page 239

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

#![no_main]
#![no_std]

use core::ptr;

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

#[entry]
fn main() -> ! {
    let mut itm = aux7::init().0;

    unsafe {
        const GPIOE_BSRR: u32 = 0x4800_1018;
        const GPIOE_ODR: u32 = 0x4800_1014;

        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);

        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 << 11);

        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 + 16));

        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 << (11 + 16));
    }

    loop {}
}

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

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

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