Skip to main content

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