cortex_m/peripheral/
mod.rs

1//! Core peripherals.
2//!
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 any
7//! one of them at any given point in time) and the only way to get an instance of them is through
8//! the [`Peripherals::take`](struct.Peripherals.html#method.take) method.
9//!
10//! ``` no_run
11//! # use cortex_m::peripheral::Peripherals;
12//! let mut peripherals = Peripherals::take().unwrap();
13//! peripherals.DCB.enable_trace();
14//! ```
15//!
16//! This method can only be successfully called *once* -- this is why the method returns an
17//! `Option`. Subsequent calls to the method will result in a `None` value being returned.
18//!
19//! ``` no_run, should_panic
20//! # use cortex_m::peripheral::Peripherals;
21//! let ok = Peripherals::take().unwrap();
22//! let panics = Peripherals::take().unwrap();
23//! ```
24//! A part of the peripheral API doesn't require access to a peripheral instance. This part of the
25//! API is provided as static methods on the peripheral types. One example is the
26//! [`DWT::cycle_count`](struct.DWT.html#method.cycle_count) method.
27//!
28//! ``` no_run
29//! # use cortex_m::peripheral::{DWT, Peripherals};
30//! {
31//!     let mut peripherals = Peripherals::take().unwrap();
32//!     peripherals.DCB.enable_trace();
33//!     peripherals.DWT.enable_cycle_counter();
34//! } // all the peripheral singletons are destroyed here
35//!
36//! // but this method can be called without a DWT instance
37//! let cyccnt = DWT::cycle_count();
38//! ```
39//!
40//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is
41//! available on all the peripheral types. This method is a useful building block for implementing
42//! safe higher level abstractions.
43//!
44//! ``` no_run
45//! # use cortex_m::peripheral::{DWT, Peripherals};
46//! {
47//!     let mut peripherals = Peripherals::take().unwrap();
48//!     peripherals.DCB.enable_trace();
49//!     peripherals.DWT.enable_cycle_counter();
50//! } // all the peripheral singletons are destroyed here
51//!
52//! // actually safe because this is an atomic read with no side effects
53//! let cyccnt = unsafe { (*DWT::PTR).cyccnt.read() };
54//! ```
55//!
56//! # References
57//!
58//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
59
60use core::marker::PhantomData;
61use core::ops;
62
63use crate::interrupt;
64
65#[cfg(cm7)]
66pub mod ac;
67#[cfg(not(armv6m))]
68pub mod cbp;
69pub mod cpuid;
70pub mod dcb;
71pub mod dwt;
72#[cfg(not(armv6m))]
73pub mod fpb;
74// NOTE(native) is for documentation purposes
75#[cfg(any(has_fpu, native))]
76pub mod fpu;
77pub mod icb;
78#[cfg(all(not(armv6m), not(armv8m_base)))]
79pub mod itm;
80pub mod mpu;
81pub mod nvic;
82#[cfg(armv8m)]
83pub mod sau;
84pub mod scb;
85pub mod syst;
86#[cfg(not(armv6m))]
87pub mod tpiu;
88
89#[cfg(test)]
90mod test;
91
92// NOTE the `PhantomData` used in the peripherals proxy is to make them `Send` but *not* `Sync`
93
94/// Core peripherals
95#[allow(non_snake_case)]
96#[allow(clippy::manual_non_exhaustive)]
97pub struct Peripherals {
98    /// Cortex-M7 TCM and cache access control.
99    #[cfg(cm7)]
100    pub AC: AC,
101
102    /// Cache and branch predictor maintenance operations.
103    /// Not available on Armv6-M.
104    pub CBP: CBP,
105
106    /// CPUID
107    pub CPUID: CPUID,
108
109    /// Debug Control Block
110    pub DCB: DCB,
111
112    /// Data Watchpoint and Trace unit
113    pub DWT: DWT,
114
115    /// Flash Patch and Breakpoint unit.
116    /// Not available on Armv6-M.
117    pub FPB: FPB,
118
119    /// Floating Point Unit.
120    pub FPU: FPU,
121
122    /// Implementation Control Block.
123    ///
124    /// The name is from the v8-M spec, but the block existed in earlier
125    /// revisions, without a name.
126    pub ICB: ICB,
127
128    /// Instrumentation Trace Macrocell.
129    /// Not available on Armv6-M and Armv8-M Baseline.
130    pub ITM: ITM,
131
132    /// Memory Protection Unit
133    pub MPU: MPU,
134
135    /// Nested Vector Interrupt Controller
136    pub NVIC: NVIC,
137
138    /// Security Attribution Unit
139    pub SAU: SAU,
140
141    /// System Control Block
142    pub SCB: SCB,
143
144    /// SysTick: System Timer
145    pub SYST: SYST,
146
147    /// Trace Port Interface Unit.
148    /// Not available on Armv6-M.
149    pub TPIU: TPIU,
150
151    // Private field making `Peripherals` non-exhaustive. We don't use `#[non_exhaustive]` so we
152    // can support older Rust versions.
153    _priv: (),
154}
155
156// NOTE `no_mangle` is used here to prevent linking different minor versions of this crate as that
157// would let you `take` the core peripherals more than once (one per minor version)
158#[no_mangle]
159static CORE_PERIPHERALS: () = ();
160
161/// Set to `true` when `take` or `steal` was called to make `Peripherals` a singleton.
162static mut TAKEN: bool = false;
163
164impl Peripherals {
165    /// Returns all the core peripherals *once*
166    #[inline]
167    pub fn take() -> Option<Self> {
168        interrupt::free(|_| {
169            if unsafe { TAKEN } {
170                None
171            } else {
172                Some(unsafe { Peripherals::steal() })
173            }
174        })
175    }
176
177    /// Unchecked version of `Peripherals::take`
178    #[inline]
179    pub unsafe fn steal() -> Self {
180        TAKEN = true;
181
182        Peripherals {
183            #[cfg(cm7)]
184            AC: AC {
185                _marker: PhantomData,
186            },
187            CBP: CBP {
188                _marker: PhantomData,
189            },
190            CPUID: CPUID {
191                _marker: PhantomData,
192            },
193            DCB: DCB {
194                _marker: PhantomData,
195            },
196            DWT: DWT {
197                _marker: PhantomData,
198            },
199            FPB: FPB {
200                _marker: PhantomData,
201            },
202            FPU: FPU {
203                _marker: PhantomData,
204            },
205            ICB: ICB {
206                _marker: PhantomData,
207            },
208            ITM: ITM {
209                _marker: PhantomData,
210            },
211            MPU: MPU {
212                _marker: PhantomData,
213            },
214            NVIC: NVIC {
215                _marker: PhantomData,
216            },
217            SAU: SAU {
218                _marker: PhantomData,
219            },
220            SCB: SCB {
221                _marker: PhantomData,
222            },
223            SYST: SYST {
224                _marker: PhantomData,
225            },
226            TPIU: TPIU {
227                _marker: PhantomData,
228            },
229            _priv: (),
230        }
231    }
232}
233
234/// Access control
235#[cfg(cm7)]
236pub struct AC {
237    _marker: PhantomData<*const ()>,
238}
239
240#[cfg(cm7)]
241unsafe impl Send for AC {}
242
243#[cfg(cm7)]
244impl AC {
245    /// Pointer to the register block
246    pub const PTR: *const self::ac::RegisterBlock = 0xE000_EF90 as *const _;
247
248    /// Returns a pointer to the register block
249    #[inline(always)]
250    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
251    pub const fn ptr() -> *const self::ac::RegisterBlock {
252        Self::PTR
253    }
254}
255
256/// Cache and branch predictor maintenance operations
257pub struct CBP {
258    _marker: PhantomData<*const ()>,
259}
260
261unsafe impl Send for CBP {}
262
263#[cfg(not(armv6m))]
264impl CBP {
265    #[inline(always)]
266    pub(crate) const unsafe fn new() -> Self {
267        CBP {
268            _marker: PhantomData,
269        }
270    }
271
272    /// Pointer to the register block
273    pub const PTR: *const self::cbp::RegisterBlock = 0xE000_EF50 as *const _;
274
275    /// Returns a pointer to the register block
276    #[inline(always)]
277    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
278    pub const fn ptr() -> *const self::cbp::RegisterBlock {
279        Self::PTR
280    }
281}
282
283#[cfg(not(armv6m))]
284impl ops::Deref for CBP {
285    type Target = self::cbp::RegisterBlock;
286
287    #[inline(always)]
288    fn deref(&self) -> &Self::Target {
289        unsafe { &*Self::PTR }
290    }
291}
292
293/// CPUID
294pub struct CPUID {
295    _marker: PhantomData<*const ()>,
296}
297
298unsafe impl Send for CPUID {}
299
300impl CPUID {
301    /// Pointer to the register block
302    pub const PTR: *const self::cpuid::RegisterBlock = 0xE000_ED00 as *const _;
303
304    /// Returns a pointer to the register block
305    #[inline(always)]
306    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
307    pub const fn ptr() -> *const self::cpuid::RegisterBlock {
308        Self::PTR
309    }
310}
311
312impl ops::Deref for CPUID {
313    type Target = self::cpuid::RegisterBlock;
314
315    #[inline(always)]
316    fn deref(&self) -> &Self::Target {
317        unsafe { &*Self::PTR }
318    }
319}
320
321/// Debug Control Block
322pub struct DCB {
323    _marker: PhantomData<*const ()>,
324}
325
326unsafe impl Send for DCB {}
327
328impl DCB {
329    /// Pointer to the register block
330    pub const PTR: *const dcb::RegisterBlock = 0xE000_EDF0 as *const _;
331
332    /// Returns a pointer to the register block
333    #[inline(always)]
334    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
335    pub const fn ptr() -> *const dcb::RegisterBlock {
336        Self::PTR
337    }
338}
339
340impl ops::Deref for DCB {
341    type Target = self::dcb::RegisterBlock;
342
343    #[inline(always)]
344    fn deref(&self) -> &Self::Target {
345        unsafe { &*DCB::PTR }
346    }
347}
348
349/// Data Watchpoint and Trace unit
350pub struct DWT {
351    _marker: PhantomData<*const ()>,
352}
353
354unsafe impl Send for DWT {}
355
356impl DWT {
357    /// Pointer to the register block
358    pub const PTR: *const dwt::RegisterBlock = 0xE000_1000 as *const _;
359
360    /// Returns a pointer to the register block
361    #[inline(always)]
362    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
363    pub const fn ptr() -> *const dwt::RegisterBlock {
364        Self::PTR
365    }
366}
367
368impl ops::Deref for DWT {
369    type Target = self::dwt::RegisterBlock;
370
371    #[inline(always)]
372    fn deref(&self) -> &Self::Target {
373        unsafe { &*Self::PTR }
374    }
375}
376
377/// Flash Patch and Breakpoint unit
378pub struct FPB {
379    _marker: PhantomData<*const ()>,
380}
381
382unsafe impl Send for FPB {}
383
384#[cfg(not(armv6m))]
385impl FPB {
386    /// Pointer to the register block
387    pub const PTR: *const fpb::RegisterBlock = 0xE000_2000 as *const _;
388
389    /// Returns a pointer to the register block
390    #[inline(always)]
391    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
392    pub const fn ptr() -> *const fpb::RegisterBlock {
393        Self::PTR
394    }
395}
396
397#[cfg(not(armv6m))]
398impl ops::Deref for FPB {
399    type Target = self::fpb::RegisterBlock;
400
401    #[inline(always)]
402    fn deref(&self) -> &Self::Target {
403        unsafe { &*Self::PTR }
404    }
405}
406
407/// Floating Point Unit
408pub struct FPU {
409    _marker: PhantomData<*const ()>,
410}
411
412unsafe impl Send for FPU {}
413
414#[cfg(any(has_fpu, native))]
415impl FPU {
416    /// Pointer to the register block
417    pub const PTR: *const fpu::RegisterBlock = 0xE000_EF30 as *const _;
418
419    /// Returns a pointer to the register block
420    #[inline(always)]
421    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
422    pub const fn ptr() -> *const fpu::RegisterBlock {
423        Self::PTR
424    }
425}
426
427#[cfg(any(has_fpu, native))]
428impl ops::Deref for FPU {
429    type Target = self::fpu::RegisterBlock;
430
431    #[inline(always)]
432    fn deref(&self) -> &Self::Target {
433        unsafe { &*Self::PTR }
434    }
435}
436
437/// Implementation Control Block.
438///
439/// This block contains implementation-defined registers like `ictr` and
440/// `actlr`. It's called the "implementation control block" in the ARMv8-M
441/// standard, but earlier standards contained the registers, just without a
442/// name.
443pub struct ICB {
444    _marker: PhantomData<*const ()>,
445}
446
447unsafe impl Send for ICB {}
448
449impl ICB {
450    /// Pointer to the register block
451    pub const PTR: *mut icb::RegisterBlock = 0xE000_E004 as *mut _;
452
453    /// Returns a pointer to the register block
454    #[inline(always)]
455    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
456    pub const fn ptr() -> *mut icb::RegisterBlock {
457        Self::PTR
458    }
459}
460
461impl ops::Deref for ICB {
462    type Target = self::icb::RegisterBlock;
463
464    #[inline(always)]
465    fn deref(&self) -> &Self::Target {
466        unsafe { &*Self::PTR }
467    }
468}
469
470impl ops::DerefMut for ICB {
471    #[inline(always)]
472    fn deref_mut(&mut self) -> &mut Self::Target {
473        unsafe { &mut *Self::PTR }
474    }
475}
476
477/// Instrumentation Trace Macrocell
478pub struct ITM {
479    _marker: PhantomData<*const ()>,
480}
481
482unsafe impl Send for ITM {}
483
484#[cfg(all(not(armv6m), not(armv8m_base)))]
485impl ITM {
486    /// Pointer to the register block
487    pub const PTR: *mut itm::RegisterBlock = 0xE000_0000 as *mut _;
488
489    /// Returns a pointer to the register block
490    #[inline(always)]
491    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
492    pub const fn ptr() -> *mut itm::RegisterBlock {
493        Self::PTR
494    }
495}
496
497#[cfg(all(not(armv6m), not(armv8m_base)))]
498impl ops::Deref for ITM {
499    type Target = self::itm::RegisterBlock;
500
501    #[inline(always)]
502    fn deref(&self) -> &Self::Target {
503        unsafe { &*Self::PTR }
504    }
505}
506
507#[cfg(all(not(armv6m), not(armv8m_base)))]
508impl ops::DerefMut for ITM {
509    #[inline(always)]
510    fn deref_mut(&mut self) -> &mut Self::Target {
511        unsafe { &mut *Self::PTR }
512    }
513}
514
515/// Memory Protection Unit
516pub struct MPU {
517    _marker: PhantomData<*const ()>,
518}
519
520unsafe impl Send for MPU {}
521
522impl MPU {
523    /// Pointer to the register block
524    pub const PTR: *const mpu::RegisterBlock = 0xE000_ED90 as *const _;
525
526    /// Returns a pointer to the register block
527    #[inline(always)]
528    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
529    pub const fn ptr() -> *const mpu::RegisterBlock {
530        Self::PTR
531    }
532}
533
534impl ops::Deref for MPU {
535    type Target = self::mpu::RegisterBlock;
536
537    #[inline(always)]
538    fn deref(&self) -> &Self::Target {
539        unsafe { &*Self::PTR }
540    }
541}
542
543/// Nested Vector Interrupt Controller
544pub struct NVIC {
545    _marker: PhantomData<*const ()>,
546}
547
548unsafe impl Send for NVIC {}
549
550impl NVIC {
551    /// Pointer to the register block
552    pub const PTR: *const nvic::RegisterBlock = 0xE000_E100 as *const _;
553
554    /// Returns a pointer to the register block
555    #[inline(always)]
556    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
557    pub const fn ptr() -> *const nvic::RegisterBlock {
558        Self::PTR
559    }
560}
561
562impl ops::Deref for NVIC {
563    type Target = self::nvic::RegisterBlock;
564
565    #[inline(always)]
566    fn deref(&self) -> &Self::Target {
567        unsafe { &*Self::PTR }
568    }
569}
570
571/// Security Attribution Unit
572pub struct SAU {
573    _marker: PhantomData<*const ()>,
574}
575
576unsafe impl Send for SAU {}
577
578#[cfg(armv8m)]
579impl SAU {
580    /// Pointer to the register block
581    pub const PTR: *const sau::RegisterBlock = 0xE000_EDD0 as *const _;
582
583    /// Returns a pointer to the register block
584    #[inline(always)]
585    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
586    pub const fn ptr() -> *const sau::RegisterBlock {
587        Self::PTR
588    }
589}
590
591#[cfg(armv8m)]
592impl ops::Deref for SAU {
593    type Target = self::sau::RegisterBlock;
594
595    #[inline(always)]
596    fn deref(&self) -> &Self::Target {
597        unsafe { &*Self::PTR }
598    }
599}
600
601/// System Control Block
602pub struct SCB {
603    _marker: PhantomData<*const ()>,
604}
605
606unsafe impl Send for SCB {}
607
608impl SCB {
609    /// Pointer to the register block
610    pub const PTR: *const scb::RegisterBlock = 0xE000_ED04 as *const _;
611
612    /// Returns a pointer to the register block
613    #[inline(always)]
614    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
615    pub const fn ptr() -> *const scb::RegisterBlock {
616        Self::PTR
617    }
618}
619
620impl ops::Deref for SCB {
621    type Target = self::scb::RegisterBlock;
622
623    #[inline(always)]
624    fn deref(&self) -> &Self::Target {
625        unsafe { &*Self::PTR }
626    }
627}
628
629/// SysTick: System Timer
630pub struct SYST {
631    _marker: PhantomData<*const ()>,
632}
633
634unsafe impl Send for SYST {}
635
636impl SYST {
637    /// Pointer to the register block
638    pub const PTR: *const syst::RegisterBlock = 0xE000_E010 as *const _;
639
640    /// Returns a pointer to the register block
641    #[inline(always)]
642    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
643    pub const fn ptr() -> *const syst::RegisterBlock {
644        Self::PTR
645    }
646}
647
648impl ops::Deref for SYST {
649    type Target = self::syst::RegisterBlock;
650
651    #[inline(always)]
652    fn deref(&self) -> &Self::Target {
653        unsafe { &*Self::PTR }
654    }
655}
656
657/// Trace Port Interface Unit
658pub struct TPIU {
659    _marker: PhantomData<*const ()>,
660}
661
662unsafe impl Send for TPIU {}
663
664#[cfg(not(armv6m))]
665impl TPIU {
666    /// Pointer to the register block
667    pub const PTR: *const tpiu::RegisterBlock = 0xE004_0000 as *const _;
668
669    /// Returns a pointer to the register block
670    #[inline(always)]
671    #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
672    pub const fn ptr() -> *const tpiu::RegisterBlock {
673        Self::PTR
674    }
675}
676
677#[cfg(not(armv6m))]
678impl ops::Deref for TPIU {
679    type Target = self::tpiu::RegisterBlock;
680
681    #[inline(always)]
682    fn deref(&self) -> &Self::Target {
683        unsafe { &*Self::PTR }
684    }
685}