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)]
13
pub use pac::Interrupt;
14

            
15
pub(crate) use crate::soc::pac;
16

            
17
#[cfg(esp32h2)]
18
#[path = "overlay_h2.rs"]
19
mod overlay;
20

            
21
/// Macro to create a peripheral structure.
22
macro_rules! create_peripheral {
23
    ($(#[$attr:meta])* $name:ident <= virtual ($($interrupt:ident: { $bind:ident, $enable:ident, $disable:ident }),*)) => {
24
        #[derive(Debug)]
25
        #[cfg_attr(feature = "defmt", derive(defmt::Format))]
26
        #[non_exhaustive]
27
        #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
28
        $(#[$attr])*
29
        pub struct $name<'a> {
30
            _marker: core::marker::PhantomData<&'a mut ()>,
31
        }
32

            
33
        impl $name<'_> {
34
            /// Unsafely creates an instance of this peripheral out of thin air.
35
            ///
36
            /// # Safety
37
            ///
38
            /// The caller must ensure that only one instance of this type is used at a time.
39
            #[inline]
40
            pub unsafe fn steal() -> Self {
41
                Self {
42
                    _marker: core::marker::PhantomData,
43
                }
44
            }
45

            
46
            /// Unsafely clone this peripheral reference.
47
            ///
48
            /// # Safety
49
            ///
50
            /// The caller must ensure that only one instance of this type is used at a time.
51
            #[inline]
52
            #[allow(dead_code)]
53
            pub unsafe fn clone_unchecked(&self) -> Self {
54
                unsafe { Self::steal() }
55
            }
56

            
57
            /// Creates a new peripheral reference with a shorter lifetime.
58
            ///
59
            /// Use this method to keep working with the peripheral after the driver
60
            /// that consumes it is dropped.
61
            #[inline]
62
            #[allow(dead_code)]
63
            pub fn reborrow(&mut self) -> $name<'_> {
64
                unsafe { self.clone_unchecked() }
65
            }
66

            
67
            $(
68
                /// Binds an interrupt handler to the corresponding interrupt for this peripheral, and enables the interrupt.
69
                ///
70
                /// <section class="warning">
71
                /// Very low-level interrupt API. Unless writing drivers, this is probably not the interrupt API to use.
72
                /// </section>
73
                ///
74
                #[instability::unstable]
75
                pub fn $bind(&self, handler: $crate::interrupt::InterruptHandler) {
76
                    $crate::interrupt::bind_handler($crate::peripherals::Interrupt::$interrupt, handler);
77
                }
78

            
79
                #[procmacros::doc_replace]
80
                #[doc = concat!("Enables the ", stringify!($interrupt), " peripheral interrupt on the given priority level.")]
81
                ///
82
                /// <section class="warning">
83
                /// Very low-level interrupt API. Unless writing drivers, this is probably not the interrupt API to use.
84
                /// </section>
85
                #[cfg_attr(multi_core, doc = "The interrupt handler will be enabled on the core that calls this function.")]
86
                ///
87
                /// A suitable interrupt handler must be set up before the first interrupt
88
                /// is triggered; otherwise the default handler panics.
89
                #[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 to handle.")]
90
                #[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 to handle."))]
91
                ///
92
                /// # Examples
93
                ///
94
                /// ```rust, no_run
95
                /// # {before_snippet}
96
                /// use esp_hal::interrupt::Priority;
97
                ///
98
                /// #[unsafe(no_mangle)]
99
                #[doc = concat!(r#"unsafe extern "C" fn "#, stringify!($interrupt), "() {")]
100
                ///     // do something
101
                /// }
102
                ///
103
                #[doc = concat!("peripherals.", stringify!($name), ".", stringify!($enable), "(Priority::Priority1);")]
104
                #[doc = concat!("peripherals.", stringify!($name), ".", stringify!($disable), "_on_all_cores();")]
105
                /// # {after_snippet}
106
                /// ```
107
                #[allow(dead_code, reason = "Peripheral may be unstable")]
108
6
                pub fn $enable(&self, priority: $crate::interrupt::Priority) {
109
                    $crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, priority);
110
6
                }
111

            
112
                paste::paste! {
113
                    #[procmacros::doc_replace]
114
                    #[doc = concat!("Disables the ",  stringify!($interrupt), " peripheral interrupt handler on the current CPU core.")]
115
                    ///
116
                    /// <section class="warning">
117
                    /// Very low-level interrupt API. Unless writing drivers, this is probably not the interrupt API to use.
118
                    /// </section>
119
                    #[instability::unstable]
120
3
                    pub fn $disable(&self) {
121
                        $crate::interrupt::disable($crate::system::Cpu::current(), $crate::peripherals::Interrupt::$interrupt);
122
3
                    }
123

            
124
                    #[procmacros::doc_replace]
125
                    #[doc = concat!("Disables the ",  stringify!($interrupt), " peripheral interrupt handler on all cores.")]
126
                    ///
127
                    /// <section class="warning">
128
                    /// Very low-level interrupt API. Unless writing drivers, this is probably not the interrupt API to use.
129
                    /// </section>
130
                    #[allow(dead_code, reason = "Peripheral may be unstable")]
131
                    pub fn [<$disable _on_all_cores>](&self) {
132
                        for core in $crate::system::Cpu::all() {
133
                            $crate::interrupt::disable(core, $crate::peripherals::Interrupt::$interrupt);
134
                        }
135
                    }
136
                }
137
            )*
138
        }
139

            
140
        impl $crate::private::Sealed for $name<'_> {}
141
    };
