我如何写入 Rust 中的内存映射地址?
How do I write to a memory-mapped address in Rust?
我正在尝试用 Rust 为 STM32F1xx 制作 "Blinky"。
我知道有它的库,但我想制作自己的 "lib" 用于学习目的。
我可以通过 C:
中的地址访问 STM32 的 "registers"
*(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 重写它,制作 consts、fns 并开始编写漂亮的 Rusty 代码。在没有 FFI 调用 C 代码的情况下,Rust 是否可能?我可以用 asm!
宏实现吗?
rust 有 std::ptr
module in the standard library. It offers functions like ptr::read
and 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;
在 C 中,访问硬件寄存器时,您应该将指针声明为 volatile
,以便编译器完全按照您的编程进行访问。否则它可以重新排序它们或消除对同一寄存器的重复访问。
从 Rust 1.9 开始(多亏了这个 RFC)你可以使用 core::ptr::read_volatile
和 core::ptr::write_volatile
来读写这样的内存。
如果您有旧版本的 Rust,可以在 core::intrinsics 中找到 volatile_read
和 volatile_store
,但是它们永远不稳定,因此需要每晚版本的 Rust访问它们。
函数 read_volatile
and 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
crate 为可变访问值提供了包装类型。
use volatile::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;
const volatile_A = A as *mut Volatile<u32>;
const volatile_B = B as *mut Volatile<u32>;
const volatile_C = C as *mut Volatile<u32>;
unsafe {
(*volatile_A).update(|x| *x | 0x10);
(*volatile_B).update(|x| *x & !0xCC);
(*volatile_C).update(|x| *x | 0x300);
}
我正在尝试用 Rust 为 STM32F1xx 制作 "Blinky"。 我知道有它的库,但我想制作自己的 "lib" 用于学习目的。
我可以通过 C:
中的地址访问 STM32 的 "registers"*(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 重写它,制作 consts、fns 并开始编写漂亮的 Rusty 代码。在没有 FFI 调用 C 代码的情况下,Rust 是否可能?我可以用 asm!
宏实现吗?
rust 有 std::ptr
module in the standard library. It offers functions like ptr::read
and 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;
在 C 中,访问硬件寄存器时,您应该将指针声明为 volatile
,以便编译器完全按照您的编程进行访问。否则它可以重新排序它们或消除对同一寄存器的重复访问。
从 Rust 1.9 开始(多亏了这个 RFC)你可以使用 core::ptr::read_volatile
和 core::ptr::write_volatile
来读写这样的内存。
如果您有旧版本的 Rust,可以在 core::intrinsics 中找到 volatile_read
和 volatile_store
,但是它们永远不稳定,因此需要每晚版本的 Rust访问它们。
函数 read_volatile
and 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
crate 为可变访问值提供了包装类型。
use volatile::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;
const volatile_A = A as *mut Volatile<u32>;
const volatile_B = B as *mut Volatile<u32>;
const volatile_C = C as *mut Volatile<u32>;
unsafe {
(*volatile_A).update(|x| *x | 0x10);
(*volatile_B).update(|x| *x & !0xCC);
(*volatile_C).update(|x| *x | 0x300);
}