| 1 | //! Volatile access to memory mapped hardware registers |
| 2 | //! |
| 3 | //! # Usage |
| 4 | //! |
| 5 | //! ``` no_run |
| 6 | //! use volatile_register::RW; |
| 7 | //! |
| 8 | //! // Create a struct that represents the memory mapped register block |
| 9 | //! /// Nested Vector Interrupt Controller |
| 10 | //! #[repr(C)] |
| 11 | //! pub struct Nvic { |
| 12 | //! /// Interrupt Set-Enable |
| 13 | //! pub iser: [RW<u32>; 8], |
| 14 | //! reserved0: [u32; 24], |
| 15 | //! /// Interrupt Clear-Enable |
| 16 | //! pub icer: [RW<u32>; 8], |
| 17 | //! reserved1: [u32; 24], |
| 18 | //! // .. more registers .. |
| 19 | //! } |
| 20 | //! |
| 21 | //! // Access the registers by casting the base address of the register block |
| 22 | //! // to the previously declared `struct` |
| 23 | //! let nvic = 0xE000_E100 as *const Nvic; |
| 24 | //! // Unsafe because the compiler can't verify the address is correct |
| 25 | //! unsafe { (*nvic).iser[0].write(1) } |
| 26 | //! ``` |
| 27 | |
| 28 | #![deny (missing_docs)] |
| 29 | #![no_std ] |
| 30 | |
| 31 | extern crate vcell; |
| 32 | |
| 33 | use vcell::VolatileCell; |
| 34 | |
| 35 | /// Read-Only register |
| 36 | #[repr (transparent)] |
| 37 | pub struct RO<T> |
| 38 | where T: Copy |
| 39 | { |
| 40 | register: VolatileCell<T>, |
| 41 | } |
| 42 | |
| 43 | impl<T> RO<T> |
| 44 | where T: Copy |
| 45 | { |
| 46 | /// Reads the value of the register |
| 47 | #[inline (always)] |
| 48 | pub fn read(&self) -> T { |
| 49 | self.register.get() |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | /// Read-Write register |
| 54 | #[repr (transparent)] |
| 55 | pub struct RW<T> |
| 56 | where T: Copy |
| 57 | { |
| 58 | register: VolatileCell<T>, |
| 59 | } |
| 60 | |
| 61 | impl<T> RW<T> |
| 62 | where T: Copy |
| 63 | { |
| 64 | /// Performs a read-modify-write operation |
| 65 | /// |
| 66 | /// NOTE: `unsafe` because writes to a register are side effectful |
| 67 | #[inline (always)] |
| 68 | pub unsafe fn modify<F>(&self, f: F) |
| 69 | where F: FnOnce(T) -> T |
| 70 | { |
| 71 | self.register.set(f(self.register.get())); |
| 72 | } |
| 73 | |
| 74 | /// Reads the value of the register |
| 75 | #[inline (always)] |
| 76 | pub fn read(&self) -> T { |
| 77 | self.register.get() |
| 78 | } |
| 79 | |
| 80 | /// Writes a `value` into the register |
| 81 | /// |
| 82 | /// NOTE: `unsafe` because writes to a register are side effectful |
| 83 | #[inline (always)] |
| 84 | pub unsafe fn write(&self, value: T) { |
| 85 | self.register.set(value) |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | /// Write-Only register |
| 90 | #[repr (transparent)] |
| 91 | pub struct WO<T> |
| 92 | where T: Copy |
| 93 | { |
| 94 | register: VolatileCell<T>, |
| 95 | } |
| 96 | |
| 97 | impl<T> WO<T> |
| 98 | where T: Copy |
| 99 | { |
| 100 | /// Writes `value` into the register |
| 101 | /// |
| 102 | /// NOTE: `unsafe` because writes to a register are side effectful |
| 103 | #[inline (always)] |
| 104 | pub unsafe fn write(&self, value: T) { |
| 105 | self.register.set(value) |
| 106 | } |
| 107 | } |
| 108 | |