如何在 Rust 中写入内存映射地址?

问题描述 投票:0回答:3

我正在尝试用 Rust 为 STM32F1xx 制作“Blinky”。 我知道有它的库,但我想制作自己的“库”以用于学习目的。

我可以通过 C: 中的地址访问 STM32 的“寄存器”

*(uint32_t*)(0x40021000 + 0x018) |= 0x10;
*(uint32_t*)(0x40011000 + 0x004) |= 0x33;
*(uint32_t*)(0x40011000 + 0x004) &= ~0xCC;
*(uint32_t*)(0x40011000 + 0x10) |= 0x300;

while(1) {}

这会将一些位写入

RCC_APB2ENR
寄存器以启用端口 C 的时钟、配置引脚并启用 Discovery 上的 LED。

我需要用 Rust 重新编写它,以制作 const、fns 并开始编写漂亮的 Rusty 代码。 Rust 中是否可以在没有 FFI 调用 C 代码的情况下实现?我可以使用

asm!
宏来实现此目的吗?

rust embedded mmap
3个回答
12
投票

在 C 中,访问硬件寄存器时,您应该将指针声明为

volatile
,以便编译器完全按照您编程的方式进行访问。否则,它可能会对它们重新排序或消除对同一寄存器的重复访问。

从 Rust 1.9 开始(感谢这个 RFC),你可以使用

core::ptr::read_volatile
core::ptr::write_volatile
来读写这样的内存。

如果您有旧版本的 Rust,它们可以在

core::intrinsics
中以
volatile_read
volatile_store 的形式提供,但是它们永久不稳定,因此需要 Rust 的夜间版本才能访问它们。


9
投票

函数

read_volatile
write_volatile
自 1.9 版本以来就稳定了,所以你应该使用它们。借用@ker的翻译样本进行演示:

use std::ptr::{read_volatile, write_volatile};

const A: *mut u32 = (0x40021000 + 0x018) as *mut u32;
const B: *mut u32 = (0x40011000 + 0x004) as *mut u32;
const C: *mut u32 = (0x40011000 + 0x10) as *mut u32;
unsafe {
    write_volatile(A, read_volatile(A) | 0x10);
    write_volatile(B, read_volatile(B) | 0x33);
    write_volatile(B, read_volatile(B) & !0xCC);
    write_volatile(C, read_volatile(C) | 0x300);
}

此外,

volatile
板条箱提供了围绕易失性访问的值的包装类型。

use std::ptr::NonNull;

use volatile::VolatilePtr; // 0.5

const A: *mut u32 = (0x40021000 + 0x018) as *mut u32;
const B: *mut u32 = (0x40011000 + 0x004) as *mut u32;
const C: *mut u32 = (0x40011000 + 0x10) as *mut u32;


unsafe {
    let volatile_a = VolatilePtr::new(NonNull::new_unchecked(A));
    let volatile_b = VolatilePtr::new(NonNull::new_unchecked(B));
    let volatile_c = VolatilePtr::new(NonNull::new_unchecked(C));

    volatile_a.update(|x| x | 0x10);
    volatile_b.update(|x| x & !0xCC);
    volatile_c.update(|x| x | 0x300);
}

2
投票

rust 在标准库中有

std::ptr
模块。它提供了像
ptr::read
ptr::write
这样的函数,这些函数比取消引用更加明确。

所以你的例子是

const A: *mut u32 = (0x40021000 + 0x018) as *mut u32;
const B: *mut u32 = (0x40011000 + 0x004) as *mut u32;
const C: *mut u32 = (0x40011000 + 0x10) as *mut u32;
unsafe {
    ptr::write(A, ptr::read(A) | 0x10);
    ptr::write(B, ptr::read(B) | 0x33);
    ptr::write(B, ptr::read(B) & !0xCC);
    ptr::write(C, ptr::read(C) | 0x300);
}

更简洁的版本是使用解引用,但这仅适用于

Copy
类型:

*A |= 0x10;
*B |= 0x33;
*B &= !0xCC;
*C |= 0x300;
© www.soinside.com 2019 - 2024. All rights reserved.