embassy-mcxa

Crates

git

Versions

mcx-a256

Flavors

DmaChannel

Struct DmaChannel 

Source
pub struct DmaChannel<C: Channel> { /* private fields */ }
Expand description

Strongly-typed handle to a DMA0 channel.

The lifetime of this value is tied to the unique peripheral token supplied by embassy_hal_internal::peripherals!, so safe code cannot create two DmaChannel instances for the same hardware channel.

Implementations§

Source§

impl<C: Channel> DmaChannel<C>

Source

pub fn new(_ch: Peri<'_, C>) -> Self

Wrap a DMA channel token (takes ownership of the Peri wrapper).

Note: DMA is initialized during hal::init() via dma::init().

Source

pub const fn index(&self) -> usize

Channel index in the EDMA_0_TCD0 array.

Source

pub fn into_any(self) -> AnyChannel

Convert this typed channel into a type-erased AnyChannel.

Source

pub fn as_any(&self) -> AnyChannel

Get a reference to the type-erased channel info.

Source

pub fn tcd(&self) -> &'static Tcd

Return a reference to the underlying TCD register block.

This steals the eDMA pointer internally since MCXA276 has only one eDMA instance.

§Note

This is exposed for advanced use cases that need direct TCD access. For most use cases, prefer the higher-level transfer methods.

Source

pub unsafe fn start_transfer(&self) -> Transfer<'_>

Start an async transfer.

The channel must already be configured. This enables the channel request and returns a Transfer future that resolves when the DMA transfer completes.

§Safety

The caller must ensure the DMA channel has been properly configured and that source/destination buffers remain valid for the duration of the transfer.

Source

pub fn mem_to_mem<W: Word>( &self, src: &[W], dst: &mut [W], options: TransferOptions, ) -> Result<Transfer<'_>, Error>

Perform a memory-to-memory DMA transfer (simplified API).

This is a type-safe wrapper that uses the Word trait to determine the correct transfer width automatically. Uses the global eDMA TCD register accessor internally.

§Arguments
  • src - Source buffer
  • dst - Destination buffer (must be at least as large as src)
  • options - Transfer configuration options
§Safety

The source and destination buffers must remain valid for the duration of the transfer.

Source

pub fn memset<W: Word>( &self, pattern: &W, dst: &mut [W], options: TransferOptions, ) -> Transfer<'_>

Fill a memory buffer with a pattern value (memset).

This performs a DMA transfer where the source address remains fixed (pattern value) while the destination address increments through the buffer. It’s useful for quickly filling large memory regions with a constant value.

§Arguments
  • pattern - Reference to the pattern value (will be read repeatedly)
  • dst - Destination buffer to fill
  • options - Transfer configuration options
§Example
use embassy_mcxa::dma::{DmaChannel, TransferOptions};

let dma_ch = DmaChannel::new(p.DMA_CH0);
let pattern: u32 = 0xDEADBEEF;
let mut buffer = [0u32; 256];

unsafe {
    dma_ch.memset(&pattern, &mut buffer, TransferOptions::default()).await;
}
// buffer is now filled with 0xDEADBEEF
Source

pub unsafe fn write<W: Word>( &self, buf: &[W], peri_addr: *mut W, options: TransferOptions, ) -> Transfer<'_>

Write data from memory to a peripheral register.

The destination address remains fixed (peripheral register) while the source address increments through the buffer.

§Arguments
  • buf - Source buffer to write from
  • peri_addr - Peripheral register address
  • options - Transfer configuration options
§Safety
  • The buffer must remain valid for the duration of the transfer.
  • The peripheral address must be valid for writes.
Source

pub unsafe fn setup_write<W: Word>( &self, buf: &[W], peri_addr: *mut W, enable_interrupt: EnableInterrupt, )

Configure a memory-to-peripheral DMA transfer without starting it.

This is a convenience wrapper around setup_write_to_peripheral() that uses the default eDMA TCD register block.

This method configures the TCD but does NOT return a Transfer. The caller is responsible for the complete DMA lifecycle:

  1. Call enable_request() to start the transfer
  2. Poll is_done() or use interrupts to detect completion
  3. Call disable_request(), clear_done(), clear_interrupt() for cleanup
§Example
let data = [0x48, 0x65, 0x6c, 0x6c, 0x6f]; // "Hello"

unsafe {
    // Configure the transfer
    dma_ch.setup_write(&data, uart_tx_addr, EnableInterrupt::Yes);

    // Start when peripheral is ready
    dma_ch.enable_request();

    // Wait for completion (or use interrupt)
    while !dma_ch.is_done() {}

    // Clean up
    dma_ch.clear_done();
    dma_ch.clear_interrupt();
}
§Arguments
  • buf - Source buffer to write from
  • peri_addr - Peripheral register address
  • enable_interrupt - Whether to enable interrupt on completion
§Safety
  • The buffer must remain valid for the duration of the transfer.
  • The peripheral address must be valid for writes.
Source

pub unsafe fn write_to_peripheral<W: Word>( &self, buf: &[W], peri_addr: *mut W, options: TransferOptions, ) -> Transfer<'_>

Write data from memory to a peripheral register.

The destination address remains fixed (peripheral register) while the source address increments through the buffer.

§Arguments
  • buf - Source buffer to write from
  • peri_addr - Peripheral register address
  • options - Transfer configuration options
§Safety
  • The buffer must remain valid for the duration of the transfer.
  • The peripheral address must be valid for writes.
Source

pub unsafe fn read<W: Word>( &self, peri_addr: *const W, buf: &mut [W], options: TransferOptions, ) -> Transfer<'_>

Read data from a peripheral register to memory.

The source address remains fixed (peripheral register) while the destination address increments through the buffer.

§Arguments
  • peri_addr - Peripheral register address
  • buf - Destination buffer to read into
  • options - Transfer configuration options
§Safety
  • The buffer must remain valid for the duration of the transfer.
  • The peripheral address must be valid for reads.
Source

pub unsafe fn setup_read<W: Word>( &self, peri_addr: *const W, buf: &mut [W], enable_interrupt: EnableInterrupt, )

Configure a peripheral-to-memory DMA transfer without starting it.

This is a convenience wrapper around setup_read_from_peripheral() that uses the default eDMA TCD register block.

This method configures the TCD but does NOT return a Transfer. The caller is responsible for the complete DMA lifecycle:

  1. Call enable_request() to start the transfer
  2. Poll is_done() or use interrupts to detect completion
  3. Call disable_request(), clear_done(), clear_interrupt() for cleanup
§Example
let mut buf = [0u8; 32];

unsafe {
    // Configure the transfer
    dma_ch.setup_read(uart_rx_addr, &mut buf, EnableInterrupt::Yes);

    // Start when peripheral is ready
    dma_ch.enable_request();

    // Wait for completion (or use interrupt)
    while !dma_ch.is_done() {}

    // Clean up
    dma_ch.clear_done();
    dma_ch.clear_interrupt();
}
// buf now contains received data
§Arguments
  • peri_addr - Peripheral register address
  • buf - Destination buffer to read into
  • enable_interrupt - Whether to enable interrupt on completion
§Safety
  • The buffer must remain valid for the duration of the transfer.
  • The peripheral address must be valid for reads.
Source

pub unsafe fn read_from_peripheral<W: Word>( &self, peri_addr: *const W, buf: &mut [W], options: TransferOptions, ) -> Transfer<'_>

Read data from a peripheral register to memory.

The source address remains fixed (peripheral register) while the destination address increments through the buffer.

§Arguments
  • peri_addr - Peripheral register address
  • buf - Destination buffer to read into
  • options - Transfer configuration options
§Safety
  • The buffer must remain valid for the duration of the transfer.
  • The peripheral address must be valid for reads.
Source

pub unsafe fn setup_write_to_peripheral<W: Word>( &self, buf: &[W], peri_addr: *mut W, enable_interrupt: EnableInterrupt, )

Configure a memory-to-peripheral DMA transfer without starting it.

This configures the TCD for a memory-to-peripheral transfer but does NOT return a Transfer object. The caller is responsible for:

  1. Enabling the peripheral’s DMA request
  2. Calling enable_request() to start the transfer
  3. Polling is_done() or using interrupts to detect completion
  4. Calling disable_request(), clear_done(), clear_interrupt() for cleanup

Use this when you need manual control over the DMA lifecycle (e.g., in peripheral drivers that have their own completion polling).

§Arguments
  • buf - Source buffer to write from
  • peri_addr - Peripheral register address
  • enable_interrupt - Whether to enable interrupt on completion
§Safety
  • The buffer must remain valid for the duration of the transfer.
  • The peripheral address must be valid for writes.
Source

pub unsafe fn setup_read_from_peripheral<W: Word>( &self, peri_addr: *const W, buf: &mut [W], enable_interrupt: EnableInterrupt, )

Configure a peripheral-to-memory DMA transfer without starting it.

This configures the TCD for a peripheral-to-memory transfer but does NOT return a Transfer object. The caller is responsible for:

  1. Enabling the peripheral’s DMA request
  2. Calling enable_request() to start the transfer
  3. Polling is_done() or using interrupts to detect completion
  4. Calling disable_request(), clear_done(), clear_interrupt() for cleanup

Use this when you need manual control over the DMA lifecycle (e.g., in peripheral drivers that have their own completion polling).

§Arguments
  • peri_addr - Peripheral register address
  • buf - Destination buffer to read into
  • enable_interrupt - Whether to enable interrupt on completion
§Safety
  • The buffer must remain valid for the duration of the transfer.
  • The peripheral address must be valid for reads.
Source

pub unsafe fn set_request_source<R: DmaRequest>(&self)

Configure the integrated channel MUX to use the given typed DMA request source (e.g., Lpuart2TxRequest or Lpuart2RxRequest).

This is the type-safe version that uses marker types to ensure compile-time verification of request source validity.

§Safety

The channel must be properly configured before enabling requests. The caller must ensure the DMA request source matches the peripheral that will drive this channel.

§Note

The NXP SDK requires a two-step write sequence: first clear the mux to 0, then set the actual source. This is a hardware requirement on eDMA4 for the mux to properly latch.

§Example
use embassy_mcxa::dma::{DmaChannel, Lpuart2RxRequest};

// Type-safe: compiler verifies this is a valid DMA request type
unsafe {
    channel.set_request_source::<Lpuart2RxRequest>();
}
Source

pub unsafe fn enable_request(&self)

Enable hardware requests for this channel (ERQ=1).

§Safety

The channel must be properly configured before enabling requests.

Source

pub unsafe fn disable_request(&self)

Disable hardware requests for this channel (ERQ=0).

§Safety

Disabling requests on an active transfer may leave the transfer incomplete.

Source

pub fn is_done(&self) -> bool

Return true if the channel’s DONE flag is set.

Source

pub unsafe fn clear_done(&self)

Clear the DONE flag for this channel.

Uses modify to preserve other bits (especially ERQ) unlike write which would clear ERQ and halt an active transfer.

§Safety

Clearing DONE while a transfer is in progress may cause undefined behavior.

Source

pub unsafe fn clear_interrupt(&self)

Clear the channel interrupt flag (CH_INT.INT).

§Safety

Must be called from the correct interrupt context or with interrupts disabled.

Source

pub unsafe fn trigger_start(&self)

Trigger a software start for this channel.

§Safety

The channel must be properly configured with a valid TCD before triggering.

Source

pub fn waker(&self) -> &'static AtomicWaker

Get the waker for this channel

Source

pub fn enable_interrupt(&self)

Enable the interrupt for this channel in the NVIC.

Enable Major Loop Linking.

When the major loop completes, the hardware will trigger a service request on link_ch.

§Arguments
  • link_ch - Target channel index (0-7) to link to
§Safety

The channel must be properly configured before setting up linking.

Disable Major Loop Linking.

Removes any major loop channel linking previously configured.

§Safety

The caller must ensure this doesn’t disrupt an active transfer that depends on the linking.

Enable Minor Loop Linking.

After each minor loop, the hardware will trigger a service request on link_ch.

§Arguments
  • link_ch - Target channel index (0-7) to link to
§Note

This rewrites CITER and BITER registers to the ELINKYES format. It preserves the current loop count.

§Safety

The channel must be properly configured before setting up linking.

Disable Minor Loop Linking.

Removes any minor loop channel linking previously configured. This rewrites CITER and BITER registers to the ELINKNO format, preserving the current loop count.

§Safety

The caller must ensure this doesn’t disrupt an active transfer that depends on the linking.

Source

pub unsafe fn load_tcd(&self, tcd: &Tcd)

Load a TCD from memory into the hardware channel registers.

This is useful for scatter/gather and ping-pong transfers where TCDs are prepared in RAM and then loaded into the hardware.

§Safety
  • The TCD must be properly initialized.
  • The caller must ensure no concurrent access to the same channel.
Source§

impl<C: Channel> DmaChannel<C>

Source

pub unsafe fn setup_circular_read<'a, W: Word>( &self, peri_addr: *const W, buf: &'a mut [W], ) -> RingBuffer<'a, W>

Set up a circular DMA transfer for continuous peripheral-to-memory reception.

This configures the DMA channel for circular operation with both half-transfer and complete-transfer interrupts enabled. The transfer runs continuously until stopped via RingBuffer::stop().

§Arguments
  • peri_addr - Peripheral register address to read from
  • buf - Destination buffer (should be power-of-2 size for best efficiency)
§Returns

A RingBuffer that can be used to read received data.

§Safety
  • The buffer must remain valid for the lifetime of the returned RingBuffer.
  • The peripheral address must be valid for reads.
  • The peripheral’s DMA request must be configured to trigger this channel.

Auto Trait Implementations§

§

impl<C> Freeze for DmaChannel<C>

§

impl<C> RefUnwindSafe for DmaChannel<C>
where C: RefUnwindSafe,

§

impl<C> Send for DmaChannel<C>
where C: Send,

§

impl<C> Sync for DmaChannel<C>
where C: Sync,

§

impl<C> Unpin for DmaChannel<C>
where C: Unpin,

§

impl<C> UnwindSafe for DmaChannel<C>
where C: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.