Ideally, you should never create references to volatile memory, and always use raw pointers. It's best to do something like this:
#[repr(C)]
struct UartMmapRegs {
txdata: u32, /* Transmit data */
rxdata: u32, /* Receive data */
txctrl: u32, /* Tx control */
rxctrl: u32, /* Rx Control */
ie: u32, /* Interrupt enable */
ip: u32, /* Interrupt pending */
div: u32, /* Divisor */
}
pub struct UartMmapRegsPtr {
ptr: *mut UartMmapRegs,
}
impl UartMmapRegsPtr {
pub fn receive(&self) -> u32 {
unsafe {
let ptr = self.ptr;
let field_ptr = core::ptr::addr_of!(ptr.rxdata);
core::ptr::read_volatile(field_ptr) & DATA_SEG_BMASK
}
}
}
This uses a wrapper struct to avoid creating a &UartMmapRegs
as &self
when calling the method, and uses addr_of!
to convert the struct ptr into a field ptr without an intermediate reference.