esp_hal/peripherals/mod.rs
1//! # Peripheral Instances
2//!
3//! This module creates singleton instances for each of the various peripherals,
4//! and re-exports them to allow users to access and use them in their
5//! applications.
6//!
7//! Should be noted that the module also re-exports the [Interrupt] enum
8//! from the PAC, allowing users to handle interrupts associated with these
9//! peripherals.
10
11// We need to export this for users to use
12#[doc(hidden)]
13pub use pac::Interrupt;
14
15pub(crate) use crate::soc::pac;
16
17#[cfg(esp32h2)]
18#[path = "overlay_h2.rs"]
19mod overlay;
20
21#[cfg(any(esp32p4, esp32s31))]
22#[path = "overlay_rmt.rs"]
23#[cfg(feature = "unstable")]
24mod overlay;
25
26/// Macro to create a peripheral structure.
27macro_rules! create_peripheral {
28 ($(#[$attr:meta])* $name:ident <= virtual ($($interrupt:ident: { $bind:ident, $enable:ident, $disable:ident }),*)) => {
29 #[derive(Debug)]
30 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
31 #[non_exhaustive]
32 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
33 $(#[$attr])*
34 pub struct $name<'a> {
35 _marker: core::marker::PhantomData<&'a mut ()>,
36 }
37
38 impl $name<'_> {
39 /// Unsafely create an instance of this peripheral out of thin air.
40 ///
41 /// # Safety
42 ///
43 /// You must ensure that you're only using one instance of this type at a time.
44 #[inline]
45 pub unsafe fn steal() -> Self {
46 Self {
47 _marker: core::marker::PhantomData,
48 }
49 }
50
51 /// Unsafely clone this peripheral reference.
52 ///
53 /// # Safety
54 ///
55 /// You must ensure that you're only using one instance of this type at a time.
56 #[inline]
57 #[allow(dead_code)]
58 pub unsafe fn clone_unchecked(&self) -> Self {
59 unsafe { Self::steal() }
60 }
61
62 /// Creates a new peripheral reference with a shorter lifetime.
63 ///
64 /// Use this method if you would like to keep working with the peripheral after
65 /// you dropped the driver that consumes this.
66 #[inline]
67 #[allow(dead_code)]
68 pub fn reborrow(&mut self) -> $name<'_> {
69 unsafe { self.clone_unchecked() }
70 }
71
72 $(
73 /// Binds an interrupt handler to the corresponding interrupt for this peripheral, and enables the interrupt.
74 ///
75 /// <section class="warning">
76 /// This function is a very low-level way to work with interrupts. Unless you're writing drivers, this is probably not the interrupt API you want to use.
77 /// </section>
78 ///
79 #[instability::unstable]
80 pub fn $bind(&self, handler: $crate::interrupt::InterruptHandler) {
81 $crate::interrupt::bind_handler($crate::peripherals::Interrupt::$interrupt, handler);
82 }
83
84 #[procmacros::doc_replace]
85 #[doc = concat!("Enables the ", stringify!($interrupt), " peripheral interrupt on the given priority level.")]
86 ///
87 /// <section class="warning">
88 /// This function is a very low-level way to work with interrupts. Unless you're writing drivers, this is probably not the interrupt API you want to use.
89 /// </section>
90 #[cfg_attr(multi_core, doc = "The interrupt handler will be enabled on the core that calls this function.")]
91 ///
92 /// Note that a suitable interrupt handler needs to be set up before the first interrupt
93 /// is triggered, otherwise the default handler will panic.
94 #[cfg_attr(not(feature = "unstable"), doc = "To set up an interrupt handler, create a function that has the same (non-mangled) name as the interrupt you want to handle.")]
95 #[cfg_attr(feature = "unstable", doc = concat!("To set up an interrupt handler, use [`Self::", stringify!($bind), "`] or create a function that has the same (non-mangled) name as the interrupt you want to handle."))]
96 ///
97 /// ## Examples
98 ///
99 /// ```rust, no_run
100 /// # {before_snippet}
101 /// use esp_hal::interrupt::Priority;
102 ///
103 /// #[unsafe(no_mangle)]
104 #[doc = concat!(r#"unsafe extern "C" fn "#, stringify!($interrupt), "() {")]
105 /// // do something
106 /// }
107 ///
108 #[doc = concat!("peripherals.", stringify!($name), ".", stringify!($enable), "(Priority::Priority1);")]
109 #[doc = concat!("peripherals.", stringify!($name), ".", stringify!($disable), "_on_all_cores();")]
110 /// # {after_snippet}
111 /// ```
112 #[allow(dead_code, reason = "Peripheral may be unstable")]
113 pub fn $enable(&self, priority: $crate::interrupt::Priority) {
114 $crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, priority);
115 }
116
117 paste::paste! {
118 #[procmacros::doc_replace]
119 #[doc = concat!("Disables the ", stringify!($interrupt), " peripheral interrupt handler on the current CPU core.")]
120 ///
121 /// <section class="warning">
122 /// This function is a very low-level way to work with interrupts. Unless you're writing drivers, this is probably not the interrupt API you want to use.
123 /// </section>
124 #[instability::unstable]
125 pub fn $disable(&self) {
126 $crate::interrupt::disable($crate::system::Cpu::current(), $crate::peripherals::Interrupt::$interrupt);
127 }
128
129 #[procmacros::doc_replace]
130 #[doc = concat!("Disables the ", stringify!($interrupt), " peripheral interrupt handler on all cores.")]
131 ///
132 /// <section class="warning">
133 /// This function is a very low-level way to work with interrupts. Unless you're writing drivers, this is probably not the interrupt API you want to use.
134 /// </section>
135 #[allow(dead_code, reason = "Peripheral may be unstable")]
136 pub fn [<$disable _on_all_cores>](&self) {
137 for core in $crate::system::Cpu::all() {
138 $crate::interrupt::disable(core, $crate::peripherals::Interrupt::$interrupt);
139 }
140 }
141 }
142 )*
143 }
144
145 impl $crate::private::Sealed for $name<'_> {}
146 };
147
148 ($(#[$attr:meta])* $name:ident <= $base:ident $interrupts:tt) => {
149 create_peripheral!($(#[$attr])* $name <= virtual $interrupts);
150
151 impl $name<'_> {
152 #[doc = r"Pointer to the register block"]
153 #[instability::unstable]
154 pub const PTR: *const <pac::$base as core::ops::Deref>::Target = pac::$base::PTR;
155
156 #[doc = r"Return the pointer to the register block"]
157 #[inline(always)]
158 #[instability::unstable]
159 pub const fn ptr() -> *const <pac::$base as core::ops::Deref>::Target {
160 pac::$base::PTR
161 }
162
163 #[doc = r"Return a reference to the register block"]
164 #[inline(always)]
165 #[instability::unstable]
166 pub fn regs<'a>() -> &'a <pac::$base as core::ops::Deref>::Target {
167 unsafe { &*Self::PTR }
168 }
169
170 #[doc = r"Return a reference to the register block"]
171 #[inline(always)]
172 #[instability::unstable]
173 pub fn register_block(&self) -> &<pac::$base as core::ops::Deref>::Target {
174 unsafe { &*Self::PTR }
175 }
176 }
177 };
178}
179
180for_each_peripheral! {
181 // Define stable peripheral singletons
182 (@peri_type $(#[$meta:meta])* $name:ident <= $from_pac:tt $interrupts:tt) => {
183 create_peripheral!( $(#[$meta])* $name <= $from_pac $interrupts);
184 };
185
186 // Define unstable peripheral singletons
187 (@peri_type $(#[$meta:meta])* $name:ident <= $from_pac:tt $interrupts:tt (unstable)) => {
188 create_peripheral!(#[instability::unstable] $(#[$meta])* $name <= $from_pac $interrupts);
189 };
190
191 // Define the Peripherals struct
192 (singletons $( ( $(#[$cfg:meta])* $name:ident $(($unstable:ident $(#[$unstable_cfg:meta])*))?) ),*) => {
193 // We need a way to ignore the "unstable" marker, but macros can't generate attributes or struct fields.
194 // The solution is printing an empty doc comment.
195 macro_rules! ignore { ($any:tt) => {""} }
196
197 /// The `Peripherals` struct provides access to all of the hardware peripherals on the chip.
198 #[allow(non_snake_case)]
199 #[non_exhaustive]
200 pub struct Peripherals {
201 $(
202 // This is a bit hairy, but non-macro attributes are not allowed on struct fields. We work
203 // around this by excluding code with the `$()?` optional macro syntax and an "unstable" marker
204 // in the source data. The marker itself is passed through the `ignore` macro so that it doesn't
205 // appear in the generated code.
206 //
207 // The code can end up looking two ways:
208 //
209 // - Without `unstable` we just generate the field:
210 // ```
211 // #[attributes]
212 // pub PERI: PERI<'static>,
213 // ```
214 //
215 // - With `unstable` we're basically emulating what `instability::unstable` would do:
216 // ```
217 // #[attributes]
218 // #[cfg(feature = "unstable")]
219 // pub PERI: PERI<'static>,
220 //
221 // #[attributes]
222 // #[cfg(not(feature = "unstable"))]
223 // pub(crate) PERI: PERI<'static>,
224 // ```
225 $(#[$cfg])*
226 #[doc = concat!("The ", stringify!($name), " peripheral.")]
227 $(
228 #[doc = "**This API is marked as unstable** and is only available when the `unstable`
229 crate feature is enabled. This comes with no stability guarantees, and could be changed
230 or removed at any time."]
231 #[doc = ignore!($unstable)]
232 #[cfg(feature = "unstable")]
233 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
234 )?
235 pub $name: $name<'static>,
236
237 $(
238 $(#[$unstable_cfg])*
239 #[doc = concat!("The ", stringify!($name), " peripheral.")]
240 #[doc = "**This API is marked as unstable** and is only available when the `unstable`
241 crate feature is enabled. This comes with no stability guarantees, and could be changed
242 or removed at any time."]
243 #[doc = ignore!($unstable)]
244 #[cfg(not(feature = "unstable"))]
245 #[allow(unused)]
246 pub(crate) $name: $name<'static>,
247 )?
248 )*
249 }
250
251 impl Peripherals {
252 /// Returns all the peripherals *once*.
253 #[inline]
254 #[cfg(feature = "rt")]
255 pub(crate) fn take() -> Self {
256 #[unsafe(no_mangle)]
257 static mut _ESP_HAL_DEVICE_PERIPHERALS: bool = false;
258
259 crate::ESP_HAL_LOCK.lock(|| unsafe {
260 if _ESP_HAL_DEVICE_PERIPHERALS {
261 panic!("init called more than once!")
262 }
263 _ESP_HAL_DEVICE_PERIPHERALS = true;
264 Self::steal()
265 })
266 }
267
268 /// Unsafely create an instance of this peripheral out of thin air.
269 ///
270 /// # Safety
271 ///
272 /// You must ensure that you're only using one instance of this type at a time.
273 #[inline]
274 pub unsafe fn steal() -> Self {
275 unsafe {
276 Self {
277 $(
278 $(#[$cfg])*
279 $name: $name::steal(),
280 )*
281 }
282 }
283 }
284 }
285 };
286}