ch58x_hal/
peripheral.rs

1//! # Exclusive peripheral access
2//!
3//! ## Overview
4//! The Peripheral module provides an exclusive access mechanism to peripherals
5//! on MCU chips. It includes the `PeripheralRef` struct, which represents an
6//! exclusive reference to a peripheral. It offers memory efficiency benefits
7//! for zero-sized types.
8//!
9//! The `PeripheralRef` struct is used to access and interact with peripherals.
10//! It implements the `Deref` and `DerefMut` traits, allowing you to dereference
11//! it to access the underlying peripheral. It also provides methods for cloning
12//! and re-borrowing the peripheral.
13//!
14//! The module also defines the `Peripheral` trait, which is implemented by
15//! types that can be used as peripherals. The trait allows conversion between
16//! owned and borrowed peripherals and provides an unsafe method for cloning the
17//! peripheral. By implementing this trait, a type can be used with the
18//! `PeripheralRef` struct.
19//!
20//! The module also includes a `peripheral_macros` module, which contains macros
21//! for generating peripheral structs and associated traits based on
22//! configuration options.
23//!
24//! ## Examples
25//!
26//! ### Initialization
27//! ```no_run
28//! let peripherals = Peripherals::take();
29//! ```
30//! ### Accessing peripherals
31//! ```no_run
32//! let mut rtc = Rtc::new(peripherals.RTC);
33//! ```
34
35use core::marker::PhantomData;
36use core::ops::{Deref, DerefMut};
37
38/// An exclusive reference to a peripheral.
39///
40/// This is functionally the same as a `&'a mut T`. The reason for having a
41/// dedicated struct is memory efficiency:
42///
43/// Peripheral singletons are typically either zero-sized (for concrete
44/// peripehrals like `PA9` or `Spi4`) or very small (for example `AnyPin` which
45/// is 1 byte). However `&mut T` is always 4 bytes for 32-bit targets, even if T
46/// is zero-sized. PeripheralRef stores a copy of `T` instead, so it's the same
47/// size.
48///
49/// but it is the size of `T` not the size
50/// of a pointer. This is useful if T is a zero sized type.
51pub struct PeripheralRef<'a, T> {
52    inner: T,
53    _lifetime: PhantomData<&'a mut T>,
54}
55
56impl<'a, T> PeripheralRef<'a, T> {
57    #[inline]
58    pub fn new(inner: T) -> Self {
59        Self {
60            inner,
61            _lifetime: PhantomData,
62        }
63    }
64
65    /// Unsafely clone (duplicate) a peripheral singleton.
66    ///
67    /// # Safety
68    ///
69    /// This returns an owned clone of the peripheral. You must manually ensure
70    /// only one copy of the peripheral is in use at a time. For example, don't
71    /// create two SPI drivers on `SPI1`, because they will "fight" each other.
72    ///
73    /// You should strongly prefer using `reborrow()` instead. It returns a
74    /// `PeripheralRef` that borrows `self`, which allows the borrow checker
75    /// to enforce this at compile time.
76    pub unsafe fn clone_unchecked(&self) -> PeripheralRef<'a, T>
77    where
78        T: Peripheral<P = T>,
79    {
80        PeripheralRef::new(self.inner.clone_unchecked())
81    }
82
83    /// Reborrow into a "child" PeripheralRef.
84    ///
85    /// `self` will stay borrowed until the child PeripheralRef is dropped.
86    pub fn reborrow(&mut self) -> PeripheralRef<'_, T>
87    where
88        T: Peripheral<P = T>,
89    {
90        // safety: we're returning the clone inside a new PeripheralRef that borrows
91        // self, so user code can't use both at the same time.
92        PeripheralRef::new(unsafe { self.inner.clone_unchecked() })
93    }
94
95    /// Map the inner peripheral using `Into`.
96    ///
97    /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`,
98    /// using an `Into` impl to convert from `T` to `U`.
99    ///
100    /// For example, this can be useful to degrade GPIO pins: converting from
101    /// PeripheralRef<'a, PB11>` to `PeripheralRef<'a, AnyPin>`.
102    #[inline]
103    pub fn map_into<U>(self) -> PeripheralRef<'a, U>
104    where
105        T: Into<U>,
106    {
107        PeripheralRef {
108            inner: self.inner.into(),
109            _lifetime: PhantomData,
110        }
111    }
112}
113
114impl<'a, T> Deref for PeripheralRef<'a, T> {
115    type Target = T;
116
117    #[inline]
118    fn deref(&self) -> &Self::Target {
119        &self.inner
120    }
121}
122
123impl<'a, T> DerefMut for PeripheralRef<'a, T> {
124    #[inline]
125    fn deref_mut(&mut self) -> &mut Self::Target {
126        &mut self.inner
127    }
128}
129
130/// Trait for any type that can be used as a peripheral of type `P`.
131///
132/// This is used in driver constructors, to allow passing either owned
133/// peripherals (e.g. `TWISPI0`), or borrowed peripherals (e.g. `&mut TWISPI0`).
134///
135/// For example, if you have a driver with a constructor like this:
136///
137/// ```ignore
138/// impl<'d, T: Instance> Twim<'d, T> {
139///     pub fn new(
140///         twim: impl Peripheral<P = T> + 'd,
141///         irq: impl Peripheral<P = T::Interrupt> + 'd,
142///         sda: impl Peripheral<P = impl GpioPin> + 'd,
143///         scl: impl Peripheral<P = impl GpioPin> + 'd,
144///         config: Config,
145///     ) -> Self { .. }
146/// }
147/// ```
148///
149/// You may call it with owned peripherals, which yields an instance that can
150/// live forever (`'static`):
151///
152/// ```ignore
153/// let mut twi: Twim<'static, ...> = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
154/// ```
155///
156/// Or you may call it with borrowed peripherals, which yields an instance that
157/// can only live for as long as the borrows last:
158///
159/// ```ignore
160/// let mut twi: Twim<'_, ...> = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
161/// ```
162///
163/// # Implementation details, for HAL authors
164///
165/// When writing a HAL, the intended way to use this trait is to take `impl
166/// Peripheral<P = ..>` in the HAL's public API (such as driver constructors),
167/// calling `.into_ref()` to obtain a `PeripheralRef`, and storing that in the
168/// driver struct.
169///
170/// `.into_ref()` on an owned `T` yields a `PeripheralRef<'static, T>`.
171/// `.into_ref()` on an `&'a mut T` yields a `PeripheralRef<'a, T>`.
172pub trait Peripheral: Sized + sealed::Sealed {
173    /// Peripheral singleton type
174    type P;
175
176    /// Unsafely clone (duplicate) a peripheral singleton.
177    ///
178    /// # Safety
179    ///
180    /// This returns an owned clone of the peripheral. You must manually ensure
181    /// only one copy of the peripheral is in use at a time. For example, don't
182    /// create two SPI drivers on `SPI1`, because they will "fight" each other.
183    ///
184    /// You should strongly prefer using `into_ref()` instead. It returns a
185    /// `PeripheralRef`, which allows the borrow checker to enforce this at
186    /// compile time.
187    unsafe fn clone_unchecked(&self) -> Self::P;
188
189    /// Convert a value into a `PeripheralRef`.
190    ///
191    /// When called on an owned `T`, yields a `PeripheralRef<'static, T>`.
192    /// When called on an `&'a mut T`, yields a `PeripheralRef<'a, T>`.
193    #[inline]
194    fn into_ref<'a>(self) -> PeripheralRef<'a, Self::P>
195    where
196        Self: 'a,
197    {
198        PeripheralRef::new(unsafe { self.clone_unchecked() })
199    }
200}
201
202impl<T> Peripheral for &mut T
203where
204    T: Peripheral<P = T>,
205{
206    type P = T;
207
208    unsafe fn clone_unchecked(&self) -> Self::P {
209        T::clone_unchecked(self)
210    }
211}
212
213impl<T> sealed::Sealed for &mut T where T: sealed::Sealed {}
214
215pub(crate) mod sealed {
216    pub trait Sealed {}
217}
218
219mod peripheral_macros {
220    #[doc(hidden)]
221    #[macro_export]
222    macro_rules! peripherals {
223        ($($(#[$cfg:meta])? $name:ident <= $from_pac:tt),*$(,)?) => {
224
225            /// Contains the generated peripherals which implement [`Peripheral`]
226            mod peripherals {
227                $(
228                    $crate::create_peripheral!($(#[$cfg])? $name <= $from_pac);
229                )*
230            }
231
232            #[allow(non_snake_case)]
233            pub struct Peripherals {
234                $(
235                    $(#[$cfg])?
236                    pub $name: peripherals::$name,
237                )*
238            }
239
240            impl Peripherals {
241                /// Returns all the peripherals *once*
242                #[inline]
243                pub fn take() -> Self {
244
245                    #[no_mangle]
246                    static mut __HAL_DEVICE_PERIPHERALS: bool = false;
247
248                    critical_section::with(|_| unsafe {
249                        if __HAL_DEVICE_PERIPHERALS {
250                            panic!("init called more than once!")
251                        }
252                        __HAL_DEVICE_PERIPHERALS = true;
253                        Self::steal()
254                    })
255                }
256            }
257
258            impl Peripherals {
259                /// Unsafely create an instance of this peripheral out of thin air.
260                ///
261                /// # Safety
262                ///
263                /// You must ensure that you're only using one instance of this type at a time.
264                #[inline]
265                pub unsafe fn steal() -> Self {
266                    Self {
267                        $(
268                            $(#[$cfg])?
269                            $name: peripherals::$name::steal(),
270                        )*
271                    }
272                }
273            }
274
275            // expose the new structs
276            $(
277                pub use peripherals::$name;
278            )*
279        }
280    }
281
282    #[doc(hidden)]
283    #[macro_export]
284    macro_rules! into_ref {
285        ($($name:ident),*) => {
286            $(
287                #[allow(unused_mut)]
288                let mut $name = $name.into_ref();
289            )*
290        }
291    }
292
293    #[doc(hidden)]
294    #[macro_export]
295    macro_rules! create_peripheral {
296        ($(#[$cfg:meta])? $name:ident <= virtual) => {
297            $(#[$cfg])?
298            #[derive(Debug)]
299            #[allow(non_camel_case_types)]
300            pub struct $name { _inner: () }
301
302            $(#[$cfg])?
303            impl $name {
304                /// Unsafely create an instance of this peripheral out of thin air.
305                ///
306                /// # Safety
307                ///
308                /// You must ensure that you're only using one instance of this type at a time.
309                #[inline]
310                pub unsafe fn steal() -> Self {
311                    Self { _inner: () }
312                }
313            }
314
315            impl $crate::peripheral::Peripheral for $name {
316                type P = $name;
317
318                #[inline]
319                unsafe fn clone_unchecked(&self) -> Self::P {
320                    Self::steal()
321                }
322            }
323
324            impl crate::peripheral::sealed::Sealed for $name {}
325        };
326        ($(#[$cfg:meta])? $name:ident <= $base:ident) => {
327            $(#[$cfg])?
328            #[derive(Debug)]
329            #[allow(non_camel_case_types)]
330            pub struct $name { _inner: () }
331
332            $(#[$cfg])?
333            impl $name {
334                /// Unsafely create an instance of this peripheral out of thin air.
335                ///
336                /// # Safety
337                ///
338                /// You must ensure that you're only using one instance of this type at a time.
339                #[inline]
340                pub unsafe fn steal() -> Self {
341                    Self { _inner: () }
342                }
343
344                #[doc = r"Pointer to the register block"]
345                pub const PTR: *const <super::pac::$base as core::ops::Deref>::Target = super::pac::$base::PTR;
346
347                #[doc = r"Return the pointer to the register block"]
348                #[inline(always)]
349                pub const fn ptr() -> *const <super::pac::$base as core::ops::Deref>::Target {
350                    super::pac::$base::PTR
351                }
352            }
353
354            impl core::ops::Deref for $name {
355                type Target = <super::pac::$base as core::ops::Deref>::Target;
356
357                fn deref(&self) -> &Self::Target {
358                    unsafe { &*Self::PTR }
359                }
360            }
361
362            impl core::ops::DerefMut for $name {
363
364                fn deref_mut(&mut self) -> &mut Self::Target {
365                    unsafe { &mut *(Self::PTR as *mut _)  }
366                }
367            }
368
369            impl crate::peripheral::Peripheral for $name {
370                type P = $name;
371
372                #[inline]
373                unsafe fn clone_unchecked(&self) -> Self::P {
374                    Self::steal()
375                }
376            }
377
378            impl crate::peripheral::sealed::Sealed for $name {}
379        };
380    }
381}
382
383#[macro_export]
384macro_rules! impl_peripheral {
385    ($type:ident) => {
386        impl $crate::Peripheral for $type {
387            type P = $type;
388
389            #[inline]
390            unsafe fn clone_unchecked(&self) -> Self::P {
391                #[allow(clippy::needless_update)]
392                $type { ..*self }
393            }
394        }
395        impl $crate::peripheral::sealed::Sealed for $type {}
396    };
397}