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}
686