142

            
143
    ($(#[$attr:meta])* $name:ident <= $base:ident $interrupts:tt) => {
144
        create_peripheral!($(#[$attr])* $name <= virtual $interrupts);
145

            
146
        impl $name<'_> {
147
            #[doc = r"Pointer to the register block"]
148
            #[instability::unstable]
149
            pub const PTR: *const <pac::$base as core::ops::Deref>::Target = pac::$base::PTR;
150

            
151
            #[doc = r"Return the pointer to the register block"]
152
            #[inline(always)]
153
            #[instability::unstable]
154
            pub const fn ptr() -> *const <pac::$base as core::ops::Deref>::Target {
155
                pac::$base::PTR
156
            }
157

            
158
            #[doc = r"Return a reference to the register block"]
159
            #[inline(always)]
160
            #[instability::unstable]
161
            pub fn regs<'a>() -> &'a <pac::$base as core::ops::Deref>::Target {
162
                unsafe { &*Self::PTR }
163
            }
164

            
165
            #[doc = r"Return a reference to the register block"]
166
            #[inline(always)]
167
            #[instability::unstable]
168
            pub fn register_block(&self) -> &<pac::$base as core::ops::Deref>::Target {
169
                unsafe { &*Self::PTR }
170
            }
171
        }
172
    };
173
}
174

            
175
for_each_peripheral! {
176
    // Define stable peripheral singletons
177
    (@peri_type $(#[$meta:meta])* $name:ident <= $from_pac:tt $interrupts:tt) => {
178
        create_peripheral!( $(#[$meta])* $name <= $from_pac $interrupts);
179
    };
180

            
181
    // Define unstable peripheral singletons
182
    (@peri_type $(#[$meta:meta])* $name:ident <= $from_pac:tt $interrupts:tt (unstable)) => {
183
        create_peripheral!(#[instability::unstable] $(#[$meta])* $name <= $from_pac $interrupts);
184
    };
185

            
186
    // Define the Peripherals struct
187
    (singletons $( ( $(#[$cfg:meta])* $name:ident $(($unstable:ident $(#[$unstable_cfg:meta])*))?) ),*) => {
188
        // We need a way to ignore the "unstable" marker, but macros can't generate attributes or struct fields.
189
        // The solution is appending an empty string to a doc comment.
190
        macro_rules! ignore { ($any:tt) => {""} }
191

            
192
        /// The `Peripherals` struct provides access to all of the hardware peripherals on the chip.
193
        #[allow(non_snake_case)]
194
        #[non_exhaustive]
195
        pub struct Peripherals {
196
            $(
197
                // This is a bit hairy, but non-macro attributes are not allowed on struct fields. We work
198
                // around this by excluding code with the `$()?` optional macro syntax and an "unstable" marker
199
                // in the source data. The marker itself is passed through the `ignore` macro so that it doesn't
200
                // appear in the generated code.
201
                //
202
                // The code can end up looking two ways:
203
                //
204
                // - Without `unstable` we just generate the field:
205
                // ```
206
                // #[attributes]
207
                // pub PERI: PERI<'static>,
208
                // ```
209
                //
210
                // - With `unstable` we're basically emulating what `instability::unstable` would do:
211
                // ```
212
                // #[attributes]
213
                // #[cfg(feature = "unstable")]
214
                // pub PERI: PERI<'static>,
215
                //
216
                // #[attributes]
217
                // #[cfg(not(feature = "unstable"))]
218
                // pub(crate) PERI: PERI<'static>,
219
                // ```
220
                $(#[$cfg])*
221
                #[doc = concat!("The ", stringify!($name), " peripheral.")]
222
                $(
223
                    #[doc = concat!("**This API is marked as unstable** and is only available when the `unstable`
224
                            crate feature is enabled. This comes with no stability guarantees, and could be changed
225
                            or removed at any time.", ignore!($unstable))]
226
                    #[cfg(feature = "unstable")]
227
                    #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
228
                )?
229
                pub $name: $name<'static>,
230

            
231
                $(
232
                    $(#[$unstable_cfg])*
233
                    #[doc = concat!("The ", stringify!($name), " peripheral.")]
234
                    #[doc = concat!("**This API is marked as unstable** and is only available when the `unstable`
235
                            crate feature is enabled. This comes with no stability guarantees, and could be changed
236
                            or removed at any time.", ignore!($unstable))]
237
                    #[cfg(not(feature = "unstable"))]
238
                    #[allow(unused)]
239
                    pub(crate) $name: $name<'static>,
240
                )?
241
            )*
242
        }
243

            
244
        impl Peripherals {
245
            /// Returns all the peripherals *once*.
246
            #[inline]
247
            #[cfg(feature = "rt")]
248
            pub(crate) fn take() -> Self {
249
                #[unsafe(no_mangle)]
250
                static mut _ESP_HAL_DEVICE_PERIPHERALS: bool = false;
251

            
252
                crate::ESP_HAL_LOCK.lock(|| unsafe {
253
325
                    if _ESP_HAL_DEVICE_PERIPHERALS {
254
                        panic!("init called more than once!")
255
                    }
256
325
                    _ESP_HAL_DEVICE_PERIPHERALS = true;
257
                    Self::steal()
258
                })
259
            }
260

            
261
            /// Unsafely creates an instance of this peripheral out of thin air.
262
            ///
263
            /// # Safety
264
            ///
265
            /// The caller must ensure that only one instance of this type is used at a time.
266
            #[inline]
267
            pub unsafe fn steal() -> Self {
268
                unsafe {
269
                    Self {
270
                        $(
271
                            $(#[$cfg])*
272
                            $name: $name::steal(),
273
                        )*
274
                    }
275
                }
276
            }
277
        }
278
    };
279
}