Skip to content

Commit

Permalink
feat: Take ownership of peripheral in SYSCON API
Browse files Browse the repository at this point in the history
Close #84
  • Loading branch information
hannobraun committed Jul 3, 2018
1 parent 2463610 commit 28d57ba
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 29 deletions.
2 changes: 1 addition & 1 deletion examples/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ entry!(main);
fn main() -> ! {
// Create the struct we're going to use to access all the peripherals. This
// is unsafe, because we're only allowed to create one instance.
let mut p = Peripherals::take().unwrap();
let p = Peripherals::take().unwrap();

// Other peripherals need to be initialized. Trying to use the API before
// initializing them will actually lead to compile-time errors.
Expand Down
2 changes: 1 addition & 1 deletion examples/i2c_vl53l0x.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use lpc82x_hal::usart::BaudRate;
entry!(main);

fn main() -> ! {
let mut p = Peripherals::take().unwrap();
let p = Peripherals::take().unwrap();

let i2c = p.I2C0;
let mut swm = p.SWM.split();
Expand Down
2 changes: 1 addition & 1 deletion examples/pmu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use lpc82x_hal::usart::BaudRate;
entry!(main);

fn main() -> ! {
let mut p = Peripherals::take().unwrap();
let p = Peripherals::take().unwrap();

let mut pmu = p.PMU.split();
let mut swm = p.SWM.split();
Expand Down
2 changes: 1 addition & 1 deletion examples/usart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use lpc82x_hal::usart::BaudRate;
entry!(main);

fn main() -> ! {
let mut p = Peripherals::take().unwrap();
let p = Peripherals::take().unwrap();

let mut swm = p.SWM.split();
let mut syscon = p.SYSCON.split();
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ extern crate void;
pub extern crate lpc82x as raw;


#[macro_use] pub(crate) mod reg_proxy;

pub mod clock;
pub mod gpio;
pub mod i2c;
Expand Down
94 changes: 94 additions & 0 deletions src/reg_proxy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! Makes registers ownable and movable
//!
//! The register code generated by svd2rust doesn't allows us to move and own
//! registers. We can only have shared references to them. This becomes
//! inconvenient, if we want to split a peripheral, so multiple components of an
//! API can access it, as every component requires a lifetime then.
//!
//! This module works around this limitation, by introducing a proxy struct that
//! provides access to a register.


use core::marker::PhantomData;
use core::mem::transmute;
use core::ops::Deref;


/// A proxy object for a register
///
/// This proxy can be moved and owned, then provide access to the register it
/// proxies from wherever it is. Access to the register is provided by
/// implementing `Deref`.
pub struct RegProxy<T> where T: Reg {
_marker: PhantomData<*const T>,
}

impl<T> RegProxy<T> where T: Reg {
/// Create a new proxy object
///
/// If this method is used to create multiple proxies for the same register,
/// using those proxies carelessly can result in race conditions. It's
/// probably always a mistake to access such shared registers using
/// `modify`, as these methods do a read-modify-write, which is not atomic.
///
/// How to access a register race-free depends on the specifics of the
/// hardware:
/// - Restricting yourself to reading from a register might be safe, but
/// please note that even reading a register might have side effects
/// (possibly even in other registers).
/// - Many registers are set up such, that only bits that are written as `1`
/// have an effect, while bits written as `0` don't. Such registers can
/// often be shared without race conditions.
/// - Generally speaking, make sure you understand the hardware, and what
/// kind of access could or could not lead to race conditions.
///
/// Please note that all of this isn't really different from the raw API
/// generated by svd2rust, as multiple shared references to the same
/// register can exist there, and a shared reference is all that's required
/// to have full control over a register.
pub fn new() -> Self {
RegProxy {
_marker: PhantomData,
}
}
}

unsafe impl<T> Send for RegProxy<T> where T: Reg {}

impl<T> Deref for RegProxy<T> where T: Reg {
type Target = T;

fn deref(&self) -> &Self::Target {
// As long as `T` upholds the safety restrictions laid out in the
// documentation of `Reg`, this should be safe. The pointer is valid for
// the duration of the program. That means:
// 1. It can always be dereferenced, so casting to a reference is safe.
// 2. It is essentially `'static`, so casting to any lifetime is safe.
unsafe { transmute(T::get()) }
}
}


/// Implemented for registers that `RegProxy` can proxy
///
/// If you want to implement this trait for a register from a crate generated by
/// svd2rust, please use the `reg!` macro.
///
/// # Safety
///
/// The pointer returned by `get` must be valid for the duration of the program.
/// This should always be the case for MMIO registers.
pub unsafe trait Reg {
/// Return a pointer to the memory location of the register
fn get() -> *const Self;
}

macro_rules! reg {
($ty:ident, $peripheral:path, $field:ident) => {
unsafe impl $crate::reg_proxy::Reg for $ty {
fn get() -> *const Self {
unsafe { &(*<$peripheral>::ptr()).$field as *const _ }
}
}
}
}
57 changes: 34 additions & 23 deletions src/syscon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use raw::syscon::{
UARTFRGDIV,
UARTFRGMULT,
};
use reg_proxy::RegProxy;


/// Entry point to the SYSCON API
Expand Down Expand Up @@ -61,13 +62,13 @@ impl SYSCON {
/// This is the regular way to access the SYSCON API. It exists as an
/// explicit step, as it's no longer possible to gain access to the raw
/// peripheral using [`SYSCON::free`] after you've called this method.
pub fn split(&mut self) -> Parts {
pub fn split(self) -> Parts {
Parts {
handle: Handle {
pdruncfg : &self.syscon.pdruncfg,
presetctrl : &self.syscon.presetctrl,
starterp1 : &self.syscon.starterp1,
sysahbclkctrl: &self.syscon.sysahbclkctrl,
pdruncfg : RegProxy::new(),
presetctrl : RegProxy::new(),
starterp1 : RegProxy::new(),
sysahbclkctrl: RegProxy::new(),
},

bod : BOD(PhantomData),
Expand All @@ -80,9 +81,9 @@ impl SYSCON {
sysosc : SYSOSC(PhantomData),
syspll : SYSPLL(PhantomData),
uartfrg: UARTFRG {
uartclkdiv : &self.syscon.uartclkdiv,
uartfrgdiv : &self.syscon.uartfrgdiv,
uartfrgmult: &self.syscon.uartfrgmult,
uartclkdiv : RegProxy::new(),
uartfrgdiv : RegProxy::new(),
uartfrgmult: RegProxy::new(),

},

Expand Down Expand Up @@ -114,9 +115,9 @@ impl SYSCON {
/// the [module documentation] for more information.
///
/// [module documentation]: index.html
pub struct Parts<'syscon> {
pub struct Parts {
/// The handle to the SYSCON peripheral
pub handle: Handle<'syscon>,
pub handle: Handle,

/// Brown-out detection
pub bod: BOD,
Expand Down Expand Up @@ -146,7 +147,7 @@ pub struct Parts<'syscon> {
pub syspll: SYSPLL,

/// UART Fractional Baud Rate Generator
pub uartfrg: UARTFRG<'syscon>,
pub uartfrg: UARTFRG,

/// The 750 kHz IRC-derived clock
pub irc_derived_clock: IrcDerivedClock<init_state::Enabled>,
Expand All @@ -163,14 +164,14 @@ pub struct Parts<'syscon> {
/// PMU.
///
/// [module documentation]: index.html
pub struct Handle<'syscon> {
pdruncfg : &'syscon PDRUNCFG,
presetctrl : &'syscon PRESETCTRL,
starterp1 : &'syscon STARTERP1,
sysahbclkctrl: &'syscon SYSAHBCLKCTRL,
pub struct Handle {
pdruncfg : RegProxy<PDRUNCFG>,
presetctrl : RegProxy<PRESETCTRL>,
starterp1 : RegProxy<STARTERP1>,
sysahbclkctrl: RegProxy<SYSAHBCLKCTRL>,
}

impl<'r> Handle<'r> {
impl Handle {
/// Enable peripheral clock
///
/// Enables the clock for a peripheral or other hardware component. HAL
Expand Down Expand Up @@ -307,13 +308,13 @@ pub struct SYSPLL(PhantomData<*const ()>);
/// [`syscon::Handle`].
///
/// [`syscon::Handle`]: struct.Handle.html
pub struct UARTFRG<'syscon> {
uartclkdiv : &'syscon UARTCLKDIV,
uartfrgdiv : &'syscon UARTFRGDIV,
uartfrgmult: &'syscon UARTFRGMULT,
pub struct UARTFRG {
uartclkdiv : RegProxy<UARTCLKDIV>,
uartfrgdiv : RegProxy<UARTFRGDIV>,
uartfrgmult: RegProxy<UARTFRGMULT>,
}

impl<'syscon> UARTFRG<'syscon> {
impl UARTFRG {
/// Set UART clock divider value (UARTCLKDIV)
///
/// See user manual, section 5.6.15.
Expand Down Expand Up @@ -450,7 +451,7 @@ macro_rules! impl_reset_control {

impl_reset_control!(raw::SPI0 , spi0_rst_n );
impl_reset_control!(raw::SPI1 , spi1_rst_n );
impl_reset_control!(UARTFRG<'a> , uartfrg_rst_n);
impl_reset_control!(UARTFRG , uartfrg_rst_n);
impl_reset_control!(raw::USART0 , uart0_rst_n );
impl_reset_control!(raw::USART1 , uart1_rst_n );
impl_reset_control!(raw::USART2 , uart2_rst_n );
Expand Down Expand Up @@ -624,3 +625,13 @@ wakeup_interrupt!(BodWakeup , bod );
wakeup_interrupt!(WktWakeup , wkt );
wakeup_interrupt!(I2c2Wakeup , i2c2 );
wakeup_interrupt!(I2c3Wakeup , i2c3 );


reg!(PDRUNCFG , raw::SYSCON, pdruncfg );
reg!(PRESETCTRL , raw::SYSCON, presetctrl );
reg!(STARTERP1 , raw::SYSCON, starterp1 );
reg!(SYSAHBCLKCTRL, raw::SYSCON, sysahbclkctrl);

reg!(UARTCLKDIV , raw::SYSCON, uartclkdiv );
reg!(UARTFRGDIV , raw::SYSCON, uartfrgdiv );
reg!(UARTFRGMULT, raw::SYSCON, uartfrgmult);
4 changes: 2 additions & 2 deletions src/usart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ impl Peripheral for raw::USART2 {
/// Can be passed to [`USART::enable`] to configure the baud rate for a USART
/// peripheral.
pub struct BaudRate<'frg> {
_uartfrg: &'frg UARTFRG<'frg>,
_uartfrg: &'frg UARTFRG,

/// USART Baud Rate Generator divider value
///
Expand All @@ -432,7 +432,7 @@ impl<'frg> BaudRate<'frg> {
/// is divided by 2 before using it, `2` means it's divided by 3, and so on.
///
/// Please refer to the user manual, section 13.3.1, for further details.
pub fn new(uartfrg : &'frg UARTFRG<'frg>, brgval : u16) -> Self {
pub fn new(uartfrg : &'frg UARTFRG, brgval : u16) -> Self {
Self {
_uartfrg: uartfrg,
brgval : brgval,
Expand Down

0 comments on commit 28d57ba

Please sign in to comment.