Skip to main content

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//! | `"imxrt1180"`     | Enable features for the 1180 chips.                              |
54//!
55//! The APIs exposed by the various `"imxrt[...]"` features are chip specific.
56//! The HAL does not support building with more than one of these features at a
57//! time.
58//!
59//! When enabling a HAL chip feature, make sure that it pairs properly with your
60//! RAL chip selection. You are responsible for making sure that your RAL chip
61//! feature is appropriate for the HAL chip feature. For instance, mixing the
62//! RAL's `imxrt1062` feature with the HAL's `imxrt1010` feature is not
63//! supported.
64//!
65//! ```toml
66//! [dependencies.imxrt-hal]
67//! version = # ...
68//! #Bad: doesn't support RAL feature.
69//! #features = ["imxrt1010"]
70//!
71//! #Good: supports RAL feature
72//! features = ["imxrt1060"]
73//!
74//! [dependencies.imxrt-ral]
75//! version = # ...
76//! features = ["imxrt1062"] # Informs the HAL chip feature
77//! ```
78
79#![no_std]
80#![warn(
81    missing_docs,
82    unsafe_op_in_unsafe_fn,
83    clippy::undocumented_unsafe_blocks,
84    clippy::missing_safety_doc
85)]
86
87use imxrt_ral as ral;
88
89mod chip;
90
91/// Modules that need no HAL conditional compilation.
92///
93/// These modules only depend on a RAL feature.
94mod common {
95    pub use imxrt_dma as dma;
96
97    pub mod ccm;
98    pub mod flexpwm;
99    pub mod gpt;
100    pub mod lpi2c;
101    pub mod lpspi;
102    pub mod lpuart;
103}
104
105// These common drivers have no associated chip APIs, so
106// export them directly.
107pub use common::{flexpwm, gpt, lpi2c, lpspi, lpuart};
108
109/// Clock control module.
110///
111/// Unlike other drivers in this package, this module only provides a
112/// thin layer over the `imxrt-ral` APIs. It's fairly low level, but
113/// more discoverable than the registers and reference manual.
114///
115/// # Overview
116///
117/// Use [`clock_gate`](crate::ccm::clock_gate) APIs to enable or disable the clock gates for
118/// various peripherals. You'll need to enable clock gates before you
119/// start using peripherals.
120///
121/// The remaining modules provide lower-level APIs for the CCM clock
122/// tree. These APIs may not be portable across chip families.
123///
124/// # Visibility
125///
126/// If you see items in this module, it's because a chip family feature is
127/// enabled in the HAL. These symbols may vary depending on the selected
128/// feature.
129pub mod ccm {
130    pub use crate::chip::ccm::*;
131}
132
133/// Direct memory access.
134///
135/// Use the `dma` APIs to perform memory operations without processor intervention.
136/// The API supports the following transfers:
137///
138/// - peripheral to memory
139/// - memory to peripheral
140/// - memory to memory
141///
142/// Peripheral support depends on the peripheral. See your peripheral's API for details.
143/// Methods that use DMA are typically prefixed with `dma`.
144///
145/// DMA transfers are modeled as futures. The examples below demonstrate a simple way
146/// to start a transfer. Since these are futures, you may use these futures in `async` code.
147///
148/// # DMA channels
149///
150/// The API provides access to at least 16 DMA channels. If you've enabled an optional chip
151/// family feature, this number may change. See [`CHANNEL_COUNT`](crate::dma::CHANNEL_COUNT)
152/// for more information.
153///
154/// # Visibility
155///
156/// Select items become visible when a chip family feature is enabled.
157///
158/// # Example
159///
160/// Use [`channels()`](crate::dma::channels) to access all DMA channels for your processor.
161///
162/// ```no_run
163/// use imxrt_hal as hal;
164/// use imxrt_ral as ral;
165///
166/// # fn doc() -> Option<()> {
167/// let mut ccm = unsafe { ral::ccm::CCM::instance() };
168/// hal::ccm::clock_gate::dma().set(&mut ccm, hal::ccm::clock_gate::ON);
169///
170/// let mut channels = hal::dma::channels(
171///     unsafe { ral::dma::DMA::instance() },
172///     unsafe { ral::dmamux::DMAMUX::instance() },
173/// );
174///
175/// // Selecting the 13th DMA channel for our examples...
176/// let mut channel = channels[13].take()?;
177/// # Some(()) }
178/// ```
179///
180/// Construct and poll a [`Memcpy`](crate::dma::memcpy::Memcpy) to
181/// perform a memory-to-memory transfer.
182///
183/// ```no_run
184/// # async fn a() -> Option<()> {
185/// # use imxrt_hal as hal;
186/// # use imxrt_ral as ral;
187/// # let mut channel = unsafe { hal::dma::DMA.channel(13) };
188/// let source = [4u32, 5, 6, 7];
189/// let mut destination = [0u32; 4];
190///
191/// let memcpy = hal::dma::memcpy::memcpy(&source, &mut destination, &mut channel);
192/// memcpy.await.ok()?;
193/// # Some(()) }
194/// ```
195///
196/// For examples of using DMA with a peripheral, see the peripheral's documentation.
197pub mod dma {
198    #[cfg_attr(chip = "none", allow(unused_imports))] // Nothing to export in this build.
199    pub use crate::chip::dma::*;
200    pub use crate::common::dma::*;
201}
202
203/// Pad muxing and configurations.
204///
205/// This module re-exports select items from the `imxrt-iomuxc` crate. When a chip feature is enabled, the module also exports
206/// chip-specific items, like `into_pads`. Use [`into_pads`](crate::iomuxc::into_pads) to transform the `imxrt-ral` instance(s)
207/// into pad objects:
208///
209/// ```
210/// use imxrt_hal as hal;
211/// use imxrt_ral as ral;
212///
213/// let iomuxc = unsafe { ral::iomuxc::IOMUXC::instance() };
214/// let pads = hal::iomuxc::into_pads(iomuxc);
215/// ```
216///
217/// [`Pads`](crate::iomuxc::pads::Pads) exposes all pads as individual, owned objects. Use [`configure`](crate::iomuxc::configure)
218/// to specify any pad configurations. Then use the pad object(s) to construct your driver.
219pub mod iomuxc {
220    #[cfg_attr(chip = "none", allow(unused_imports))] // Nothing to export in this build.
221    pub use crate::chip::iomuxc::*;
222    pub use imxrt_iomuxc::prelude::*;
223}
224
225#[cfg_attr(chip = "none", allow(unused_imports))] // Nothing to export in this build.
226pub use crate::chip::*;
227
228/// Simply spin on the future.
229fn spin_on<F: core::future::Future>(future: F) -> F::Output {
230    use core::task::{Context, Poll};
231
232    let waker = futures::task::noop_waker();
233    let mut context = Context::from_waker(&waker);
234    let mut future = core::pin::pin!(future);
235
236    loop {
237        if let Poll::Ready(result) = future.as_mut().poll(&mut context) {
238            return result;
239        }
240    }
241}
242
243/// The wrapped pin is not compatible with this peripheral instance.
244///
245/// If `P` is `()`, it indicates that the caller's pin was incompatible with the
246/// peripheral, but the method did not take ownership of a pin.
247pub struct PinPortIncompatibleError<P>(P);
248impl<P> PinPortIncompatibleError<P> {
249    /// Acquire the pin from this error.
250    pub fn pin(self) -> P {
251        self.0
252    }
253}
254
255impl<P> core::fmt::Debug for PinPortIncompatibleError<P> {
256    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
257        f.write_str("PinPortIncompatibleError")
258    }
259}
260
261#[cfg(feature = "defmt")]
262impl<P> defmt::Format for PinPortIncompatibleError<P> {
263    fn format(&self, f: defmt::Formatter) {
264        defmt::write!(f, "PinPortIncompatibleError")
265    }
266}
267
268/// The peripheral instance for when we don't care.
269const HAL_INST: u8 = 0xff;
270
271/// Any peripheral instance acquired by
272/// our drivers, without the instance
273/// number.
274type AnyInstance<T> = imxrt_ral::Instance<T, HAL_INST>;
275
276/// Discard the instance number.
277fn into_any<T, const N: u8>(inst: imxrt_ral::Instance<T, N>) -> AnyInstance<T> {
278    // Safety: the user who made inst claims that it
279    // points to static MMIO. We're the new owner of
280    // that MMIO, and we choose to discard type info.
281    // We'll never reveal this instance back to the
282    // user.
283    unsafe {
284        let block: *const T = &*inst;
285        AnyInstance::new(block)
286    }
287}
288
289/// Returns `true` if these instances point to the same register block.
290#[allow(unused, reason = "Only needed in some chip-specific drivers")]
291fn is_same_instance<T>(left: &AnyInstance<T>, right: &AnyInstance<T>) -> bool {
292    let left: *const T = &**left;
293    let right: *const T = &**right;
294    core::ptr::eq(left, right)
295}