esp_hal/
peripheral.rs

1//! # Exclusive peripheral access
2
3/// Creates a new `Peripherals` struct and its associated methods.
4///
5/// The macro has a few fields doing different things, in the form of
6/// `second <= third (fourth)`.
7/// - The second field is the name of the peripheral, as it appears in the
8///   `Peripherals` struct.
9/// - The third field is the name of the peripheral as it appears in the PAC.
10///   This may be `virtual` if the peripheral is not present in the PAC.
11/// - The fourth field is an optional list of interrupts that can be bound to
12///   the peripheral.
13#[doc(hidden)]
14#[macro_export]
15macro_rules! peripherals {
16    (
17        peripherals: [
18            $(
19                $name:ident <= $from_pac:tt $(($($interrupt:ident),*))?
20            ),* $(,)?
21        ],
22        unstable_peripherals: [
23            $(
24                $unstable_name:ident <= $unstable_from_pac:tt $(($($unstable_interrupt:ident),*))?
25            ),* $(,)?
26        ],
27        pins: [
28            $( ( $pin:literal, $($pin_tokens:tt)* ) )*
29        ]
30    ) => {
31        paste::paste! {
32            $(
33                $crate::create_peripheral!($name <= $from_pac);
34            )*
35            $(
36                $crate::create_peripheral!(#[instability::unstable] $unstable_name <= $unstable_from_pac);
37            )*
38            $(
39                $crate::create_peripheral!([< GPIO $pin >] <= virtual);
40            )*
41
42            /// The `Peripherals` struct provides access to all of the hardware peripherals on the chip.
43            #[allow(non_snake_case)]
44            pub struct Peripherals {
45                $(
46                    #[doc = concat!("The ", stringify!($name), " peripheral.")]
47                    pub $name: $name<'static>,
48                )*
49                $(
50                    #[doc = concat!("The ", stringify!($unstable_name), " peripheral.")]
51                    #[doc = "**This API is marked as unstable** and is only available when the `unstable`
52                            crate feature is enabled. This comes with no stability guarantees, and could be changed
53                            or removed at any time."]
54                    #[cfg(feature = "unstable")]
55                    #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
56                    pub $unstable_name: $unstable_name<'static>,
57
58                    #[doc = concat!("The ", stringify!($unstable_name), " peripheral.")]
59                    #[doc = "**This API is marked as unstable** and is only available when the `unstable`
60                            crate feature is enabled. This comes with no stability guarantees, and could be changed
61                            or removed at any time."]
62                    #[cfg(not(feature = "unstable"))]
63                    #[allow(unused)]
64                    pub(crate) $unstable_name: $unstable_name<'static>,
65                )*
66
67                $(
68                    #[doc = concat!("GPIO", stringify!($pin))]
69                    pub [<GPIO $pin>]: [<GPIO $pin>]<'static>,
70                )*
71            }
72
73            impl Peripherals {
74                /// Returns all the peripherals *once*
75                #[inline]
76                pub(crate) fn take() -> Self {
77                    #[unsafe(no_mangle)]
78                    static mut _ESP_HAL_DEVICE_PERIPHERALS: bool = false;
79
80                    critical_section::with(|_| unsafe {
81                        if _ESP_HAL_DEVICE_PERIPHERALS {
82                            panic!("init called more than once!")
83                        }
84                        _ESP_HAL_DEVICE_PERIPHERALS = true;
85                        Self::steal()
86                    })
87                }
88
89                /// Unsafely create an instance of this peripheral out of thin air.
90                ///
91                /// # Safety
92                ///
93                /// You must ensure that you're only using one instance of this type at a time.
94                #[inline]
95                pub unsafe fn steal() -> Self {
96                    unsafe {
97                        Self {
98                            $(
99                                $name: $name::steal(),
100                            )*
101                            $(
102                                $unstable_name: $unstable_name::steal(),
103                            )*
104
105                            $(
106                                [<GPIO $pin>]: [<GPIO $pin>]::steal(),
107                            )*
108                        }
109                    }
110                }
111            }
112
113            $crate::gpio! {
114                $( ($pin, $($pin_tokens)* ) )*
115            }
116        }
117
118        $(
119            $(
120                impl $name<'_> {
121                    $(
122                        paste::paste!{
123                            /// Binds an interrupt handler to the corresponding interrupt for this peripheral.
124                            #[instability::unstable]
125                            pub fn [<bind_ $interrupt:lower _interrupt >](&mut self, handler: unsafe extern "C" fn() -> ()) {
126                                unsafe { $crate::interrupt::bind_interrupt($crate::peripherals::Interrupt::$interrupt, handler); }
127                            }
128                        }
129                    )*
130                }
131            )*
132        )*
133
134        $(
135            $(
136                impl $unstable_name<'_> {
137                    $(
138                        paste::paste!{
139                            /// Binds an interrupt handler to the corresponding interrupt for this peripheral.
140                            #[instability::unstable]
141                            pub fn [<bind_ $unstable_interrupt:lower _interrupt >](&mut self, handler: unsafe extern "C" fn() -> ()) {
142                                unsafe { $crate::interrupt::bind_interrupt($crate::peripherals::Interrupt::$unstable_interrupt, handler); }
143                            }
144                        }
145                    )*
146                }
147            )*
148        )*
149    };
150}
151
152#[doc(hidden)]
153#[macro_export]
154/// Macro to create a peripheral structure.
155macro_rules! create_peripheral {
156    ($(#[$attr:meta])? $name:ident <= virtual) => {
157        $(#[$attr])?
158        #[derive(Debug)]
159        #[cfg_attr(feature = "defmt", derive(defmt::Format))]
160        #[non_exhaustive]
161        #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
162        #[doc = concat!(stringify!($name), " peripheral singleton")]
163        pub struct $name<'a> {
164            _marker: core::marker::PhantomData<&'a mut ()>,
165        }
166
167        impl $name<'_> {
168            /// Unsafely create an instance of this peripheral out of thin air.
169            ///
170            /// # Safety
171            ///
172            /// You must ensure that you're only using one instance of this type at a time.
173            #[inline]
174            pub unsafe fn steal() -> Self {
175                Self {
176                    _marker: core::marker::PhantomData,
177                }
178            }
179
180            /// Unsafely clone this peripheral reference.
181            ///
182            /// # Safety
183            ///
184            /// You must ensure that you're only using one instance of this type at a time.
185            #[inline]
186            #[allow(dead_code)]
187            pub unsafe fn clone_unchecked(&self) -> Self {
188                unsafe { Self::steal() }
189            }
190
191            /// Creates a new peripheral reference with a shorter lifetime.
192            ///
193            /// Use this method if you would like to keep working with the peripheral after
194            /// you dropped the driver that consumes this.
195            #[inline]
196            #[allow(dead_code)]
197            pub fn reborrow(&mut self) -> $name<'_> {
198                unsafe { self.clone_unchecked() }
199            }
200        }
201
202        impl $crate::private::Sealed for $name<'_> {}
203    };
204
205    ($(#[$attr:meta])? $name:ident <= $base:ident) => {
206        $crate::create_peripheral!($(#[$attr])? $name <= virtual);
207
208        impl $name<'_> {
209            #[doc = r"Pointer to the register block"]
210            #[instability::unstable]
211            pub const PTR: *const <pac::$base as core::ops::Deref>::Target = pac::$base::PTR;
212
213            #[doc = r"Return the pointer to the register block"]
214            #[inline(always)]
215            #[instability::unstable]
216            pub const fn ptr() -> *const <pac::$base as core::ops::Deref>::Target {
217                pac::$base::PTR
218            }
219
220            #[doc = r"Return a reference to the register block"]
221            #[inline(always)]
222            #[instability::unstable]
223            pub const fn regs<'a>() -> &'a <pac::$base as core::ops::Deref>::Target {
224                unsafe { &*Self::PTR }
225            }
226
227            #[doc = r"Return a reference to the register block"]
228            #[inline(always)]
229            #[instability::unstable]
230            pub fn register_block(&self) -> &<pac::$base as core::ops::Deref>::Target {
231                unsafe { &*Self::PTR }
232            }
233        }
234    };
235}