imxrt_hal/
lib.rs

1//! A hardware abstraction layer (HAL) for i.MX RT MCUs.
2//!
3//! `imxrt-hal` contains a collection of hardware drivers for various i.MX RT
4//! MCUs. A default build of `imxrt-hal` provides drivers that are portable
5//! across all i.MX RT chips. When your specific chip is known, `imxrt-hal`
6//! provides additional, chip-specific APIs. Most drivers implement their
7//! corresponding `embedded-hal` traits, or they can be adapted to use
8//! `embedded-hal` traits in user code.
9//!
10//! # Building
11//!
12//! `imxrt-hal` requires that you, or something in your dependency graph, enable
13//! a chip-specific feature from `imxrt-ral`, the i.MX RT _register access layer
14//! (RAL)_.  Without this, the HAL does not build. Since the HAL uses the RAL in
15//! its public API, you're expected to depend on both packages.
16//!
17//! Here's an example of a project that builds the `imxrt-hal` for an i.MX RT
18//! 1062 system.
19//!
20//! ```toml
21//! [dependencies.imxrt-hal] # There's no required feature here...
22//! version = # ...
23//!
24//! [dependencies.imxrt-ral]
25//! version = # ...
26//! features = ["imxrt1062"] # ...but this feature is required.
27//! ```
28//!
29//! Once you've enabled a RAL feature, the HAL builds without any additional
30//! features. All APIs exposed in this build are portable across all supported
31//! i.MX RT chips.
32//!
33//! # Examples
34//!
35//! See each module's documentation for examples. Note that documentation
36//! examples may assume a specific chip and chip family, so you may need to
37//! adapt the example for your hardware.
38//!
39//! The `imxrt-hal` repository maintains examples that run on various i.MX RT
40//! development boards. See the project documentation for more information.
41//!
42//! # Configuration
43//!
44//! Use these optional features to control the HAL build.
45//!
46//! | Feature           | Description                                                      |
47//! |-------------------|------------------------------------------------------------------|
48//! | `"imxrt1010"`     | Enable features for the 1010 chips.                              |
49//! | `"imxrt1020"`     | Enable features for the 1020 chips.                              |
50//! | `"imxrt1060"`     | Enable features for the 1060 chips.                              |
51//! | `"imxrt1064"`     | Enable features for the 1064 chips.                              |
52//! | `"imxrt1170"`     | Enable features for the 1170 chips.                              |
53//! | `"eh02-unproven"` | Enable implementations for embedded-hal 0.2 `"unproven"` traits. |
54//! | `"rand_core"`     | Allows the TRNG to be used with the `rand` package.              |
55//!
56//! The APIs exposed by the various `"imxrt[...]"` features are chip specific.
57//! The HAL does not support building with more than one of these features at a
58//! time.
59//!
60//! When enabling a HAL chip feature, make sure that it pairs properly with your
61//! RAL chip selection. You are responsible for making sure that your RAL chip
62//! feature is appropriate for the HAL chip feature. For instance, mixing the
63//! RAL's `imxrt1062` feature with the HAL's `imxrt1010` feature is not
64//! supported.
65//!
66//! ```toml
67//! [dependencies.imxrt-hal]
68//! version = # ...
69//! #Bad: doesn't support RAL feature.
70//! #features = ["imxrt1010"]
71//!
72//! #Good: supports RAL feature
73//! features = ["imxrt1060"]
74//!
75//! [dependencies.imxrt-ral]
76//! version = # ...
77//! features = ["imxrt1062"] # Informs the HAL chip feature
78//! ```
79//!
80//! The `"eh02-unproven"` feature will not build without the corresponding
81//! `"unproven"` feature enabled in embedded-hal 0.2.
82
83#![no_std]
84#![warn(
85    missing_docs,
86    unsafe_op_in_unsafe_fn,
87    clippy::undocumented_unsafe_blocks,
88    clippy::missing_safety_doc
89)]
90
91use imxrt_ral as ral;
92
93mod chip;
94
95/// Modules that need no HAL conditional compilation.
96///
97/// These modules only depend on a RAL feature.
98mod common {
99    pub use imxrt_dma as dma;
100
101    pub mod ccm;
102    pub mod flexpwm;
103    pub mod gpio;
104    pub mod gpt;
105    pub mod lpi2c;
106    pub mod lpspi;
107    pub mod lpuart;
108    pub mod pit;
109    pub mod snvs;
110    pub mod timer;
111}
112
113// These common drivers have no associated chip APIs, so
114// export them directly.
115pub use common::{flexpwm, gpio, gpt, lpi2c, lpspi, lpuart, pit, snvs, timer};
116
117/// Clock control module.
118///
119/// Unlike other drivers in this package, this module only provides a
120/// thin layer over the `imxrt-ral` APIs. It's fairly low level, but
121/// more discoverable than the registers and reference manual.
122///
123/// # Overview
124///
125/// Use [`clock_gate`](crate::ccm::clock_gate) APIs to enable or disable the clock gates for
126/// various peripherals. You'll need to enable clock gates before you
127/// start using peripherals.
128///
129/// The remaining modules provide lower-level APIs for the CCM clock
130/// tree. These APIs may not be portable across chip families.
131///
132/// # Visibility
133///
134/// If you see items in this module, it's because a chip family feature is
135/// enabled in the HAL. These symbols may vary depending on the selected
136/// feature.
137pub mod ccm {
138    pub use crate::chip::ccm::*;
139}
140
141/// Direct memory access.
142///
143/// Use the `dma` APIs to perform memory operations without processor intervention.
144/// The API supports the following transfers:
145///
146/// - peripheral to memory
147/// - memory to peripheral
148/// - memory to memory
149///
150/// Peripheral support depends on the peripheral. See your peripheral's API for details.
151/// Methods that use DMA are typically prefixed with `dma`.
152///
153/// DMA transfers are modeled as futures. The examples below demonstrate a simple way
154/// to start a transfer. Since these are futures, you may use these futures in `async` code.
155///
156/// # DMA channels
157///
158/// The API provides access to at least 16 DMA channels. If you've enabled an optional chip
159/// family feature, this number may change. See [`CHANNEL_COUNT`](crate::dma::CHANNEL_COUNT)
160/// for more information.
161///
162/// # Visibility
163///
164/// Select items become visible when a chip family feature is enabled.
165///
166/// # Example
167///
168/// Use [`channels()`](crate::dma::channels) to access all DMA channels for your processor.
169///
170/// ```no_run
171/// use imxrt_hal as hal;
172/// use imxrt_ral as ral;
173///
174/// # fn doc() -> Option<()> {
175/// let mut ccm = unsafe { ral::ccm::CCM::instance() };
176/// hal::ccm::clock_gate::dma().set(&mut ccm, hal::ccm::clock_gate::ON);
177///
178/// let mut channels = hal::dma::channels(
179///     unsafe { ral::dma::DMA::instance() },
180///     unsafe { ral::dmamux::DMAMUX::instance() },
181/// );
182///
183/// // Selecting the 13th DMA channel for our examples...
184/// let mut channel = channels[13].take()?;
185/// # Some(()) }
186/// ```
187///
188/// Construct and poll a [`Memcpy`](crate::dma::memcpy::Memcpy) to
189/// perform a memory-to-memory transfer.
190///
191/// ```no_run
192/// # async fn a() -> Option<()> {
193/// # use imxrt_hal as hal;
194/// # use imxrt_ral as ral;
195/// # let mut channel = unsafe { hal::dma::DMA.channel(13) };
196/// let source = [4u32, 5, 6, 7];
197/// let mut destination = [0u32; 4];
198///
199/// let memcpy = hal::dma::memcpy::memcpy(&source, &mut destination, &mut channel);
200/// memcpy.await.ok()?;
201/// # Some(()) }
202/// ```
203///
204/// For examples of using DMA with a peripheral, see the peripheral's documentation.
205pub mod dma {
206    #[cfg_attr(family = "none", allow(unused_imports))] // Nothing to export in this build.
207    pub use crate::chip::dma::*;
208    pub use crate::common::dma::*;
209}
210
211/// USB device.
212///
213/// This module re-exports types from the `imxrt-usbd` package. The driver is compatible
214///  with the [`usb-device`](https://docs.rs/usb-device/latest/usb_device/) ecosystem.
215///
216/// It also provides [`Instances`](crate::usbd::Instances), an implementation of `imxrt_usbd::Peripherals` over
217/// `imxrt-ral` USB instances.
218///
219/// # Example
220///
221/// Construct a [`BusAdapter`](crate::usbd::BusAdapter) with USB peripheral instances. See the
222/// [`BusAdapter`](crate::usbd::BusAdapter) documentation for more information on how to use the bus.
223///
224/// ```no_run
225/// use imxrt_hal as hal;
226/// use imxrt_ral as ral;
227///
228/// use hal::usbd;
229///
230/// # || -> Option<()> {
231/// let mut usb_analog = unsafe { ral::usb_analog::USB_ANALOG::instance() };
232/// let usb_instances = usbd::Instances {
233///     usb: unsafe { ral::usb::USB1::instance() },
234///     usbnc: unsafe { ral::usbnc::USBNC1::instance() },
235///     usbphy: unsafe { ral::usbphy::USBPHY1::instance() },
236/// };
237///
238/// // Prepare the USB clocks.
239/// let mut ccm_analog = unsafe { ral::ccm_analog::CCM_ANALOG::instance() };
240/// hal::ccm::analog::pll3::restart(&mut ccm_analog);
241///
242/// static ENDPOINT_MEMORY: usbd::EndpointMemory<2048> = usbd::EndpointMemory::new();
243/// static ENDPOINT_STATE: usbd::EndpointState = usbd::EndpointState::max_endpoints();
244///
245/// let usbd = usbd::BusAdapter::new(usb_instances, &ENDPOINT_MEMORY, &ENDPOINT_STATE);
246/// # Some(()) }().unwrap();
247/// ```
248#[cfg(feature = "imxrt-usbd")]
249pub mod usbd {
250    pub use imxrt_usbd::*;
251
252    use crate::ral;
253
254    /// Aggregate of `imxrt-ral` USB peripheral instances.
255    ///
256    /// This takes ownership of USB peripheral instances and implements
257    /// [`Peripherals`]. You can use this type to allocate a USB device
258    /// driver. See the [module-level documentation](crate::usbd) for an
259    /// example.
260    pub struct Instances<const N: u8> {
261        /// USB core registers.
262        pub usb: ral::usb::Instance<N>,
263        /// USB non-core registers.
264        pub usbnc: ral::usbnc::Instance<N>,
265        /// USBPHY registers.
266        pub usbphy: ral::usbphy::Instance<N>,
267    }
268
269    // Safety: pointers to USB peripheral blocks come from
270    // imxrt-ral, which provides correct addresses. We take
271    // ownership of the peripheral instances, preventing others
272    // from aliasing the peripherals.
273    unsafe impl<const N: u8> Peripherals for Instances<N> {
274        fn usb(&self) -> *const () {
275            (&*self.usb as *const ral::usb::RegisterBlock).cast()
276        }
277        fn usbphy(&self) -> *const () {
278            (&*self.usbphy as *const ral::usbphy::RegisterBlock).cast()
279        }
280    }
281}
282
283/// Pad muxing and configurations.
284///
285/// This module re-exports select items from the `imxrt-iomuxc` crate. When a chip feature is enabled, the module also exports
286/// chip-specific items, like `into_pads`. Use [`into_pads`](crate::iomuxc::into_pads) to transform the `imxrt-ral` instance(s)
287/// into pad objects:
288///
289/// ```
290/// use imxrt_hal as hal;
291/// use imxrt_ral as ral;
292///
293/// let iomuxc = unsafe { ral::iomuxc::IOMUXC::instance() };
294/// let pads = hal::iomuxc::into_pads(iomuxc);
295/// ```
296///
297/// [`Pads`](crate::iomuxc::pads::Pads) exposes all pads as individual, owned objects. Use [`configure`](crate::iomuxc::configure)
298/// to specify any pad configurations. Then use the pad object(s) to construct your driver.
299pub mod iomuxc {
300    #[cfg_attr(family = "none", allow(unused_imports))] // Nothing to export in this build.
301    pub use crate::chip::iomuxc::*;
302    pub use imxrt_iomuxc::prelude::*;
303}
304
305#[cfg_attr(family = "none", allow(unused_imports))] // Nothing to export in this build.
306pub use crate::chip::reexports::*;
307
308/// Simply spin on the future.
309fn spin_on<F: core::future::Future>(future: F) -> F::Output {
310    use core::task::{Context, Poll};
311
312    let waker = futures::task::noop_waker();
313    let mut context = Context::from_waker(&waker);
314    let mut future = core::pin::pin!(future);
315
316    loop {
317        if let Poll::Ready(result) = future.as_mut().poll(&mut context) {
318            return result;
319        }
320    }
321}