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. Однако OUTSET и OUTCLR не позволяют узнать текущее состояние выходов порта P0.

Регистр OUTSET описан в спецификации продукта:

Подраздел 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};

// Выводим текущее содержимое 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 {
        // Куча «магических» адресов!
        const P0_OUTSET: u32 = 0x5000_0508;
        const P0_OUTCLR: u32 = 0x5000_050C;

        // Выводим начальное содержимое OUT
        print_out();

        // Включаем верхний ряд светодиодов
        ptr::write_volatile(P0_OUTSET as *mut u32, 1 << 21);
        print_out();

        // Включаем нижний ряд светодиодов
        ptr::write_volatile(P0_OUTSET as *mut u32, 1 << 19);
        print_out();

        // Выключаем верхний ряд светодиодов
        ptr::write_volatile(P0_OUTCLR as *mut u32, 1 << 21);
        print_out();

        // Выключаем нижний ряд светодиодов
        ptr::write_volatile(P0_OUTCLR as *mut u32, 1 << 19);
        print_out();
    }

    loop {
        core::hint::spin_loop();
    }
}

Если запустить эту программу, увидите следующее:

$ cargo embed
# консоль cargo-embed
(..)
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.