我试图制作" Blinky"对于Rust中的STM32F1xx。 我知道它有libs,但我想创建自己的" lib"用于学习目的。
我可以访问STM32"寄存器"通过他们在C:
中的地址*(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!
宏来实现这一目标吗?
答案 0 :(得分:8)
在C中,您应该在访问硬件寄存器时将指针声明为volatile
,以便编译器完全按照您编程的方式进行访问。否则它可能会重新排序它们或消除对同一寄存器的重复访问。
自Rust 1.9(感谢此RFC)以来,您可以使用core::ptr::read_volatile
和core::ptr::write_volatile
来读取和写入此类内存。
如果您使用较旧版本的Rust,则这些版本在core::intrinsics中以volatile_read
和volatile_store
提供,但这些版本永久不稳定,因此需要每晚版本的Rust才能访问它们。
答案 1 :(得分:4)
自1.9版以来,函数read_volatile
和write_volatile
是稳定的,因此您应该使用这些函数。借用@ 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 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);
}
答案 2 :(得分:1)
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;