Skip to content

Commit 6720d2f

Browse files
committed
Update API documentation
Add a small getting started to the package docs that describe how to allocate a DMA driver. Link to the higher-level APIs, and add examples to those APIs. Simplify the README to refer to the API docs.
1 parent e2395d2 commit 6720d2f

5 files changed

Lines changed: 234 additions & 51 deletions

File tree

README.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
imxrt-dma
22
=========
33

4-
DMA driver for i.MX RT microcontrollers
4+
DMA driver for i.MX RT microcontrollers.
55

66
**[API Docs (main branch)][main-api-docs]**
77

88
[main-api-docs]: https://imxrt-rs.github.io/imxrt-dma/
99

10-
`imxrt-dma` provides
11-
12-
- an unsafe API for defining and scheduling transfers with DMA `Channel`s
13-
and `Transfer`s
14-
- safe DMA futures for memcpy, peripheral-to-memory, and memory-to-peripheral
15-
transfers
16-
1710
See the API docs for more information. To try examples on hardware, see the
1811
examples directory.
1912

src/interrupt.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ impl<const CHANNELS: usize> super::Dma<CHANNELS> {
1616
/// Handle a DMA interrupt
1717
///
1818
/// Checks the interrupt status for the channel identified by `channel`.
19-
/// If the channel completed its transfer, or it's in an error state,
20-
/// `on_interrupt` wakes the channel's waker.
19+
/// If the channel completed its transfer, `on_interrupt` wakes the channel's
20+
/// waker.
2121
///
2222
/// Consider calling `on_interrupt` in a DMA channel's interrupt handler:
2323
///
@@ -39,9 +39,9 @@ impl<const CHANNELS: usize> super::Dma<CHANNELS> {
3939
///
4040
/// # Safety
4141
///
42-
/// Caller must ensure that `on_interrupt` is called in the correct interrupt
43-
/// handler. Caller must ensure that `channel` is valid for the given system,
44-
/// and for the interrupt handler.
42+
/// This should only be used when the associated DMA channel is exclusively referenced
43+
/// by a DMA transfer future. Caller must ensure that `on_interrupt` is called in
44+
/// the correct interrupt handler.
4545
///
4646
/// # Panics
4747
///
@@ -102,14 +102,13 @@ pub(crate) const NO_WAKER: SharedWaker = Mutex::new(RefCell::new(None));
102102
/// use imxrt_dma::{channel::Channel, Transfer};
103103
///
104104
/// # static DMA: imxrt_dma::Dma<32> = unsafe { imxrt_dma::Dma::new(core::ptr::null(), core::ptr::null()) };
105+
/// # async fn f() -> imxrt_dma::Result<()> {
105106
/// let my_channel: Channel = // Acquire your channel...
106107
/// # unsafe { DMA.channel(0) };
107108
/// // Properly prepare your transfer...
108109
/// // Safety: transfer properly prepared
109-
/// let my_transfer = unsafe { Transfer::new(&my_channel) };
110-
/// // Execute your transfer with a blocking executor...
111-
/// # mod executor { pub fn block<F: core::future::Future>(_: F) {} }
112-
/// executor::block(my_transfer);
110+
/// unsafe { Transfer::new(&my_channel) }.await?;
111+
/// # Ok(()) }
113112
/// ```
114113
pub struct Transfer<'a> {
115114
channel: &'a Channel,

src/lib.rs

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,56 @@
1-
//! Direct Memory Access (DMA) driver for i.MX RT processors
1+
//! Direct Memory Access (DMA) driver for i.MX RT processors.
22
//!
33
//! `imxrt-dma` provides
44
//!
5-
//! - an unsafe API for defining and scheduling transfers with DMA `Channel`s
6-
//! and `Transfer`s
5+
//! - an unsafe API for defining and scheduling transfers with DMA `Channel`s.
76
//! - safe DMA futures for memcpy, peripheral-to-memory, and memory-to-peripheral
8-
//! transfers
7+
//! transfers.
98
//!
10-
//! This DMA driver may be re-exported from a HAL. If it is, you should consider
11-
//! using the safer APIs provided by your HAL.
9+
//! This DMA driver may be re-exported from a hardware abstraction layer
10+
//! (HAL). If it is, you should use the safer APIs provided by your HAL.
1211
//!
13-
//! # Portability
12+
//! # Getting started
1413
//!
15-
//! This DMA driver works across all considered i.MX RT variants (1010 and 1060
16-
//! family). You must make sure that the DMA channel you're creating is valid for
17-
//! your i.MX RT processor. This only matters on i.MX RT 1010 processors, which
18-
//! only support 16 DMA channels. Creating an invalid channel for your 1010 processor
19-
//! will result in a channel that references reserved memory.
14+
//! To allocate a [`Dma`](crate::Dma) driver, you'll need to know
15+
//!
16+
//! 1. the location of the DMA controller registers.
17+
//! 2. the location of the DMAMUX registers.
18+
//! 3. the number of DMA channels supported by your chip.
19+
//!
20+
//! These parameters depend on the i.MX RT chip you're targeting. If you're
21+
//! already using [`imxrt-ral`](https://docs.rs/imxrt-ral), consider using the
22+
//! `DMA` and `DMAMUX` constants for the addresses. You're always responsible
23+
//! for configuring the number of DMA channels.
24+
//!
25+
//! With those three parameters, assign a `Dma` to a static. Then, use that
26+
//! object to create DMA [`Channel`](crate::channel::Channel)s.
27+
//!
28+
//! ```
29+
//! use imxrt_dma::Dma;
30+
//! # const DMA_PTR: *const () = core::ptr::null() as _;
31+
//! # const DMAMUX_PTR: *const () = core::ptr::null() as _;
32+
//!
33+
//! // Safety: addresses and channel count are valid for this target.
34+
//! static DMA: Dma<32> = unsafe { Dma::new(DMA_PTR, DMAMUX_PTR) };
35+
//!
36+
//! // Safety: we only allocate one DMA channel 7 object.
37+
//! let mut channel = unsafe { DMA.channel(7) };
38+
//! ```
39+
//!
40+
//! Once you have a channel, you can use the higher-level DMA APIs, like
41+
//!
42+
//! - [`memcpy`](crate::memcpy::memcpy) for memory copies.
43+
//! - [`transfer`](crate::peripheral::transfer) to transmit data from memory to
44+
//! a peripheral.
45+
//! - [`receive`](crate::peripheral::receive) to receive data from a peripheral.
46+
//! - [`full_duplex`](crate::peripheral::full_duplex) to read / write with a
47+
//! peripheral using a single buffer.
48+
//!
49+
//! Peripheral transfers depends on a peripheral's DMA support. These are signaled
50+
//! through various [`peripheral`](crate::peripheral) traits.
51+
//!
52+
//! For a lower-level API, use the [`channel`](crate::channel) objects and helper
53+
//! functions.
2054
//!
2155
//! ### License
2256
//!
@@ -49,7 +83,7 @@ pub use ral::tcd::BandwidthControl;
4983
/// A DMA result
5084
pub type Result<T> = core::result::Result<T, Error>;
5185

52-
/// A DMA peripheral.
86+
/// A DMA driver.
5387
///
5488
/// This DMA driver manages the DMA controller and the multiplexer.
5589
/// It's configured with pointers to both peripherals.
@@ -68,22 +102,23 @@ unsafe impl<const CHANNELS: usize> Sync for Dma<CHANNELS> {}
68102
impl<const CHANNELS: usize> Dma<CHANNELS> {
69103
/// Create the DMA driver.
70104
///
71-
/// Note that this can evaluate at compile time. Consider using this to expose
72-
/// a `DMA` constant through your higher-level API that you can use to allocate
73-
/// DMA channels.
105+
/// Note that this can evaluate at compile time. Consider using this to
106+
/// expose a `Dma` through your higher-level API that you can use to
107+
/// allocate DMA channels.
74108
///
75-
/// `max_channels` specifies the total number of channels supported by the DMA
109+
/// `CHANNELS` specifies the total number of channels supported by the DMA
76110
/// controller. It's referenced when allocating channels.
77111
///
78112
/// # Safety
79113
///
80-
/// Caller must make sure that `controller` is a pointer to the start of the DMA
81-
/// controller register block. Caller must also make sure that `multiplexer` is
82-
/// a pointer to the start of the DMA multiplexer. Both pointers must be valid
83-
/// for your MCU.
114+
/// Caller must make sure that `controller` is a pointer to the start of the
115+
/// DMA controller register block. Caller must also make sure that
116+
/// `multiplexer` is a pointer to the start of the DMA multiplexer. Both
117+
/// pointers must be valid for your MCU.
84118
///
85-
/// An incorrect `max_channels` value prevents proper bounds checking when allocating
86-
/// channels. This may result in DMA channels that point to invalid memory.
119+
/// An incorrect `CHANNELS` value prevents proper bounds checking when
120+
/// allocating channels. This may result in DMA channels that point to
121+
/// invalid memory.
87122
pub const unsafe fn new(controller: *const (), multiplexer: *const ()) -> Self {
88123
Self {
89124
controller: ral::Static(controller.cast()),

src/memcpy.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,14 @@ pub struct Memcpy<'a, E> {
3636
/// ```no_run
3737
/// use imxrt_dma::{channel::Channel, memcpy};
3838
///
39-
/// static DMA: imxrt_dma::Dma<32> = unsafe { imxrt_dma::Dma::new(core::ptr::null(), core::ptr::null()) };
39+
/// # static DMA: imxrt_dma::Dma<32> = unsafe { imxrt_dma::Dma::new(core::ptr::null(), core::ptr::null()) };
4040
/// // #[cortex_m_rt::interrupt]
4141
/// fn DMA7() {
42-
/// // Safety: DMA channel 7 valid
42+
/// // Safety: DMA channel 7 valid and used by a future.
4343
/// unsafe { DMA.on_interrupt(7) };
4444
/// }
4545
///
46+
/// # async fn f() -> imxrt_dma::Result<()> {
4647
/// let mut channel_7: Channel = // DMA channel 7
4748
/// # unsafe { DMA.channel(7) };
4849
/// channel_7.set_interrupt_on_completion(true);
@@ -51,9 +52,8 @@ pub struct Memcpy<'a, E> {
5152
/// let source = [4u32, 5, 6, 7, 8];
5253
/// let mut destination = [0; 5];
5354
///
54-
/// let transfer = memcpy::memcpy(&source, &mut destination, &mut channel_7);
55-
/// # mod executor { pub fn wfi(_: impl core::future::Future) {} }
56-
/// executor::wfi(transfer);
55+
/// memcpy::memcpy(&source, &mut destination, &mut channel_7).await?;
56+
/// # Ok(()) }
5757
/// ```
5858
pub fn memcpy<'a, E: Element>(
5959
source: &'a [E],

0 commit comments

Comments
 (0)