2017-06-12 70 views
0

在嵌入式編程中,可以通過放置在正確地址的結構來訪問內存映射外設。我如何確保對外設的內存訪問確實在Rust的總線上執行?在C中,這可以通過設置變量或字段volatile來完成。如何確保內存映射外設的內存訪問是不穩定的?

考慮這個例子:

#[repr(C)] 
struct Periph { 
    sr: u32, /* Status */ 
    cr: u32, /* Control */ 
    dr: u32, /* Data */ 
} 

const PERIPH1: *mut Periph = 0x10001200 as *mut Periph; 
const PERIPH2: *mut Periph = 0x10001400 as *mut Periph; 

fn useperiph(p: &mut Periph) -> i32 { 
    p.cr = CR_CONSTANT; 
    if p.cr != CR_CONSTANT { 
     /* Peripheral was not enabled */ 
     return -1; 
    } 

    /* Loop a few micro seconds until ready */ 
    while p.sr != SR_CONSTANT {} 

    /* Write values to hardware FIFO */ 
    p.dr = DATA1; 
    p.dr = DATA2; 
    p.dr = DATA3; 
    0 
} 

我需要確保編譯器不會刪除支票上的控制寄存器,將離開狀態寄存器的所有負載,而不會崩潰三個店到數據寄存器。我怎麼做?

+0

也就是說https://stackoverflow.com/q/35009015/1233251的副本,但答案是過時的。我想我應該在那裏做一個更新的答案,而不是在這裏複製信息。 –

+0

請參閱我的回答[here](https://stackoverflow.com/a/44510388/1233251)。 –

回答

0

我所知道的最好的方法是使用類似於Zinc的volatile_cell庫的東西。內存映射外設寄存器的結構具有VolatileCell<u32>型寄存器,而不是普通的u32VolatileCell包裝一個值,具有相同的大小,並提供使用core::ptr::read_volatilecore::ptr::write_volatile的訪問器。剝離下來到它的本質,VolatileCell看起來是這樣的:

#[repr(C)] 
pub struct VolatileCell<T> { 
    value: T, 
} 

impl<T> VolatileCell<T> { 

    /// Get register value. 
    #[inline] 
    pub fn get(&self) -> T { 
     unsafe { 
      read_volatile(&self.value) 
     } 
    } 

    /// Set register value. 
    #[inline] 
    pub fn set(&self, value: T) { 
     unsafe { 
      write_volatile(&self.value as *const T as *mut T, value) 
     } 
    } 
} 

然後外設寄存器結構使用VolatileCell<u32>領域寫着:

#[repr(C)] 
struct Periph { 
    sr: VolatileCell<u32>, /* Status */ 
    cr: VolatileCell<u32>, /* Control */ 
    dr: VolatileCell<u32>, /* Data */ 
} 

const PERIPH1: *mut Periph = 0x10001200 as *mut Periph; 
const PERIPH2: *mut Periph = 0x10001400 as *mut Periph; 

fn useperiph(p: &mut Periph) -> i32 { 
    p.cr.set(CR_CONSTANT); 
    if p.cr.get() != CR_CONSTANT { 
     /* Peripheral was not enabled */ 
     return -1; 
    } 

    /* Loop a few micro seconds until ready */ 
    while p.sr.get() != SR_CONSTANT {} 

    p.dr.set(DATA1); 
    p.dr.set(DATA2); 
    p.dr.set(DATA3); 
    0 
} 

生成的代碼具有正確的語義,只是稍微詳細比直接使用u32。明確表示可以說是一個好處。