简体   繁体   English

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

[英]How do I write to a memory-mapped address in Rust?

I'm trying to make "Blinky" for STM32F1xx in Rust. 我正在尝试为Rust中的STM32F1xx制作“Blinky”。 I know that there are libs for it, but I want to make my own "lib" for learning purposes. 我知道它有libs,但是我想创建自己的“lib”用于学习目的。

I can access STM32's "registers" by their addresses like this in C: 我可以通过C中的地址访问STM32的“寄存器”:

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

while(1) {}

This writes some bits to the RCC_APB2ENR register to enable clocking of port C, configures pins and enables LEDs on my Discovery. 这会将一些位写入RCC_APB2ENR寄存器以启用端口C的时钟,配置引脚并启用Discovery上的LED。

I need to re-write this it in Rust, to make consts, fns and start writing nice Rusty code. 我需要在Rust中重写它,以制作consts,fns并开始编写漂亮的Rusty代码。 Is it possible in Rust without FFI calling C code? 在没有FFI调用C代码的情况下Rust是否可能? Can I achieve this with the asm! 我可以用asm!实现这个目标asm! macro? 宏?

In C you should declare your pointers as volatile when accessing hardware registers, so that the compiler does the accesses exactly as you program them. 在C中,您应该在访问硬件寄存器时将指针声明为volatile ,以便编译器完全按照您编程的方式进行访问。 Otherwise it could reorder them or eliminate duplicate accesses to the same register. 否则,它可以重新排序它们或消除对同一寄存器的重复访问。

Since Rust 1.9 (thanks to this RFC ) you can use core::ptr::read_volatile and core::ptr::write_volatile to read and write to such memory. 自Rust 1.9(感谢此RFC )以来,您可以使用core::ptr::read_volatilecore::ptr::write_volatile来读取和写入此类内存。

If you have an older version of Rust, these are available as volatile_read and volatile_store in core::intrinsics , which however are permanently unstable, and thus require a nightly version of Rust to access them. 如果你有一个较旧版本的Rust,它们在core :: intrinsics中可用作volatile_readvolatile_store ,但是它们永久不稳定,因此需要每晚版本的Rust来访问它们。

The functions read_volatile and write_volatile are stable since version 1.9, so you should be using these. 自版本1.9以来,函数read_volatilewrite_volatile是稳定的,因此您应该使用这些函数。 Borrowing @ker's translated sample for demonstration: 借用@ 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);
}

Furthermore, the volatile crate provides wrapper types around values for volatile access. 此外, volatile crate提供了围绕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);
}

rust has the std::ptr module in the standard library. rust在标准库中有std::ptr模块。 It offers functions like ptr::read and ptr::write which are much more explicit than dereferencing. 它提供了像ptr::readptr::write这样的函数,它们比解除引用更明确。

So your example would be 所以你的榜样就是

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

The more concise version is to use dereferencing, but that only works for Copy types: 更简洁的版本是使用解除引用,但这仅适用于Copy类型:

*A |= 0x10;
*B |= 0x33;
*B &= !0xCC;
*C |= 0x300;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM