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

穿精又带淫゛_ 提交于 2019-12-19 13:56:52

问题


I'm trying to make "Blinky" for STM32F1xx in Rust. I know that there are libs for it, but I want to make my own "lib" for learning purposes.

I can access STM32's "registers" by their addresses like this in C:

*(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.

I need to re-write this it in Rust, to make consts, fns and start writing nice Rusty code. Is it possible in Rust without FFI calling C code? Can I achieve this with the asm! macro?


回答1:


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. 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.

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.




回答2:


The functions read_volatile and write_volatile are stable since version 1.9, so you should be using these. Borrowing @ker's translated sample for demonstration:

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.

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



回答3:


rust has the std::ptr module in the standard library. It offers functions like ptr::read and ptr::write which are much more explicit than dereferencing.

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:

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


来源:https://stackoverflow.com/questions/35009015/how-do-i-write-to-a-memory-mapped-address-in-rust

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!