Skip to content

revise peripheral API #69

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ pub enum Exception {
/// An interrupt
Interrupt(u8),
// Unreachable variant
#[doc(hidden)]
Reserved,
#[doc(hidden)] Reserved,
}

impl Exception {
Expand Down
24 changes: 13 additions & 11 deletions src/peripheral/cbp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

use volatile_register::WO;

use peripheral::CBP;

/// Register block
#[repr(C)]
pub struct RegisterBlock {
Expand Down Expand Up @@ -33,26 +35,26 @@ const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS;
const CBP_SW_SET_POS: u32 = 5;
const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS;

impl RegisterBlock {
impl CBP {
/// I-cache invalidate all to PoU
#[inline]
pub fn iciallu(&self) {
pub fn iciallu(&mut self) {
unsafe {
self.iciallu.write(0);
}
}

/// I-cache invalidate by MVA to PoU
#[inline]
pub fn icimvau(&self, mva: u32) {
pub fn icimvau(&mut self, mva: u32) {
unsafe {
self.icimvau.write(mva);
}
}

/// D-cache invalidate by MVA to PoC
#[inline]
pub fn dcimvac(&self, mva: u32) {
pub fn dcimvac(&mut self, mva: u32) {
unsafe {
self.dcimvac.write(mva);
}
Expand All @@ -62,7 +64,7 @@ impl RegisterBlock {
///
/// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
#[inline]
pub fn dcisw(&self, set: u16, way: u16) {
pub fn dcisw(&mut self, set: u16, way: u16) {
// The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way
// operations have a register data format which depends on the implementation's
// associativity and number of sets. Specifically the 'way' and 'set' fields have
Expand All @@ -82,15 +84,15 @@ impl RegisterBlock {

/// D-cache clean by MVA to PoU
#[inline]
pub fn dccmvau(&self, mva: u32) {
pub fn dccmvau(&mut self, mva: u32) {
unsafe {
self.dccmvau.write(mva);
}
}

/// D-cache clean by MVA to PoC
#[inline]
pub fn dccmvac(&self, mva: u32) {
pub fn dccmvac(&mut self, mva: u32) {
unsafe {
self.dccmvac.write(mva);
}
Expand All @@ -100,7 +102,7 @@ impl RegisterBlock {
///
/// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
#[inline]
pub fn dccsw(&self, set: u16, way: u16) {
pub fn dccsw(&mut self, set: u16, way: u16) {
// See comment for dcisw() about the format here
unsafe {
self.dccsw.write(
Expand All @@ -112,7 +114,7 @@ impl RegisterBlock {

/// D-cache clean and invalidate by MVA to PoC
#[inline]
pub fn dccimvac(&self, mva: u32) {
pub fn dccimvac(&mut self, mva: u32) {
unsafe {
self.dccimvac.write(mva);
}
Expand All @@ -122,7 +124,7 @@ impl RegisterBlock {
///
/// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
#[inline]
pub fn dccisw(&self, set: u16, way: u16) {
pub fn dccisw(&mut self, set: u16, way: u16) {
// See comment for dcisw() about the format here
unsafe {
self.dccisw.write(
Expand All @@ -134,7 +136,7 @@ impl RegisterBlock {

/// Branch predictor invalidate all
#[inline]
pub fn bpiall(&self) {
pub fn bpiall(&mut self) {
unsafe {
self.bpiall.write(0);
}
Expand Down
9 changes: 6 additions & 3 deletions src/peripheral/cpuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use volatile_register::RO;
#[cfg(any(armv7m, test))]
use volatile_register::RW;

#[cfg(armv7m)]
use peripheral::CPUID;

/// Register block
#[repr(C)]
pub struct RegisterBlock {
Expand Down Expand Up @@ -45,14 +48,14 @@ pub enum CsselrCacheType {
}

#[cfg(armv7m)]
impl RegisterBlock {
impl CPUID {
/// Selects the current CCSIDR
///
/// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2
/// * `ind`: select instruction cache or data/unified cache
///
/// `level` is masked to be between 0 and 7.
pub fn select_cache(&self, level: u8, ind: CsselrCacheType) {
pub fn select_cache(&mut self, level: u8, ind: CsselrCacheType) {
const CSSELR_IND_POS: u32 = 0;
const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS;
const CSSELR_LEVEL_POS: u32 = 1;
Expand All @@ -67,7 +70,7 @@ impl RegisterBlock {
}

/// Returns the number of sets and ways in the selected cache
pub fn cache_num_sets_ways(&self, level: u8, ind: CsselrCacheType) -> (u16, u16) {
pub fn cache_num_sets_ways(&mut self, level: u8, ind: CsselrCacheType) -> (u16, u16) {
const CCSIDR_NUMSETS_POS: u32 = 13;
const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS;
const CCSIDR_ASSOCIATIVITY_POS: u32 = 3;
Expand Down
22 changes: 15 additions & 7 deletions src/peripheral/dwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

use volatile_register::{RO, RW, WO};

use peripheral::DWT;

/// Register block
#[repr(C)]
pub struct RegisterBlock {
Expand Down Expand Up @@ -30,13 +32,6 @@ pub struct RegisterBlock {
pub lsr: RO<u32>,
}

impl RegisterBlock {
/// Enables the cycle counter
pub fn enable_cycle_counter(&self) {
unsafe { self.ctrl.modify(|r| r | 1) }
}
}

/// Comparator
#[repr(C)]
pub struct Comparator {
Expand All @@ -48,3 +43,16 @@ pub struct Comparator {
pub function: RW<u32>,
reserved: u32,
}

impl DWT {
/// Enables the cycle counter
pub fn enable_cycle_counter(&mut self) {
unsafe { self.ctrl.modify(|r| r | 1) }
}

/// Returns the current clock cycle count
pub fn get_cycle_count() -> u32 {
// NOTE(unsafe) atomic read with no side effects
unsafe { (*Self::ptr()).cyccnt.read() }
}
}
69 changes: 68 additions & 1 deletion src/peripheral/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,66 @@
//! Core peripherals
//!
//! # API
//!
//! To use (most of) the peripheral API first you must get an *instance* of the peripheral. All the
//! core peripherals are modeled as singletons (there can only ever be, at most, one instance of
//! them at any given point in time) and the only way to get an instance of them is through the
//! [`Peripherals::take`](struct.Peripherals.html#method.take) method.
//!
//! ``` no_run
//! extern crate cortex_m;
//!
//! use cortex_m::peripheral::Peripherals;
//!
//! fn main() {
//! let mut peripherals = Peripherals::take().unwrap();
//! peripherals.DWT.enable_cycle_counter();
//! }
//! ```
//!
//! This method can only be successfully called *once* -- this is why the method returns an
//! `Option`. Subsequent calls to the method will result in a `None` value being returned.
//!
//! A part of the peripheral API doesn't require access to a peripheral instance. This part of the
//! API is provided as static methods on the peripheral types. One example is the
//! [`DWT::cyccnt`](struct.DWT.html#method.cyccnt) method.
//!
//! ``` no_run
//! extern crate cortex_m;
//!
//! use cortex_m::peripheral::{DWT, Peripherals};
//!
//! fn main() {
//! {
//! let mut peripherals = Peripherals::take().unwrap();
//! peripherals.DWT.enable_cycle_counter();
//! } // all the peripheral singletons are destroyed here
//!
//! // but this method can be called without a DWT instance
//! let cyccnt = DWT::get_cycle_count();
//! }
//! ```
//!
//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is
//! available on all the peripheral types. This method is a useful building block for implementing
//! higher level and safe abstractions.
//!
//! ``` no_run
//! extern crate cortex_m;
//!
//! use cortex_m::peripheral::{DWT, Peripherals};
//!
//! fn main() {
//! {
//! let mut peripherals = Peripherals::take().unwrap();
//! peripherals.DWT.enable_cycle_counter();
//! } // all the peripheral singletons are destroyed here
//!
//! // actually safe because this is an atomic read with no side effects
//! let cyccnt = unsafe { (*DWT::ptr()).cyccnt.read() };
//! }
//! ```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also broken. Fixed version:

//! ``` no_run
//! use cortex_m::peripheral::{
//!     DWT,
//!     Peripherals,
//! };
//!
//! fn main() {
//!     {
//!         let mut peripherals = Peripherals::take().unwrap();
//!         peripherals.DWT.enable_cycle_counter();
//!     } // all the peripheral singletons are destroyed here
//!
//!     // actually safe because this is an atomic read with no side effects
//!     let cyccnt = unsafe { (*DWT::ptr()).cyccnt.read() };
//! }
//! ```

//!
//! # References
//!
//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
Expand Down Expand Up @@ -80,7 +141,7 @@ impl Peripherals {
})
}

/// Unchecked version of `Peripherals::steal`
/// Unchecked version of `Peripherals::take`
pub unsafe fn steal() -> Self {
debug_assert!(!CORE_PERIPHERALS);

Expand Down Expand Up @@ -136,6 +197,12 @@ pub struct CBP {

#[cfg(armv7m)]
impl CBP {
pub(crate) unsafe fn new() -> Self {
CBP {
_marker: PhantomData,
}
}

/// Returns a pointer to the register block
pub fn ptr() -> *const self::cbp::RegisterBlock {
0xE000_EF50 as *const _
Expand Down
Loading