1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
//! A hardware abstraction layer (HAL) for i.MX RT MCUs.
//!
//! `imxrt-hal` contains a collection of hardware drivers for various i.MX RT
//! MCUs. A default build of `imxrt-hal` provides drivers that are portable
//! across all i.MX RT chips. When your specific chip is known, `imxrt-hal`
//! provides additional, chip-specific APIs. Most drivers implement their
//! corresponding `embedded-hal` traits, or they can be adapted to use
//! `embedded-hal` traits in user code.
//!
//! # Building
//!
//! `imxrt-hal` requires that you, or something in your dependency graph, enable
//! a chip-specific feature from `imxrt-ral`, the i.MX RT _register access layer
//! (RAL)_.  Without this, the HAL does not build. Since the HAL uses the RAL in
//! its public API, you're expected to depend on both packages.
//!
//! Here's an example of a project that builds the `imxrt-hal` for an i.MX RT
//! 1062 system.
//!
//! ```toml
//! [dependencies.imxrt-hal] # There's no required feature here...
//! version = # ...
//!
//! [dependencies.imxrt-ral]
//! version = # ...
//! features = ["imxrt1062"] # ...but this feature is required.
//! ```
//!
//! Once you've enabled a RAL feature, the HAL builds without any additional
//! features. All APIs exposed in this build are portable across all supported
//! i.MX RT chips.
//!
//! # Examples
//!
//! See each module's documentation for examples. Note that documentation
//! examples may assume a specific chip and chip family, so you may need to
//! adapt the example for your hardware.
//!
//! The `imxrt-hal` repository maintains examples that run on various i.MX RT
//! development boards. See the project documentation for more information.
//!
//! # Configuration
//!
//! Use these optional features to control the HAL build.
//!
//! | Feature           | Description                                                      |
//! |-------------------|------------------------------------------------------------------|
//! | `"imxrt1010"`     | Enable features for the 1010 chips.                              |
//! | `"imxrt1020"`     | Enable features for the 1020 chips.                              |
//! | `"imxrt1060"`     | Enable features for the 1060 chips.                              |
//! | `"imxrt1064"`     | Enable features for the 1064 chips.                              |
//! | `"imxrt1170"`     | Enable features for the 1170 chips.                              |
//! | `"eh02-unproven"` | Enable implementations for embedded-hal 0.2 `"unproven"` traits. |
//! | `"rand_core"`     | Allows the TRNG to be used with the `rand` package.              |
//!
//! The APIs exposed by the various `"imxrt[...]"` features are chip specific.
//! The HAL does not support building with more than one of these features at a
//! time.
//!
//! When enabling a HAL chip feature, make sure that it pairs properly with your
//! RAL chip selection. You are responsible for making sure that your RAL chip
//! feature is appropriate for the HAL chip feature. For instance, mixing the
//! RAL's `imxrt1062` feature with the HAL's `imxrt1010` feature is not
//! supported.
//!
//! ```toml
//! [dependencies.imxrt-hal]
//! version = # ...
//! #Bad: doesn't support RAL feature.
//! #features = ["imxrt1010"]
//!
//! #Good: supports RAL feature
//! features = ["imxrt1060"]
//!
//! [dependencies.imxrt-ral]
//! version = # ...
//! features = ["imxrt1062"] # Informs the HAL chip feature
//! ```
//!
//! The `"eh02-unproven"` feature will not build without the corresponding
//! `"unproven"` feature enabled in embedded-hal 0.2.

#![no_std]
#![warn(missing_docs)]

use imxrt_ral as ral;

mod chip;

/// Modules that need no HAL conditional compilation.
///
/// These modules only depend on a RAL feature.
mod common {
    pub use imxrt_dma as dma;

    pub mod ccm;
    pub mod flexpwm;
    pub mod gpio;
    pub mod gpt;
    pub mod lpi2c;
    pub mod lpspi;
    pub mod lpuart;
    pub mod pit;
    pub mod snvs;
    pub mod timer;
}

// These common drivers have no associated chip APIs, so
// export them directly.
pub use common::{flexpwm, gpio, gpt, lpi2c, lpspi, lpuart, pit, snvs, timer};

/// Clock control module.
///
/// Unlike other drivers in this package, this module only provides a
/// thin layer over the `imxrt-ral` APIs. It's fairly low level, but
/// more discoverable than the registers and reference manual.
///
/// # Overview
///
/// Use [`clock_gate`](crate::ccm::clock_gate) APIs to enable or disable the clock gates for
/// various peripherals. You'll need to enable clock gates before you
/// start using peripherals.
///
/// The remaining modules provide lower-level APIs for the CCM clock
/// tree. These APIs may not be portable across chip families.
///
/// # Visibility
///
/// If you see items in this module, it's because a chip family feature is
/// enabled in the HAL. These symbols may vary depending on the selected
/// feature.
pub mod ccm {
    pub use crate::chip::ccm::*;
}

