Skip to content
Snippets Groups Projects
Select Git revision
  • 56f08040b22da908993cedddeababe4a7ff9d744
  • master default protected
  • itm
  • v0.4.2
  • v0.4.1
  • v0.4.0
  • v0.1.7
  • v0.2.12
  • v0.3.1
  • v0.3.0
  • v0.2.11
  • v0.2.10
  • v0.2.9
  • v0.2.8
  • v0.2.7
  • v0.2.6
  • v0.2.5
  • v0.2.4
  • v0.2.3
  • v0.2.2
  • v0.2.1
  • v0.2.0
  • v0.1.6
23 results

mod.rs

Blame
  • mod.rs 11.92 KiB
    //! 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
    //! 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.
    //!
    //! ``` no_run
    //! extern crate cortex_m;
    //!
    //! use cortex_m::peripheral::Peripherals;
    //!
    //! fn main() {
    //!     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::get_cycle_count`](struct.DWT.html#method.get_cycle_count) 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
    //! safe higher level 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() };
    //! }
    //! ```
    //!
    //! # References
    //!
    //! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
    
    // TODO stand-alone registers: ICTR, ACTLR and STIR
    
    #![allow(private_no_mangle_statics)]
    
    use core::marker::PhantomData;
    use core::ops;
    
    use interrupt;
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    pub mod cbp;
    pub mod cpuid;
    pub mod dcb;
    pub mod dwt;
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    pub mod fpb;
    #[cfg(any(has_fpu, target_arch = "x86_64"))]
    pub mod fpu;
    // NOTE(target_arch) is for documentation purposes
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    pub mod itm;
    pub mod mpu;
    pub mod nvic;
    pub mod scb;
    pub mod syst;
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    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)]
    pub struct Peripherals {
        /// Cache and branch predictor maintenance operations
        #[cfg(any(armv7m, target_arch = "x86_64"))]
        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
        #[cfg(any(armv7m, target_arch = "x86_64"))]
        pub FPB: FPB,
        /// Floating Point Unit
        #[cfg(any(has_fpu, target_arch = "x86_64"))]
        pub FPU: FPU,
        /// Instrumentation Trace Macrocell
        #[cfg(any(armv7m, target_arch = "x86_64"))]
        pub ITM: ITM,
        /// Memory Protection Unit
        pub MPU: MPU,
        /// Nested Vector Interrupt Controller
        pub NVIC: NVIC,
        /// System Control Block
        pub SCB: SCB,
        /// SysTick: System Timer
        pub SYST: SYST,
        /// Trace Port Interface Unit;
        #[cfg(any(armv7m, target_arch = "x86_64"))]
        pub TPIU: TPIU,
    }
    
    // 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 mut CORE_PERIPHERALS: bool = false;
    
    impl Peripherals {
        /// Returns all the core peripherals *once*
        #[inline]
        pub fn take() -> Option<Self> {
            interrupt::free(|_| {
                if unsafe { CORE_PERIPHERALS } {
                    None
                } else {
                    Some(unsafe { Peripherals::steal() })
                }
            })
        }
    
        /// Unchecked version of `Peripherals::take`
        pub unsafe fn steal() -> Self {
            debug_assert!(!CORE_PERIPHERALS);
    
            CORE_PERIPHERALS = true;
    
            Peripherals {
                #[cfg(any(armv7m, target_arch = "x86_64"))]
                CBP: CBP {
                    _marker: PhantomData,
                },
                CPUID: CPUID {
                    _marker: PhantomData,
                },
                DCB: DCB {
                    _marker: PhantomData,
                },
                DWT: DWT {
                    _marker: PhantomData,
                },
                #[cfg(any(armv7m, target_arch = "x86_64"))]
                FPB: FPB {
                    _marker: PhantomData,
                },
                #[cfg(any(has_fpu, target_arch = "x86_64"))]
                FPU: FPU {
                    _marker: PhantomData,
                },
                #[cfg(any(armv7m, target_arch = "x86_64"))]
                ITM: ITM {
                    _marker: PhantomData,
                },
                MPU: MPU {
                    _marker: PhantomData,
                },
                NVIC: NVIC {
                    _marker: PhantomData,
                },
                SCB: SCB {
                    _marker: PhantomData,
                },
                SYST: SYST {
                    _marker: PhantomData,
                },
                #[cfg(any(armv7m, target_arch = "x86_64"))]
                TPIU: TPIU {
                    _marker: PhantomData,
                },
            }
        }
    }
    
    /// Cache and branch predictor maintenance operations
    ///
    /// *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`)
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    pub struct CBP {
        _marker: PhantomData<*const ()>,
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    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 _
        }
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    unsafe impl Send for CBP {}
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    impl ops::Deref for CBP {
        type Target = self::cbp::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// CPUID
    pub struct CPUID {
        _marker: PhantomData<*const ()>,
    }
    
    impl CPUID {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const self::cpuid::RegisterBlock {
            0xE000_ED00 as *const _
        }
    }
    
    impl ops::Deref for CPUID {
        type Target = self::cpuid::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// Debug Control Block
    pub struct DCB {
        _marker: PhantomData<*const ()>,
    }
    
    impl DCB {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const dcb::RegisterBlock {
            0xE000_EDF0 as *const _
        }
    }
    
    impl ops::Deref for DCB {
        type Target = self::dcb::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*DCB::ptr() }
        }
    }
    
    /// Data Watchpoint and Trace unit
    pub struct DWT {
        _marker: PhantomData<*const ()>,
    }
    
    impl DWT {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const dwt::RegisterBlock {
            0xE000_1000 as *const _
        }
    }
    
    impl ops::Deref for DWT {
        type Target = self::dwt::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// Flash Patch and Breakpoint unit
    ///
    /// *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`)
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    pub struct FPB {
        _marker: PhantomData<*const ()>,
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    impl FPB {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const fpb::RegisterBlock {
            0xE000_2000 as *const _
        }
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    impl ops::Deref for FPB {
        type Target = self::fpb::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// Floating Point Unit
    ///
    /// *NOTE* Available only on ARMv7E-M (`thumbv7em-none-eabihf`)
    #[cfg(any(has_fpu, target_arch = "x86_64"))]
    pub struct FPU {
        _marker: PhantomData<*const ()>,
    }
    
    #[cfg(any(has_fpu, target_arch = "x86_64"))]
    impl FPU {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const fpu::RegisterBlock {
            0xE000_EF30 as *const _
        }
    }
    
    #[cfg(any(has_fpu, target_arch = "x86_64"))]
    impl ops::Deref for FPU {
        type Target = self::fpu::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// Instrumentation Trace Macrocell
    ///
    /// *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`)
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    pub struct ITM {
        _marker: PhantomData<*const ()>,
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    impl ITM {
        /// Returns a pointer to the register block
        pub fn ptr() -> *mut itm::RegisterBlock {
            0xE000_0000 as *mut _
        }
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    impl ops::Deref for ITM {
        type Target = self::itm::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    impl ops::DerefMut for ITM {
        fn deref_mut(&mut self) -> &mut Self::Target {
            unsafe { &mut *Self::ptr() }
        }
    }
    
    /// Memory Protection Unit
    pub struct MPU {
        _marker: PhantomData<*const ()>,
    }
    
    impl MPU {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const mpu::RegisterBlock {
            0xE000_ED90 as *const _
        }
    }
    
    impl ops::Deref for MPU {
        type Target = self::mpu::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// Nested Vector Interrupt Controller
    pub struct NVIC {
        _marker: PhantomData<*const ()>,
    }
    
    impl NVIC {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const nvic::RegisterBlock {
            0xE000_E100 as *const _
        }
    }
    
    impl ops::Deref for NVIC {
        type Target = self::nvic::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// System Control Block
    pub struct SCB {
        _marker: PhantomData<*const ()>,
    }
    
    impl SCB {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const scb::RegisterBlock {
            0xE000_ED04 as *const _
        }
    }
    
    impl ops::Deref for SCB {
        type Target = self::scb::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// SysTick: System Timer
    pub struct SYST {
        _marker: PhantomData<*const ()>,
    }
    
    impl SYST {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const syst::RegisterBlock {
            0xE000_E010 as *const _
        }
    }
    
    impl ops::Deref for SYST {
        type Target = self::syst::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }
    
    /// Trace Port Interface Unit;
    ///
    /// *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`)
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    pub struct TPIU {
        _marker: PhantomData<*const ()>,
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    impl TPIU {
        /// Returns a pointer to the register block
        pub fn ptr() -> *const tpiu::RegisterBlock {
            0xE004_0000 as *const _
        }
    }
    
    #[cfg(any(armv7m, target_arch = "x86_64"))]
    impl ops::Deref for TPIU {
        type Target = self::tpiu::RegisterBlock;
    
        fn deref(&self) -> &Self::Target {
            unsafe { &*Self::ptr() }
        }
    }