aboutsummaryrefslogtreecommitdiff
path: root/src/peripheral/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/peripheral/mod.rs')
-rw-r--r--src/peripheral/mod.rs594
1 files changed, 594 insertions, 0 deletions
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
new file mode 100644
index 0000000..af922b1
--- /dev/null
+++ b/src/peripheral/mod.rs
@@ -0,0 +1,594 @@
+//! 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 any
+//! one 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
+//! # use cortex_m::peripheral::Peripherals;
+//! let mut peripherals = Peripherals::take().unwrap();
+//! peripherals.DCB.enable_trace();
+//! ```
+//!
+//! 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.
+//!
+//! ``` no_run, should_panic
+//! # use cortex_m::peripheral::Peripherals;
+//! let ok = Peripherals::take().unwrap();
+//! let panics = Peripherals::take().unwrap();
+//! ```
+//! 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::cycle_count`](struct.DWT.html#method.cycle_count) method.
+//!
+//! ``` no_run
+//! # use cortex_m::peripheral::{DWT, Peripherals};
+//! {
+//! let mut peripherals = Peripherals::take().unwrap();
+//! peripherals.DCB.enable_trace();
+//! 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::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
+//! safe higher level abstractions.
+//!
+//! ``` no_run
+//! # use cortex_m::peripheral::{DWT, Peripherals};
+//! {
+//! let mut peripherals = Peripherals::take().unwrap();
+//! peripherals.DCB.enable_trace();
+//! 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
+
+use core::marker::PhantomData;
+use core::ops;
+
+use crate::interrupt;
+
+#[cfg(cm7)]
+pub mod ac;
+#[cfg(not(armv6m))]
+pub mod cbp;
+pub mod cpuid;
+pub mod dcb;
+pub mod dwt;
+#[cfg(not(armv6m))]
+pub mod fpb;
+// NOTE(native) is for documentation purposes
+#[cfg(any(has_fpu, native))]
+pub mod fpu;
+pub mod icb;
+#[cfg(all(not(armv6m), not(armv8m_base)))]
+pub mod itm;
+pub mod mpu;
+pub mod nvic;
+#[cfg(armv8m)]
+pub mod sau;
+pub mod scb;
+pub mod syst;
+#[cfg(not(armv6m))]
+pub mod tpiu;
+
+#[cfg(test)]
+mod test;
+
+// NOTE the `PhantomData` used in the peripherals proxy is to make them `Send` but *not* `Sync`
+
+/// Core peripherals
+#[allow(non_snake_case)]
+#[allow(clippy::manual_non_exhaustive)]
+pub struct Peripherals {
+ /// Cortex-M7 TCM and cache access control.
+ #[cfg(cm7)]
+ pub AC: AC,
+
+ /// Cache and branch predictor maintenance operations.
+ /// Not available on Armv6-M.
+ pub CBP: CBP,
+
+ /// CPUID
+ pub CPUID: CPUID,
+
+ /// Debug Control Block
+ pub DCB: DCB,
+
+ /// Data Watchpoint and Trace unit
+ pub DWT: DWT,
+
+ /// Flash Patch and Breakpoint unit.
+ /// Not available on Armv6-M.
+ pub FPB: FPB,
+
+ /// Floating Point Unit.
+ pub FPU: FPU,
+
+ /// Implementation Control Block.
+ ///
+ /// The name is from the v8-M spec, but the block existed in earlier
+ /// revisions, without a name.
+ pub ICB: ICB,
+
+ /// Instrumentation Trace Macrocell.
+ /// Not available on Armv6-M and Armv8-M Baseline.
+ pub ITM: ITM,
+
+ /// Memory Protection Unit
+ pub MPU: MPU,
+
+ /// Nested Vector Interrupt Controller
+ pub NVIC: NVIC,
+
+ /// Security Attribution Unit
+ pub SAU: SAU,
+
+ /// System Control Block
+ pub SCB: SCB,
+
+ /// SysTick: System Timer
+ pub SYST: SYST,
+
+ /// Trace Port Interface Unit.
+ /// Not available on Armv6-M.
+ pub TPIU: TPIU,
+
+ // Private field making `Peripherals` non-exhaustive. We don't use `#[non_exhaustive]` so we
+ // can support older Rust versions.
+ _priv: (),
+}
+
+// NOTE `no_mangle` is used here to prevent linking different minor versions of this crate as that
+// would let you `take` the core peripherals more than once (one per minor version)
+#[no_mangle]
+static CORE_PERIPHERALS: () = ();
+
+/// Set to `true` when `take` or `steal` was called to make `Peripherals` a singleton.
+static mut TAKEN: bool = false;
+
+impl Peripherals {
+ /// Returns all the core peripherals *once*
+ #[inline]
+ pub fn take() -> Option<Self> {
+ interrupt::free(|_| {
+ if unsafe { TAKEN } {
+ None
+ } else {
+ Some(unsafe { Peripherals::steal() })
+ }
+ })
+ }
+
+ /// Unchecked version of `Peripherals::take`
+ #[inline]
+ pub unsafe fn steal() -> Self {
+ TAKEN = true;
+
+ Peripherals {
+ #[cfg(cm7)]
+ AC: AC {
+ _marker: PhantomData,
+ },
+ CBP: CBP {
+ _marker: PhantomData,
+ },
+ CPUID: CPUID {
+ _marker: PhantomData,
+ },
+ DCB: DCB {
+ _marker: PhantomData,
+ },
+ DWT: DWT {
+ _marker: PhantomData,
+ },
+ FPB: FPB {
+ _marker: PhantomData,
+ },
+ FPU: FPU {
+ _marker: PhantomData,
+ },
+ ICB: ICB {
+ _marker: PhantomData,
+ },
+ ITM: ITM {
+ _marker: PhantomData,
+ },
+ MPU: MPU {
+ _marker: PhantomData,
+ },
+ NVIC: NVIC {
+ _marker: PhantomData,
+ },
+ SAU: SAU {
+ _marker: PhantomData,
+ },
+ SCB: SCB {
+ _marker: PhantomData,
+ },
+ SYST: SYST {
+ _marker: PhantomData,
+ },
+ TPIU: TPIU {
+ _marker: PhantomData,
+ },
+ _priv: (),
+ }
+ }
+}
+
+/// Access control
+#[cfg(cm7)]
+pub struct AC {
+ _marker: PhantomData<*const ()>,
+}
+
+#[cfg(cm7)]
+unsafe impl Send for AC {}
+
+#[cfg(cm7)]
+impl AC {
+ /// Pointer to the register block
+ pub const PTR: *const self::ac::RegisterBlock = 0xE000_EF90 as *const _;
+}
+
+/// Cache and branch predictor maintenance operations
+#[allow(clippy::upper_case_acronyms)]
+pub struct CBP {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for CBP {}
+
+#[cfg(not(armv6m))]
+impl CBP {
+ #[inline(always)]
+ pub(crate) const unsafe fn new() -> Self {
+ CBP {
+ _marker: PhantomData,
+ }
+ }
+
+ /// Pointer to the register block
+ pub const PTR: *const self::cbp::RegisterBlock = 0xE000_EF50 as *const _;
+}
+
+#[cfg(not(armv6m))]
+impl ops::Deref for CBP {
+ type Target = self::cbp::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// CPUID
+#[allow(clippy::upper_case_acronyms)]
+pub struct CPUID {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for CPUID {}
+
+impl CPUID {
+ /// Pointer to the register block
+ pub const PTR: *const self::cpuid::RegisterBlock = 0xE000_ED00 as *const _;
+}
+
+impl ops::Deref for CPUID {
+ type Target = self::cpuid::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// Debug Control Block
+#[allow(clippy::upper_case_acronyms)]
+pub struct DCB {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for DCB {}
+
+impl DCB {
+ /// Pointer to the register block
+ pub const PTR: *const dcb::RegisterBlock = 0xE000_EDF0 as *const _;
+}
+
+impl ops::Deref for DCB {
+ type Target = self::dcb::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*DCB::PTR }
+ }
+}
+
+/// Data Watchpoint and Trace unit
+#[allow(clippy::upper_case_acronyms)]
+pub struct DWT {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for DWT {}
+
+impl DWT {
+ /// Pointer to the register block
+ pub const PTR: *const dwt::RegisterBlock = 0xE000_1000 as *const _;
+}
+
+impl ops::Deref for DWT {
+ type Target = self::dwt::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// Flash Patch and Breakpoint unit
+#[allow(clippy::upper_case_acronyms)]
+pub struct FPB {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for FPB {}
+
+#[cfg(not(armv6m))]
+impl FPB {
+ /// Pointer to the register block
+ pub const PTR: *const fpb::RegisterBlock = 0xE000_2000 as *const _;
+}
+
+#[cfg(not(armv6m))]
+impl ops::Deref for FPB {
+ type Target = self::fpb::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// Floating Point Unit
+#[allow(clippy::upper_case_acronyms)]
+pub struct FPU {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for FPU {}
+
+#[cfg(any(has_fpu, native))]
+impl FPU {
+ /// Pointer to the register block
+ pub const PTR: *const fpu::RegisterBlock = 0xE000_EF30 as *const _;
+}
+
+#[cfg(any(has_fpu, native))]
+impl ops::Deref for FPU {
+ type Target = self::fpu::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// Implementation Control Block.
+///
+/// This block contains implementation-defined registers like `ictr` and
+/// `actlr`. It's called the "implementation control block" in the ARMv8-M
+/// standard, but earlier standards contained the registers, just without a
+/// name.
+#[allow(clippy::upper_case_acronyms)]
+pub struct ICB {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for ICB {}
+
+impl ICB {
+ /// Pointer to the register block
+ pub const PTR: *mut icb::RegisterBlock = 0xE000_E004 as *mut _;
+}
+
+impl ops::Deref for ICB {
+ type Target = self::icb::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+impl ops::DerefMut for ICB {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe { &mut *Self::PTR }
+ }
+}
+
+/// Instrumentation Trace Macrocell
+#[allow(clippy::upper_case_acronyms)]
+pub struct ITM {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for ITM {}
+
+#[cfg(all(not(armv6m), not(armv8m_base)))]
+impl ITM {
+ /// Pointer to the register block
+ pub const PTR: *mut itm::RegisterBlock = 0xE000_0000 as *mut _;
+}
+
+#[cfg(all(not(armv6m), not(armv8m_base)))]
+impl ops::Deref for ITM {
+ type Target = self::itm::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+#[cfg(all(not(armv6m), not(armv8m_base)))]
+impl ops::DerefMut for ITM {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe { &mut *Self::PTR }
+ }
+}
+
+/// Memory Protection Unit
+#[allow(clippy::upper_case_acronyms)]
+pub struct MPU {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for MPU {}
+
+impl MPU {
+ /// Pointer to the register block
+ pub const PTR: *const mpu::RegisterBlock = 0xE000_ED90 as *const _;
+}
+
+impl ops::Deref for MPU {
+ type Target = self::mpu::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// Nested Vector Interrupt Controller
+#[allow(clippy::upper_case_acronyms)]
+pub struct NVIC {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for NVIC {}
+
+impl NVIC {
+ /// Pointer to the register block
+ pub const PTR: *const nvic::RegisterBlock = 0xE000_E100 as *const _;
+}
+
+impl ops::Deref for NVIC {
+ type Target = self::nvic::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// Security Attribution Unit
+#[allow(clippy::upper_case_acronyms)]
+pub struct SAU {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for SAU {}
+
+#[cfg(armv8m)]
+impl SAU {
+ /// Pointer to the register block
+ pub const PTR: *const sau::RegisterBlock = 0xE000_EDD0 as *const _;
+}
+
+#[cfg(armv8m)]
+impl ops::Deref for SAU {
+ type Target = self::sau::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// System Control Block
+#[allow(clippy::upper_case_acronyms)]
+pub struct SCB {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for SCB {}
+
+impl SCB {
+ /// Pointer to the register block
+ pub const PTR: *const scb::RegisterBlock = 0xE000_ED04 as *const _;
+}
+
+impl ops::Deref for SCB {
+ type Target = self::scb::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// SysTick: System Timer
+#[allow(clippy::upper_case_acronyms)]
+pub struct SYST {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for SYST {}
+
+impl SYST {
+ /// Pointer to the register block
+ pub const PTR: *const syst::RegisterBlock = 0xE000_E010 as *const _;
+}
+
+impl ops::Deref for SYST {
+ type Target = self::syst::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}
+
+/// Trace Port Interface Unit
+#[allow(clippy::upper_case_acronyms)]
+pub struct TPIU {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for TPIU {}
+
+#[cfg(not(armv6m))]
+impl TPIU {
+ /// Pointer to the register block
+ pub const PTR: *const tpiu::RegisterBlock = 0xE004_0000 as *const _;
+}
+
+#[cfg(not(armv6m))]
+impl ops::Deref for TPIU {
+ type Target = self::tpiu::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::PTR }
+ }
+}