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}