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

Embedded 如何在Rust中写入内存映射地址?,embedded,rust,Embedded,Rust,我想在Rust中为STM32F1xx制作“Blinky”。 我知道它有lib,但我想为学习目的制作自己的“lib” 我可以通过地址访问STM32的“寄存器”,如C中所示: *(uint32_t*)(0x40021000+0x018)|=0x10; *(uint32_t*)(0x40011000+0x004)|=0x33; *(uint32_t*)(0x40011000+0x004)和=~0xCC; *(uint32_t*)(0x40011000+0x10)|=0x300; 而(1){} 这会将

我想在Rust中为STM32F1xx制作“Blinky”。 我知道它有lib,但我想为学习目的制作自己的“lib”

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

*(uint32_t*)(0x40021000+0x018)|=0x10;
*(uint32_t*)(0x40011000+0x004)|=0x33;
*(uint32_t*)(0x40011000+0x004)和=~0xCC;
*(uint32_t*)(0x40011000+0x10)|=0x300;
而(1){}
这会将一些位写入
RCC_APB2ENR
寄存器,以启用端口C的时钟,配置管脚并启用我的发现上的指示灯

我需要用Rust重新编写它,生成const,fns并开始编写漂亮的生锈代码。在锈迹斑斑的情况下,FFI是否可以调用C代码?我可以通过
asm实现这一点吗宏?

rust在标准库中有该模块。它提供了像and这样的函数,这些函数比去引用更加明确

所以你的例子是

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(得益于此),您可以使用
core::ptr::read_volatile
core::ptr::write_volatile
读取和写入此类内存

如果您使用的是旧版本的Rust,则它们可以作为
volatile\u read
volatile\u store
在中提供,但是它们是永久不稳定的,因此需要每夜一次的Rust版本来访问它们。

这些功能自版本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);
}
此外,板条箱还提供了围绕易失性访问值的包装类型

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);
}
使用volatile::volatile;
常数A:*mut u32=(0x40021000+0x018)为*mut u32;
常数B:*mut u32=(0x40011000+0x004)为*mut u32;
常数C:*mut u32=(0x40011000+0x10)作为*mut u32;
常量volatile_A=A作为*mut volatile;
常量volatile_B=B作为*mut volatile;
常量volatile_C=C as*mut volatile;
不安全{
(*volatile_A).更新(|x |*x | 0x10);
(*volatile_B).update(|x |*x&!0xCC);
(*volatile|C).更新(| x |*x | 0x300);
}

编译器对非易失性指针的行为是否与C和Rust相同?是的,Rust编译器可以进行相同的优化。执行此操作的LLVM后端用于两种语言。