Skip to content

Commit 80328e9

Browse files
committed
revise peripheral API
closes #67
1 parent bdc7ca9 commit 80328e9

File tree

9 files changed

+270
-165
lines changed

9 files changed

+270
-165
lines changed

src/exception.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ pub enum Exception {
2222
/// An interrupt
2323
Interrupt(u8),
2424
// Unreachable variant
25-
#[doc(hidden)]
26-
Reserved,
25+
#[doc(hidden)] Reserved,
2726
}
2827

2928
impl Exception {

src/peripheral/cbp.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
use volatile_register::WO;
44

5+
use peripheral::CBP;
6+
57
/// Register block
68
#[repr(C)]
79
pub struct RegisterBlock {
@@ -33,26 +35,26 @@ const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS;
3335
const CBP_SW_SET_POS: u32 = 5;
3436
const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS;
3537

36-
impl RegisterBlock {
38+
impl CBP {
3739
/// I-cache invalidate all to PoU
3840
#[inline]
39-
pub fn iciallu(&self) {
41+
pub fn iciallu(&mut self) {
4042
unsafe {
4143
self.iciallu.write(0);
4244
}
4345
}
4446

4547
/// I-cache invalidate by MVA to PoU
4648
#[inline]
47-
pub fn icimvau(&self, mva: u32) {
49+
pub fn icimvau(&mut self, mva: u32) {
4850
unsafe {
4951
self.icimvau.write(mva);
5052
}
5153
}
5254

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

8385
/// D-cache clean by MVA to PoU
8486
#[inline]
85-
pub fn dccmvau(&self, mva: u32) {
87+
pub fn dccmvau(&mut self, mva: u32) {
8688
unsafe {
8789
self.dccmvau.write(mva);
8890
}
8991
}
9092

9193
/// D-cache clean by MVA to PoC
9294
#[inline]
93-
pub fn dccmvac(&self, mva: u32) {
95+
pub fn dccmvac(&mut self, mva: u32) {
9496
unsafe {
9597
self.dccmvac.write(mva);
9698
}
@@ -100,7 +102,7 @@ impl RegisterBlock {
100102
///
101103
/// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
102104
#[inline]
103-
pub fn dccsw(&self, set: u16, way: u16) {
105+
pub fn dccsw(&mut self, set: u16, way: u16) {
104106
// See comment for dcisw() about the format here
105107
unsafe {
106108
self.dccsw.write(
@@ -112,7 +114,7 @@ impl RegisterBlock {
112114

113115
/// D-cache clean and invalidate by MVA to PoC
114116
#[inline]
115-
pub fn dccimvac(&self, mva: u32) {
117+
pub fn dccimvac(&mut self, mva: u32) {
116118
unsafe {
117119
self.dccimvac.write(mva);
118120
}
@@ -122,7 +124,7 @@ impl RegisterBlock {
122124
///
123125
/// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
124126
#[inline]
125-
pub fn dccisw(&self, set: u16, way: u16) {
127+
pub fn dccisw(&mut self, set: u16, way: u16) {
126128
// See comment for dcisw() about the format here
127129
unsafe {
128130
self.dccisw.write(
@@ -134,7 +136,7 @@ impl RegisterBlock {
134136

135137
/// Branch predictor invalidate all
136138
#[inline]
137-
pub fn bpiall(&self) {
139+
pub fn bpiall(&mut self) {
138140
unsafe {
139141
self.bpiall.write(0);
140142
}

src/peripheral/cpuid.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use volatile_register::RO;
44
#[cfg(any(armv7m, test))]
55
use volatile_register::RW;
66

7+
#[cfg(armv7m)]
8+
use peripheral::CPUID;
9+
710
/// Register block
811
#[repr(C)]
912
pub struct RegisterBlock {
@@ -45,14 +48,14 @@ pub enum CsselrCacheType {
4548
}
4649

4750
#[cfg(armv7m)]
48-
impl RegisterBlock {
51+
impl CPUID {
4952
/// Selects the current CCSIDR
5053
///
5154
/// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2
5255
/// * `ind`: select instruction cache or data/unified cache
5356
///
5457
/// `level` is masked to be between 0 and 7.
55-
pub fn select_cache(&self, level: u8, ind: CsselrCacheType) {
58+
pub fn select_cache(&mut self, level: u8, ind: CsselrCacheType) {
5659
const CSSELR_IND_POS: u32 = 0;
5760
const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS;
5861
const CSSELR_LEVEL_POS: u32 = 1;
@@ -67,7 +70,7 @@ impl RegisterBlock {
6770
}
6871

6972
/// Returns the number of sets and ways in the selected cache
70-
pub fn cache_num_sets_ways(&self, level: u8, ind: CsselrCacheType) -> (u16, u16) {
73+
pub fn cache_num_sets_ways(&mut self, level: u8, ind: CsselrCacheType) -> (u16, u16) {
7174
const CCSIDR_NUMSETS_POS: u32 = 13;
7275
const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS;
7376
const CCSIDR_ASSOCIATIVITY_POS: u32 = 3;

src/peripheral/dwt.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
use volatile_register::{RO, RW, WO};
44

5+
use peripheral::DWT;
6+
57
/// Register block
68
#[repr(C)]
79
pub struct RegisterBlock {
@@ -30,13 +32,6 @@ pub struct RegisterBlock {
3032
pub lsr: RO<u32>,
3133
}
3234

33-
impl RegisterBlock {
34-
/// Enables the cycle counter
35-
pub fn enable_cycle_counter(&self) {
36-
unsafe { self.ctrl.modify(|r| r | 1) }
37-
}
38-
}
39-
4035
/// Comparator
4136
#[repr(C)]
4237
pub struct Comparator {
@@ -48,3 +43,16 @@ pub struct Comparator {
4843
pub function: RW<u32>,
4944
reserved: u32,
5045
}
46+
47+
impl DWT {
48+
/// Enables the cycle counter
49+
pub fn enable_cycle_counter(&mut self) {
50+
unsafe { self.ctrl.modify(|r| r | 1) }
51+
}
52+
53+
/// Returns the current clock cycle count
54+
pub fn get_cycle_count() -> u32 {
55+
// NOTE(unsafe) atomic read with no side effects
56+
unsafe { (*Self::ptr()).cyccnt.read() }
57+
}
58+
}

src/peripheral/mod.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,54 @@
11
//! Core peripherals
22
//!
3+
//! # API
4+
//!
5+
//! To use (most of) the peripheral API first you must get an *instance* of the peripheral. All the
6+
//! core peripherals are modeled as singletons (there can only ever be, at most, one instance of
7+
//! them at any given point in time) and the only way to get an instance of them is through the
8+
//! [`Peripherals::take`](struct.Peripherals.html#method.take) method.
9+
//!
10+
//! ``` ignore
11+
//! fn main() {
12+
//! let peripherals = Peripherals::take();
13+
//! peripherals.dwt.enable_cycle_counter();
14+
//! }
15+
//! ```
16+
//!
17+
//! This method can only be successfully called *once* -- this is why the method returns an
18+
//! `Option`. Subsequent calls to the method will result in a `None` value being returned.
19+
//!
20+
//! A part of the peripheral API doesn't require access to a peripheral instance. This part of the
21+
//! API is provided as static methods on the peripheral types. One example is the
22+
//! [`DWT::cyccnt`](struct.DWT.html#method.cyccnt) method.
23+
//!
24+
//! ``` ignore
25+
//! fn main() {
26+
//! {
27+
//! let peripherals = Peripherals::take().unwrap();
28+
//! peripherals.DWT.enable_cycle_counter();
29+
//! } // all the peripheral singletons are destroyed here
30+
//!
31+
//! // but this method can be called without a DWT instance
32+
//! let cyccnt = DWT::cyccnt();
33+
//! }
34+
//! ```
35+
//!
36+
//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is
37+
//! available on all the peripheral types. This method is a useful building block for implementing
38+
//! higher level and safe abstractions.
39+
//!
40+
//! ``` ignore
41+
//! fn main() {
42+
//! {
43+
//! let peripherals = Peripherals::take().unwrap();
44+
//! peripherals.DWT.enable_cycle_counter();
45+
//! } // all the peripheral singletons are destroyed here
46+
//!
47+
//! // actually safe because this is an atomic read with no side effects
48+
//! let cyccnt = unsafe { (*DWT::ptr()).cyccnt.read() };
49+
//! }
50+
//! ```
51+
//!
352
//! # References
453
//!
554
//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
@@ -80,7 +129,7 @@ impl Peripherals {
80129
})
81130
}
82131

83-
/// Unchecked version of `Peripherals::steal`
132+
/// Unchecked version of `Peripherals::take`
84133
pub unsafe fn steal() -> Self {
85134
debug_assert!(!CORE_PERIPHERALS);
86135

@@ -136,6 +185,12 @@ pub struct CBP {
136185

137186
#[cfg(armv7m)]
138187
impl CBP {
188+
pub(crate) unsafe fn new() -> Self {
189+
CBP {
190+
_marker: PhantomData,
191+
}
192+
}
193+
139194
/// Returns a pointer to the register block
140195
pub fn ptr() -> *const self::cbp::RegisterBlock {
141196
0xE000_EF50 as *const _

0 commit comments

Comments
 (0)