/// Direct memory access.
///
/// Use the `dma` APIs to perform memory operations without processor intervention.
/// The API supports the following transfers:
///
/// - peripheral to memory
/// - memory to peripheral
/// - memory to memory
///
/// Peripheral support depends on the peripheral. See your peripheral's API for details.
/// Methods that use DMA are typically prefixed with `dma`.
///
/// DMA transfers are modeled as futures. The examples below demonstrate a simple way
/// to start a transfer. Since these are futures, you may use these futures in `async` code.
///
/// # DMA channels
///
/// The API provides access to at least 16 DMA channels. If you've enabled an optional chip
/// family feature, this number may change. See [`CHANNEL_COUNT`](crate::dma::CHANNEL_COUNT)
/// for more information.
///
/// # Visibility
///
/// Select items become visible when a chip family feature is enabled.
///
/// # Example
///
/// Use [`channels()`](crate::dma::channels) to access all DMA channels for your processor.
///
/// ```no_run
/// use imxrt_hal as hal;
/// use imxrt_ral as ral;
///
/// # fn doc() -> Option<()> {
/// let mut ccm = unsafe { ral::ccm::CCM::instance() };
/// hal::ccm::clock_gate::dma().set(&mut ccm, hal::ccm::clock_gate::ON);
///
/// let mut channels = hal::dma::channels(
///     unsafe { ral::dma::DMA::instance() },
///     unsafe { ral::dmamux::DMAMUX::instance() },
/// );
///
/// // Selecting the 13th DMA channel for our examples...
/// let mut channel = channels[13].take()?;
/// # Some(()) }
/// ```
///
/// Construct and poll a [`Memcpy`](crate::dma::memcpy::Memcpy) to
/// perform a memory-to-memory transfer.
///
/// ```no_run
/// # async fn a() -> Option<()> {
/// # use imxrt_hal as hal;
/// # use imxrt_ral as ral;
/// # let mut channel = unsafe { hal::dma::DMA.channel(13) };
/// let source = [4u32, 5, 6, 7];
/// let mut destination = [0u32; 4];
///
/// let memcpy = hal::dma::memcpy::memcpy(&source, &mut destination, &mut channel);
/// memcpy.await.ok()?;
/// # Some(()) }
/// ```
///
/// For examples of using DMA with a peripheral, see the peripheral's documentation.
pub mod dma {
    pub use crate::chip::dma::*;
    pub use crate::common::dma::*;
}

/// USB device.
///
/// This module re-exports types from the `imxrt-usbd` package. The driver is compatible
///  with the [`usb-device`](https://docs.rs/usb-device/latest/usb_device/) ecosystem.
///
/// It also provides [`Instances`](crate::usbd::Instances), an implementation of `imxrt_usbd::Peripherals` over
/// `imxrt-ral` USB instances.
///
/// # Example
///
/// Construct a [`BusAdapter`](crate::usbd::BusAdapter) with USB peripheral instances. See the
/// [`BusAdapter`](crate::usbd::BusAdapter) documentation for more information on how to use the bus.
///
/// ```no_run
/// use imxrt_hal as hal;
/// use imxrt_ral as ral;
///
/// use hal::usbd;
///
/// # || -> Option<()> {
/// let mut usb_analog = unsafe { ral::usb_analog::USB_ANALOG::instance() };
/// let usb_instances = usbd::Instances {
///     usb: unsafe { ral::usb::USB1::instance() },
///     usbnc: unsafe { ral::usbnc::USBNC1::instance() },
///     usbphy: unsafe { ral::usbphy::USBPHY1::instance() },
/// };
///
/// // Prepare the USB clocks.
/// let mut ccm_analog = unsafe { ral::ccm_analog::CCM_ANALOG::instance() };
/// hal::ccm::analog::pll3::restart(&mut ccm_analog);
///
/// static ENDPOINT_MEMORY: usbd::EndpointMemory<2048> = usbd::EndpointMemory::new();
/// static ENDPOINT_STATE: usbd::EndpointState = usbd::EndpointState::max_endpoints();
///
/// let usbd = usbd::BusAdapter::new(usb_instances, &ENDPOINT_MEMORY, &ENDPOINT_STATE);
/// # Some(()) }().unwrap();
/// ```
#[cfg(feature = "imxrt-usbd")]
pub mod usbd {
    pub use imxrt_usbd::*;

    use crate::ral;

    /// Aggregate of `imxrt-ral` USB peripheral instances.
    ///
    /// This takes ownership of USB peripheral instances and implements
    /// [`Peripherals`]. You can use this type to allocate a USB device
    /// driver. See the [module-level documentation](crate::usbd) for an
    /// example.
    pub struct Instances<const N: u8> {
        /// USB core registers.
        pub usb: ral::usb::Instance<N>,
        /// USB non-core registers.
        pub usbnc: ral::usbnc::Instance<N>,
        /// USBPHY registers.
        pub usbphy: ral::usbphy::Instance<N>,
    }

    unsafe impl<const N: u8> Peripherals for Instances<N> {
        fn usb(&self) -> *const () {
            (&*self.usb as *const ral::usb::RegisterBlock).cast()
        }
        fn usbphy(&self) -> *const () {
            (&*self.usbphy as *const ral::usbphy::RegisterBlock).cast()
        }
    }
}

/// Pad muxing and configurations.
///
/// This module re-exports select items from the `imxrt-iomuxc` crate. When a chip feature is enabled, the module also exports
/// chip-specific items, like `into_pads`. Use [`into_pads`](crate::iomuxc::into_pads) to transform the `imxrt-ral` instance(s)
/// into pad objects:
///
/// ```
/// use imxrt_hal as hal;
/// use imxrt_ral as ral;
///
/// let iomuxc = unsafe { ral::iomuxc::IOMUXC::instance() };
/// let pads = hal::iomuxc::into_pads(iomuxc);
/// ```
///
/// [`Pads`](crate::iomuxc::pads::Pads) exposes all pads as individual, owned objects. Use [`configure`](crate::iomuxc::configure)
/// to specify any pad configurations. Then use the pad object(s) to construct your driver.
pub mod iomuxc {
    pub use crate::chip::iomuxc::*;
    pub use imxrt_iomuxc::prelude::*;
}

pub use crate::chip::reexports::*;