DMA Channel Driver#

High-level API to perform DMA transfers on a single channel.

Overview#

The DMA Channel Driver builds on top of the dma_manager service. It assumes a DMA channel has already been allocated (or reserved) at the manager layer and focuses on per-channel operations: transfer submission, queuing and linking, status query, and callback notification.

Together, the DMA Manager and the DMA Channel Driver replace the legacy DMADRV - DMA Driver component. See the DMADRV Migration Guide for the full API mapping table when porting existing code.

Core responsibilities:

  • Provide simple memory-to-memory (M2M), memory-to-peripheral (M2P) and peripheral-to-memory (P2M) submission APIs.

  • Maintain a software queue (singly-linked list) mirroring the hardware descriptor link chain so that completions can be processed in batch when interrupts are delayed or masked.

  • Invoke a user callback once per descriptor (or per aborted descriptor when an error occurs) with explicit error / abort flags.

  • Automatically select an optimal transfer unit size (byte/half/word) based on alignment and length for M2M transfers, and automatically segment transfers larger than the hardware descriptor capacity.

Integration steps#

To integrate the DMA Channel Driver in an application:

  1. Add the components. Include the dma_channel and dma_manager SLC components in your .slcp. The DMA Manager is auto-initialized by SL Main; no manual init() call is required.

  2. Allocate (or reserve) a channel. Use sl_dma_manager_allocate_channel() (any channel) or sl_dma_manager_reserve_channel() (a specific channel number) from the DMA Manager.

  3. Declare and initialize a channel handle. Each active channel needs one application-owned sl_dma_channel_handle_t. Call sl_dma_channel_init() with the channel number, the peripheral instance (or NULL for the default), the completion callback and a user-data pointer.

  4. Set the peripheral signal if required. Memory-to-peripheral and peripheral-to-memory transfers use block-handshake mode by default and need a request line from the peripheral. Call sl_dma_channel_set_peripheral_signal() with the appropriate SL_DMA_SIGNAL_* constant before submitting M2P/P2M traffic. Memory-to-memory transfers do not need this step.

  5. Submit transfers. Pick the helper that matches your transfer pattern (see "Transfer modes" below). Pass NULL as the descriptor argument to let the driver allocate one, or pre-allocate via sl_dma_channel_descriptor_alloc() for deterministic memory use.

  6. Handle completions. The callback registered at init time is invoked once per descriptor that requested a callback, with explicit error / aborted flags. Application code may also poll progress via sl_dma_channel_get_status().

  7. Tear down. When done, call sl_dma_channel_abort() if a transfer is still active, then sl_dma_channel_deinit() to release the channel handle and sl_dma_manager_free_channel() to return the channel to the manager.

Transfer modes#

Helper

Pattern

Loops?

Peripheral signal required

sl_dma_channel_submit_transfer_m2m()

Memory-to-memory

No

No

sl_dma_channel_submit_transfer_m2p()

Memory-to-peripheral

No

Yes

sl_dma_channel_submit_transfer_p2m()

Peripheral-to-memory

No

Yes

sl_dma_channel_submit_transfer_list()

Linked list of heterogeneous transfers

No

When list contains M2P/P2M

sl_dma_channel_submit_ping_pong_transfer_m2p()

Two-buffer streaming M2P

Yes

Yes

sl_dma_channel_submit_ping_pong_transfer_p2m()

Two-buffer streaming P2M

Yes

Yes

sl_dma_channel_submit_triple_buffered_transfer_m2p()

Three-buffer streaming M2P

Yes

Yes

sl_dma_channel_submit_triple_buffered_transfer_p2m()

Three-buffer streaming P2M

Yes

Yes

sl_dma_channel_update_active_transfer()

Resize the currently-running head transfer

-

-

Peripheral signals and block-handshake mode#

Peripheral-attached transfers (M2P, P2M, and their ping-pong / triple-buffered variants) advance one block at a time on a request line asserted by the peripheral — this is what the API and the underlying hardware call block-handshake mode (see the block_handshake_mode field of sl_dma_channel_transfer_t). The peripheral signal selected via sl_dma_channel_set_peripheral_signal() identifies that request line. Without a signal set, an M2P or P2M transfer would have no hardware event to gate on. M2M transfers use full-cycle mode and ignore the peripheral signal.

Callback contract#

The completion callback installed by sl_dma_channel_init() is invoked from DMA channel IRQ context. It receives the channel handle, the user-data pointer, and two booleans:

  • error — set when the hardware reported a channel error. The channel is automatically disabled and the remaining queued descriptors are aborted.

  • aborted — set when sl_dma_channel_abort() was used to terminate the descriptor (or when the descriptor was aborted as a side-effect of an error).

Both false means a normal completion. In looping modes (ping-pong / triple-buffered) the callback is invoked on every buffer completion until the channel is aborted by the application. The callback return type is void — there is no way to stop a looping transfer from the callback by returning a value; call sl_dma_channel_abort() instead.

Error handling#

If the hardware sets the CHERROR bit for a channel, the driver disables the channel, aborts all queued descriptors and invokes the registered callback for each pending descriptor with error=true and aborted=true. The application is responsible for re-enabling or reinitializing the channel before submitting new work.

Performance#

On devices with external FLASH, the component "RAM Code for DMA Channel Performance" (ram_code_select_dma_channel_performance) can be added to move the DMA channel ISR into RAM to improve interrupt latency at the cost of higher RAM consumption.

Typical usage#

The example below shows a memory-to-memory transfer (app_dma_m2m, no peripheral signal needed) and a memory-to-peripheral transfer (app_dma_tx, which calls sl_dma_channel_set_peripheral_signal() first because m2p uses block-handshake mode).

static sl_dma_channel_handle_t dma_handle;

static void dma_cb(sl_dma_channel_handle_t *handle,
                   void                    *user_data,
                   bool                     error,
                   bool                     aborted)
{
  (void)handle;
  (void)user_data;
  if (!error && !aborted) {
    do_application_work();
  }
}

void app_dma_init(void)
{
  uint8_t ch;
  sl_dma_manager_allocate_channel(NULL, &ch);
  sl_dma_channel_init(&dma_handle, NULL, ch, dma_cb, NULL);
}

void app_dma_m2m(void *src, void *dst, size_t len)
{
  sl_dma_channel_submit_transfer_m2m(&dma_handle, src, dst, len, NULL);
}

void app_dma_tx(const uint8_t *data, size_t len)
{
  sl_dma_channel_set_peripheral_signal(&dma_handle,
                                       SL_DMA_SIGNAL_EUSART0_TXFL);
  sl_dma_channel_submit_transfer_m2p(&dma_handle,
                                     (void *)data,
                                     (void *)&EUSART0->TXDATA,
                                     len,
                                     SL_DMA_CTRL_SIZE_BYTE,
                                     NULL);
}

Modules#

sl_dma_channel_xfer_descriptor_flags_t

sl_dma_channel_handle

sl_dma_channel_transfer_t

sl_dma_channel_status_t

Enumerations#

enum
SL_DMA_CHANNEL_STATE_DISABLED
SL_DMA_CHANNEL_STATE_ENABLED
SL_DMA_CHANNEL_STATE_ABORTING
}

DMA channel state.

enum
SL_DMA_CHANNEL_MODE_NORMAL
SL_DMA_CHANNEL_MODE_LOOPING
}

DMA channel operating mode.

Typedefs#

typedef void(*
sl_dma_channel_callback_t)(sl_dma_channel_handle_t *handle, void *user_data, bool error, bool aborted)

Typedef for the user supplied callback function which is called on a transfer complete event.

Functions#

sl_status_t
sl_dma_channel_abort(sl_dma_channel_handle_t *handle)

Aborts all pending transfers on a given DMA channel.

sl_status_t
sl_dma_channel_suspend(const sl_dma_channel_handle_t *handle)

Suspends peripheral requests for a given DMA channel.

sl_status_t
sl_dma_channel_resume(const sl_dma_channel_handle_t *handle)

Resumes peripheral requests for a previously suspended DMA channel.

sl_status_t
sl_dma_channel_get_status(sl_dma_channel_handle_t *handle, sl_dma_channel_status_t *status)

Gets the status of the given DMA channel.

sl_status_t
sl_dma_channel_handle_alloc(sl_dma_channel_handle_t **handle)

Allocate a DMA channel handle structure from the heap.

sl_status_t
sl_dma_channel_handle_free(sl_dma_channel_handle_t *handle)

Free a DMA channel handle previously allocated by sl_dma_channel_handle_alloc().

size_t

Get the size in bytes of the channel handle structure.

sl_status_t
sl_dma_channel_descriptor_alloc(const sl_dma_channel_handle_t *handle, sl_dma_channel_xfer_descriptor_t **descriptor)

Allocate a DMA channel transfer descriptor from the heap.

sl_status_t
sl_dma_channel_descriptor_free(const sl_dma_channel_handle_t *handle, sl_dma_channel_xfer_descriptor_t *descriptor)

Free a DMA channel transfer descriptor previously allocated by sl_dma_channel_descriptor_alloc().

size_t

Get the size in bytes of the channel transfer descriptor structure.

sl_status_t
sl_dma_channel_init(sl_dma_channel_handle_t *handle, sl_peripheral_t peripheral, uint8_t channel_number, sl_dma_channel_callback_t callback, void *user_data)

Initialize an allocated channel handle with peripheral instance, channel index and user completion callback.

sl_status_t
sl_dma_channel_deinit(sl_dma_channel_handle_t *handle)

Deinitialize a DMA channel handle.

sl_status_t
sl_dma_channel_set_peripheral_signal(const sl_dma_channel_handle_t *handle, sl_dma_signal_t signal)

Set the peripheral signal routed to a DMA channel.

sl_status_t
sl_dma_channel_submit_transfer_m2m(sl_dma_channel_handle_t *handle, void *source, void *destination, size_t size, sl_dma_channel_xfer_descriptor_t *descriptor)

Submit a memory-to-memory transfer on a channel.

sl_status_t
sl_dma_channel_submit_transfer_m2p(sl_dma_channel_handle_t *handle, void *source, void *reg, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t *descriptor)

Submit a memory-to-peripheral transfer on a channel.

sl_status_t
sl_dma_channel_submit_transfer_p2m(sl_dma_channel_handle_t *handle, void *reg, void *destination, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t *descriptor)

Submit a peripheral-to-memory transfer on a channel.

sl_status_t
sl_dma_channel_submit_transfer_list(sl_dma_channel_handle_t *handle, sl_dma_channel_transfer_t *list_head)

Submits a list of transfers to the specified DMA channel.

sl_status_t
sl_dma_channel_submit_ping_pong_transfer_m2p(sl_dma_channel_handle_t *handle, void *source, void *source_2, void *destination, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t *descriptor)

Submits a memory to peripheral ping pong transfer on given DMA channel.

sl_status_t
sl_dma_channel_submit_ping_pong_transfer_p2m(sl_dma_channel_handle_t *handle, void *source, void *destination, void *destination_2, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t *descriptors)

Submits a peripheral to memory ping pong transfer on given DMA channel.

sl_status_t
sl_dma_channel_submit_triple_buffered_transfer_m2p(sl_dma_channel_handle_t *handle, void *source, void *source_2, void *source_3, void *destination, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t *descriptors)

Submits a memory to peripheral triple buffered transfer on given DMA channel.

sl_status_t
sl_dma_channel_submit_triple_buffered_transfer_p2m(sl_dma_channel_handle_t *handle, void *source, void *destination, void *destination_2, void *destination_3, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t *descriptor)

Submits a peripheral to memory triple buffered transfer on given DMA channel.

sl_status_t
sl_dma_channel_update_active_transfer(sl_dma_channel_handle_t *handle, size_t new_size)

Updates size of the current transfer.

Enumeration Documentation#

sl_dma_channel_state_t#

sl_dma_channel_state_t

DMA channel state.

Enumerator
SL_DMA_CHANNEL_STATE_DISABLED
SL_DMA_CHANNEL_STATE_ENABLED
SL_DMA_CHANNEL_STATE_ABORTING

sl_dma_channel_mode_t#

sl_dma_channel_mode_t

DMA channel operating mode.

Enumerator
SL_DMA_CHANNEL_MODE_NORMAL

Normal mode: single or linked transfers with callbacks.

SL_DMA_CHANNEL_MODE_LOOPING

Looping mode: circular descriptor chain (ping-pong/triple-buffered)


Typedef Documentation#

sl_dma_channel_callback_t#

typedef void(* sl_dma_channel_callback_t) (sl_dma_channel_handle_t *handle, void *user_data, bool error, bool aborted) )(sl_dma_channel_handle_t *handle, void *user_data, bool error, bool aborted)

Typedef for the user supplied callback function which is called on a transfer complete event.

Parameters
TypeDirectionArgument NameDescription
N/Ahandle

Handle to DMA channel.

N/Auser_data

Pointer to user data that is passed to the tx complete handler function.

N/Aerror

Flag that indicates if an error occurred during transfer.

N/Aaborted

Flag that indicates if the transfer was aborted.

Note

  • In case of error, the channel will be disabled and all submitted transfers will be aborted. It is the responsibility of the user to re-enable the channel and re-submit transfers.


Function Documentation#

sl_dma_channel_abort#

sl_status_t sl_dma_channel_abort (sl_dma_channel_handle_t * handle)

Aborts all pending transfers on a given DMA channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

DMA channel handle.

This function may be called from thread context or from within a DMA channel callback (IRQ context). Re-entrant calls are safe: if the channel is already in the SL_DMA_CHANNEL_STATE_ABORTING or SL_DMA_CHANNEL_STATE_DISABLED state, the function returns SL_STATUS_OK immediately without taking any action.

Returns

  • SL_STATUS_OK on success, or if the channel was already aborting or already disabled.

Note

  • In normal mode, the registered callback is invoked with error=false and aborted=true for each descriptor from the currently active descriptor onwards. When called from thread context, descriptors that have already completed in hardware but not yet been processed by the IRQ handler will have their callbacks invoked normally before the abort callbacks. When called from IRQ context (i.e., from within a DMA channel callback), those already-completed descriptors are handled by the current IRQ invocation and will not receive an additional callback from the abort. In looping mode, callbacks are invoked for all descriptors in the circular chain. Callbacks are only invoked for descriptors that requested a callback on completion.

  • Internally allocated descriptors will be freed automatically.

  • Invalid handle checks are performed via assertions in debug builds only.

This function may be called from thread context or from within a DMA channel callback (IRQ context). When invoked from a callback, the function detects that it is executing inside process_completed_descriptors() and fast-forwards past already- processed descriptors, aborting only those that remain. Re-entrant calls (e.g. from an abort callback that itself calls abort) are safe: the function returns SL_STATUS_OK immediately when the channel state is already SL_DMA_CHANNEL_STATE_ABORTING or SL_DMA_CHANNEL_STATE_DISABLED.


sl_dma_channel_suspend#

sl_status_t sl_dma_channel_suspend (const sl_dma_channel_handle_t * handle)

Suspends peripheral requests for a given DMA channel.

Parameters
TypeDirectionArgument NameDescription
const sl_dma_channel_handle_t *[in]handle

DMA channel handle.

Suspending disables peripheral requests, preventing new transfers from being triggered. Any active transfer will be allowed to complete.

Returns

  • SL_STATUS_OK on success.

Note

  • Any active transfer will be allowed to complete, but no new transfers will be started until the channel is resumed with sl_dma_channel_resume().

  • Invalid handle checks are performed via assertions in debug builds only.


sl_dma_channel_resume#

sl_status_t sl_dma_channel_resume (const sl_dma_channel_handle_t * handle)

Resumes peripheral requests for a previously suspended DMA channel.

Parameters
TypeDirectionArgument NameDescription
const sl_dma_channel_handle_t *[in]handle

DMA channel handle.

This re-enables peripheral requests that were disabled by sl_dma_channel_suspend(), allowing new transfers to be triggered.

Returns

  • SL_STATUS_OK on success.

Note

  • Invalid handle checks are performed via assertions in debug builds only.


sl_dma_channel_get_status#

sl_status_t sl_dma_channel_get_status (sl_dma_channel_handle_t * handle, sl_dma_channel_status_t * status)

Gets the status of the given DMA channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[in]handle

DMA channel handle.

sl_dma_channel_status_t *[out]status

Pointer to status structure to populate with channel status. The following fields are populated:

  • enabled: Whether the channel is enabled in hardware

  • active: Whether a transfer list is currently active

  • bytes_completed: Bytes completed in the current (head) descriptor only

Retrieves the current runtime status of the DMA channel, including whether it is enabled, whether a transfer is active, and progress information.

Returns

  • SL_STATUS_OK on success.

Note

  • The bytes_completed field only reflects progress in the currently active descriptor. This does not include bytes from previously completed descriptors in a chain.

  • Invalid handle checks are performed via assertions in debug builds only.


sl_dma_channel_handle_alloc#

sl_status_t sl_dma_channel_handle_alloc (sl_dma_channel_handle_t ** handle)

Allocate a DMA channel handle structure from the heap.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t **[out]handle

Location where the allocated handle pointer is stored. Set to NULL on allocation failure.

This helper allocates memory for a channel handle. The channel still needs to be initialized with sl_dma_channel_init() before use. Provided mainly for dynamic use cases; applications with static allocation may ignore it.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_ALLOCATION_FAILED if memory cannot be allocated.

Note

  • Invalid arguments (NULL pointer) trigger EFM_ASSERT in debug builds only. In release builds, passing NULL will result in undefined behavior.


sl_dma_channel_handle_free#

sl_status_t sl_dma_channel_handle_free (sl_dma_channel_handle_t * handle)

Free a DMA channel handle previously allocated by sl_dma_channel_handle_alloc().

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[in]handle

Channel handle pointer to free.

The channel must be deinitialized with sl_dma_channel_deinit() before calling this function. Calling this function while transfers are in progress or while descriptors are still queued results in undefined behavior.

Returns

  • SL_STATUS_OK on success.

Note

  • Invalid arguments (NULL pointer) trigger EFM_ASSERT in debug builds only. In release builds, passing NULL will result in undefined behavior.


sl_dma_channel_handle_get_size#

size_t sl_dma_channel_handle_get_size (void )

Get the size in bytes of the channel handle structure.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Useful for static allocation arrays or custom pools.

Returns

  • Size in bytes of sl_dma_channel_handle_t.


sl_dma_channel_descriptor_alloc#

sl_status_t sl_dma_channel_descriptor_alloc (const sl_dma_channel_handle_t * handle, sl_dma_channel_xfer_descriptor_t ** descriptor)

Allocate a DMA channel transfer descriptor from the heap.

Parameters
TypeDirectionArgument NameDescription
const sl_dma_channel_handle_t *[in]handle

DMA channel handle.

sl_dma_channel_xfer_descriptor_t **[out]descriptor

Location where the allocated descriptor pointer is stored. Set to NULL on allocation failure.

This helper allocates memory for a transfer descriptor. The descriptor can be used with transfer submission functions to avoid internal allocation. Provided mainly for dynamic use cases; applications with static allocation may ignore it.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Note

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only. In release builds, passing NULL will result in undefined behavior.


sl_dma_channel_descriptor_free#

sl_status_t sl_dma_channel_descriptor_free (const sl_dma_channel_handle_t * handle, sl_dma_channel_xfer_descriptor_t * descriptor)

Free a DMA channel transfer descriptor previously allocated by sl_dma_channel_descriptor_alloc().

Parameters
TypeDirectionArgument NameDescription
const sl_dma_channel_handle_t *[in]handle

DMA channel handle.

sl_dma_channel_xfer_descriptor_t *[in]descriptor

Descriptor pointer to free.

The descriptor should not be in use by any active or pending transfer when freeing.

Returns

  • SL_STATUS_OK on success.

Note

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only. In release builds, passing NULL will result in undefined behavior.


sl_dma_channel_descriptor_get_size#

size_t sl_dma_channel_descriptor_get_size (void )

Get the size in bytes of the channel transfer descriptor structure.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Useful for static allocation arrays or custom pools.

Returns

  • Size in bytes of sl_dma_channel_xfer_descriptor_t.


sl_dma_channel_init#

sl_status_t sl_dma_channel_init (sl_dma_channel_handle_t * handle, sl_peripheral_t peripheral, uint8_t channel_number, sl_dma_channel_callback_t callback, void * user_data)

Initialize an allocated channel handle with peripheral instance, channel index and user completion callback.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Pointer to handle (must be allocated).

sl_peripheral_t[in]peripheral

DMA peripheral base object. If NULL, the default dma peripheral of the target will be used.

uint8_t[in]channel_number

Hardware channel number.

sl_dma_channel_callback_t[in]callback

User callback invoked on transfer completion or error (may be NULL if not needed).

void *[in]user_data

User data pointer forwarded to callback (may be NULL if not needed).

The channel itself must already be reserved/allocated at the DMA manager layer. This function initializes the channel handle and sets up the channel for DMA transfers.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_BUSY if the DMA channel is currently enabled. For DMA channels managed by this driver, an enabled channel indicates that there are transfers that are not yet completed.

Note

  • If you wish to force re-initialization of a DMA channel that is currently enabled, you can call sl_dma_channel_abort() beforehand to abort any pending transfers and disable the channel.

  • Invalid arguments (NULL handle pointer, invalid channel number) trigger EFM_ASSERT in debug builds only. In release builds, passing invalid arguments will result in undefined behavior.


sl_dma_channel_deinit#

sl_status_t sl_dma_channel_deinit (sl_dma_channel_handle_t * handle)

Deinitialize a DMA channel handle.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Pointer to the channel handle to deinitialize.

The channel must not be enabled when calling this function. If the channel is enabled (indicating active or pending transfers), this function will return SL_STATUS_BUSY. To deinitialize a channel with active transfers, first call sl_dma_channel_abort() to abort pending transfers and disable the channel.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_BUSY if the DMA channel is currently enabled. The channel must be disabled (either by completing all transfers naturally or by calling sl_dma_channel_abort()) before it can be deinitialized.

Note

  • Invalid arguments (NULL handle pointer) trigger EFM_ASSERT in debug builds only. In release builds, passing invalid arguments will result in undefined behavior.

Returns SL_STATUS_BUSY if the channel is not in the SL_DMA_CHANNEL_STATE_DISABLED state (i.e., if transfers are still active or the channel is being aborted). Call sl_dma_channel_abort() first to ensure the channel is idle.


sl_dma_channel_set_peripheral_signal#

sl_status_t sl_dma_channel_set_peripheral_signal (const sl_dma_channel_handle_t * handle, sl_dma_signal_t signal)

Set the peripheral signal routed to a DMA channel.

Parameters
TypeDirectionArgument NameDescription
const sl_dma_channel_handle_t *[in]handle

Pointer to handle (must be allocated and initialized).

sl_dma_signal_t[in]signal

Peripheral signal to route to the channel, expressed as one of the SL_DMA_SIGNAL_* constants defined in sl_device_dma.h.

The peripheral signal is necessary for transfers configured in block-handshake mode (block_handshake_mode == true in sl_dma_channel_transfer_t), which pend on the signal being asserted before executing each block. For instance, memory-to-peripheral or peripheral-to-memory transfers shall only execute when the peripheral is ready to consume or serve data, so the DMA waits on the peripheral's request line between blocks.

The peripheral signal is shared by every transfer subsequently submitted on the channel, so it typically only needs to be set once during channel setup. The m2p / p2m helpers (sl_dma_channel_submit_transfer_m2p(), sl_dma_channel_submit_transfer_p2m(), sl_dma_channel_submit_ping_pong_transfer_m2p(), sl_dma_channel_submit_ping_pong_transfer_p2m(), sl_dma_channel_submit_triple_buffered_transfer_m2p(), and sl_dma_channel_submit_triple_buffered_transfer_p2m()) enable block-handshake mode by default, so they all rely on this routing. Memory-to-memory transfers (sl_dma_channel_submit_transfer_m2m()) do not use block-handshake mode and therefore do not depend on the peripheral signal.

No transfers must be active on the DMA channel when calling this API; the channel must be idle so that the new routing applies cleanly to the next submission.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_BUSY when the DMA channel has active transfers.

Note

  • Invalid signal values trigger EFM_ASSERT in debug builds only.

  • Invalid handle checks are performed via assertions in debug builds only.

Set the peripheral signal routed to a DMA channel.

The peripheral signal is necessary for memory-to-peripheral or peripheral-to-memory transfers which require a handshake with the peripheral for each block transferred.

The peripheral signal can only be changed while the channel is in the SL_DMA_CHANNEL_STATE_DISABLED state. Returns SL_STATUS_BUSY if the channel has active or pending transfers.


sl_dma_channel_submit_transfer_m2m#

sl_status_t sl_dma_channel_submit_transfer_m2m (sl_dma_channel_handle_t * handle, void * source, void * destination, size_t size, sl_dma_channel_xfer_descriptor_t * descriptor)

Submit a memory-to-memory transfer on a channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Channel handle.

void *[in]source

Source address.

void *[in]destination

Destination address.

size_t[in]size

Transfer size in bytes (must be > 0).

sl_dma_channel_xfer_descriptor_t *[inout]descriptor

Optional pre-built descriptor pointer; if NULL one is allocated and filled.

If descriptor is NULL, a descriptor is allocated internally and populated. This function automatically selects an optimal transfer unit size based on buffer alignment and transfer size.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if size is 0, if the transfer size (in bytes) is not a multiple of the automatically selected unit size (in bytes), if source or destination buffers are misaligned for the selected unit size, or if a user-provided descriptor is too small for a transfer requiring segmentation.

  • SL_STATUS_INVALID_STATE if channel is in looping mode (ping-pong or triple-buffered transfer is active).

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Note

  • A completion callback is always requested for this transfer.

  • Buffer alignment requirements: Both source and destination must be aligned for the selected unit size (WORD requires 4-byte alignment, HALF requires 2-byte alignment, BYTE has no alignment requirement). The transfer size must be a multiple of the selected unit size.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.


sl_dma_channel_submit_transfer_m2p#

sl_status_t sl_dma_channel_submit_transfer_m2p (sl_dma_channel_handle_t * handle, void * source, void * reg, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t * descriptor)

Submit a memory-to-peripheral transfer on a channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Channel handle.

void *[in]source

Source memory address.

void *[in]reg

Peripheral destination address.

size_t[in]size

Transfer size in bytes (must be > 0).

sl_dma_ctrl_size_t[in]unit_size

Transfer unit size (SL_DMA_CTRL_SIZE_BYTE, SL_DMA_CTRL_SIZE_HALF, or SL_DMA_CTRL_SIZE_WORD).

sl_dma_channel_xfer_descriptor_t *[inout]descriptor

Optional pre-built descriptor pointer; if NULL one is allocated and filled.

If descriptor is NULL, a descriptor is allocated internally and populated. The transfer is triggered in block handshake mode with the current peripheral signal set with sl_dma_channel_set_peripheral_signal().

Contrary to sl_dma_channel_submit_transfer_m2m(), the destination address is a peripheral register address. The source address is incremented during the transfer.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if size is 0, if the transfer size (in bytes) is not a multiple of the unit size (in bytes), if source or peripheral register address is misaligned for the specified unit size, or if a user-provided descriptor is too small for a transfer requiring segmentation.

  • SL_STATUS_INVALID_STATE if channel is in looping mode (ping-pong or triple-buffered transfer is active).

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Note

  • Transfer defaults: source increments, destination does not increment, block handshake mode is enabled, and a completion callback is always requested.

  • Buffer alignment requirements: Both the source address and the peripheral register address must be aligned according to the unit size. For SL_DMA_CTRL_SIZE_HALF, both addresses must be 2-byte aligned. For SL_DMA_CTRL_SIZE_WORD, both addresses must be 4-byte aligned. SL_DMA_CTRL_SIZE_BYTE has no alignment requirement. In practice, peripheral registers are always naturally aligned to their access size.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.


sl_dma_channel_submit_transfer_p2m#

sl_status_t sl_dma_channel_submit_transfer_p2m (sl_dma_channel_handle_t * handle, void * reg, void * destination, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t * descriptor)

Submit a peripheral-to-memory transfer on a channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Channel handle.

void *[in]reg

Peripheral register address (e.g., &EUSART0->RXDATA).

void *[in]destination

Memory destination address.

size_t[in]size

Transfer size in bytes (must be > 0).

sl_dma_ctrl_size_t[in]unit_size

Transfer unit size (SL_DMA_CTRL_SIZE_BYTE, SL_DMA_CTRL_SIZE_HALF, or SL_DMA_CTRL_SIZE_WORD).

sl_dma_channel_xfer_descriptor_t *[inout]descriptor

Optional pre-built descriptor pointer; if NULL one is allocated and filled.

If descriptor is NULL, a descriptor is allocated internally and populated. The transfer is triggered in block handshake mode with the current peripheral signal set with sl_dma_channel_set_peripheral_signal().

Contrary to sl_dma_channel_submit_transfer_m2m(), the source address is a peripheral register address. The destination address is incremented during the transfer.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if size is 0, if the transfer size (in bytes) is not a multiple of the unit size (in bytes), if destination or peripheral register address is misaligned for the specified unit size, or if a user-provided descriptor is too small for a transfer requiring segmentation.

  • SL_STATUS_INVALID_STATE if channel is in looping mode (ping-pong or triple-buffered transfer is active).

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Note

  • Transfer defaults: source does not increment, destination increments, block handshake mode is enabled, and a completion callback is always requested.

  • Buffer alignment requirements: Both the destination address and the peripheral register address must be aligned according to the unit size. For SL_DMA_CTRL_SIZE_HALF, both addresses must be 2-byte aligned. For SL_DMA_CTRL_SIZE_WORD, both addresses must be 4-byte aligned. SL_DMA_CTRL_SIZE_BYTE has no alignment requirement. In practice, peripheral registers are always naturally aligned to their access size.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.


sl_dma_channel_submit_transfer_list#

sl_status_t sl_dma_channel_submit_transfer_list (sl_dma_channel_handle_t * handle, sl_dma_channel_transfer_t * list_head)

Submits a list of transfers to the specified DMA channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Pointer to the DMA channel handle.

sl_dma_channel_transfer_t *[in]list_head

Pointer to the head of the transfer list.

If other transfers and/or transfer lists are already submitted, this list of transfers will be appended to the list of pending transfers for the given DMA channel.

Large transfers may be automatically segmented if they exceed the maximum transfer size. For multi-segment transfers, the completion callback is only triggered when the last segment completes.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if any transfer in the list has size == 0, if the transfer size (in bytes) is not a multiple of the unit size (in bytes), if source or destination buffers are misaligned for the specified unit size, or if a user-provided descriptor is too small for a transfer requiring segmentation.

  • SL_STATUS_INVALID_STATE if channel is in looping mode (ping-pong or triple-buffered transfer is active).

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Warnings

  • Transfer structures in the transfer list should only be freed or reused after they have completed.

  • This function must not be used to submit looping transfers, which are transfers where the transfer list forms a circular structure (the last transfer's next pointer points back to an earlier transfer in the list, creating a loop). Looping transfers are only supported through specialized ping-pong and triple-buffered transfer APIs. The transfer list submitted to this function must be linear, with the last transfer in the list having its next pointer set to NULL. Submitting a looping transfer to this function will result in undefined behavior that the DMA Channel Driver cannot recover from.

Note

  • Each transfer in the list must have size > 0. Transfers with size == 0 will cause this function to return SL_STATUS_INVALID_PARAMETER.

  • The transfer size (in bytes) must be a multiple of the unit size (in bytes). For example, if unit_size is SL_DMA_CTRL_SIZE_HALF (2 bytes), the size must be an even number. If unit_size is SL_DMA_CTRL_SIZE_WORD (4 bytes), the size must be a multiple of 4. If this requirement is not met, the function will return SL_STATUS_INVALID_PARAMETER.

  • Buffer alignment requirements: Source and destination addresses must be aligned according to the unit size. For SL_DMA_CTRL_SIZE_HALF, buffers must be 2-byte aligned. For SL_DMA_CTRL_SIZE_WORD, buffers must be 4-byte aligned. SL_DMA_CTRL_SIZE_BYTE has no alignment requirement. Misaligned buffers will cause this function to return SL_STATUS_INVALID_PARAMETER.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.


sl_dma_channel_submit_ping_pong_transfer_m2p#

sl_status_t sl_dma_channel_submit_ping_pong_transfer_m2p (sl_dma_channel_handle_t * handle, void * source, void * source_2, void * destination, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t * descriptors)

Submits a memory to peripheral ping pong transfer on given DMA channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Channel handle.

void *[in]source

First source buffer.

void *[in]source_2

Second source buffer.

void *[in]destination

Peripheral destination address.

size_t[in]size

Transfer size in bytes per buffer (must be > 0).

sl_dma_ctrl_size_t[in]unit_size

Transfer unit size (SL_DMA_CTRL_SIZE_BYTE, SL_DMA_CTRL_SIZE_HALF, or SL_DMA_CTRL_SIZE_WORD).

sl_dma_channel_xfer_descriptor_t *[inout]descriptors

Optional pre-built descriptor pointer array; if NULL, descriptors are allocated and filled. If provided, must point to an array of 2 descriptors.

This function sets up a continuous ping-pong transfer between two source buffers and a peripheral register. The transfer loops indefinitely, alternating between the two source buffers until the channel is disabled.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if size is 0, if the transfer size (in bytes) is not a multiple of the unit size (in bytes), if source buffers are misaligned for the specified unit size, or if size exceeds the maximum single descriptor capacity.

  • SL_STATUS_INVALID_STATE if channel is already in looping mode or has pending transfers.

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Note

  • The transfer loops infinitely until the channel is stopped with sl_dma_channel_abort().

  • This implementation configures the source to increment. The destination does not increment.

  • Buffer alignment requirements: Source addresses must be aligned according to the unit size. For SL_DMA_CTRL_SIZE_HALF, sources must be 2-byte aligned. For SL_DMA_CTRL_SIZE_WORD, sources must be 4-byte aligned. SL_DMA_CTRL_SIZE_BYTE has no alignment requirement.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.

Submits a memory to peripheral ping pong transfer on given DMA channel.


sl_dma_channel_submit_ping_pong_transfer_p2m#

sl_status_t sl_dma_channel_submit_ping_pong_transfer_p2m (sl_dma_channel_handle_t * handle, void * source, void * destination, void * destination_2, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t * descriptors)

Submits a peripheral to memory ping pong transfer on given DMA channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Channel handle.

void *[in]source

Peripheral source address.

void *[in]destination

First destination buffer.

void *[in]destination_2

Second destination buffer.

size_t[in]size

Transfer size in bytes per buffer (must be > 0).

sl_dma_ctrl_size_t[in]unit_size

Transfer unit size (SL_DMA_CTRL_SIZE_BYTE, SL_DMA_CTRL_SIZE_HALF, or SL_DMA_CTRL_SIZE_WORD).

sl_dma_channel_xfer_descriptor_t *[inout]descriptors

Optional pre-built descriptor pointer array; if NULL, descriptors are allocated and filled. If provided, must point to an array of 2 descriptors.

This function sets up a continuous ping-pong transfer between a peripheral register and two destination buffers. The transfer loops indefinitely, alternating between the two destination buffers until the channel is disabled.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if size is 0, if the transfer size (in bytes) is not a multiple of the unit size (in bytes), if destination buffers are misaligned for the specified unit size, or if size exceeds the maximum single descriptor capacity.

  • SL_STATUS_INVALID_STATE if channel is already in looping mode or has pending transfers.

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Note

  • The transfer loops infinitely until the channel is stopped with sl_dma_channel_abort().

  • This implementation configures the destination to increment. The source does not increment.

  • Buffer alignment requirements: Destination addresses must be aligned according to the unit size. For SL_DMA_CTRL_SIZE_HALF, destinations must be 2-byte aligned. For SL_DMA_CTRL_SIZE_WORD, destinations must be 4-byte aligned. SL_DMA_CTRL_SIZE_BYTE has no alignment requirement.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.

Submits a peripheral to memory ping pong transfer on given DMA channel.


sl_dma_channel_submit_triple_buffered_transfer_m2p#

sl_status_t sl_dma_channel_submit_triple_buffered_transfer_m2p (sl_dma_channel_handle_t * handle, void * source, void * source_2, void * source_3, void * destination, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t * descriptors)

Submits a memory to peripheral triple buffered transfer on given DMA channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Channel handle.

void *[in]source

First source buffer.

void *[in]source_2

Second source buffer.

void *[in]source_3

Third source buffer.

void *[in]destination

Peripheral destination address.

size_t[in]size

Transfer size in bytes per buffer (must be > 0).

sl_dma_ctrl_size_t[in]unit_size

Transfer unit size (SL_DMA_CTRL_SIZE_BYTE, SL_DMA_CTRL_SIZE_HALF, or SL_DMA_CTRL_SIZE_WORD).

sl_dma_channel_xfer_descriptor_t *[inout]descriptors

Optional pre-built descriptor pointer array; if NULL, descriptors are allocated and filled. If provided, must point to an array of 3 descriptors.

This function sets up a continuous triple-buffered transfer cycling through three source buffers to a peripheral register. The transfer loops indefinitely, cycling through the three source buffers until the channel is disabled.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if size is 0, if the transfer size (in bytes) is not a multiple of the unit size (in bytes), if source buffers are misaligned for the specified unit size, or if size exceeds the maximum single descriptor capacity.

  • SL_STATUS_INVALID_STATE if channel is already in looping mode or has pending transfers.

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Note

  • The transfer loops infinitely until the channel is stopped with sl_dma_channel_abort().

  • This implementation configures the source to increment. The destination does not increment.

  • Buffer alignment requirements: Source addresses must be aligned according to the unit size. For SL_DMA_CTRL_SIZE_HALF, sources must be 2-byte aligned. For SL_DMA_CTRL_SIZE_WORD, sources must be 4-byte aligned. SL_DMA_CTRL_SIZE_BYTE has no alignment requirement.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.

Submits a memory to peripheral triple buffered transfer on given DMA channel.


sl_dma_channel_submit_triple_buffered_transfer_p2m#

sl_status_t sl_dma_channel_submit_triple_buffered_transfer_p2m (sl_dma_channel_handle_t * handle, void * source, void * destination, void * destination_2, void * destination_3, size_t size, sl_dma_ctrl_size_t unit_size, sl_dma_channel_xfer_descriptor_t * descriptors)

Submits a peripheral to memory triple buffered transfer on given DMA channel.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[inout]handle

Channel handle.

void *[in]source

Peripheral source address.

void *[in]destination

First destination buffer.

void *[in]destination_2

Second destination buffer.

void *[in]destination_3

Third destination buffer.

size_t[in]size

Transfer size in bytes per buffer (must be > 0).

sl_dma_ctrl_size_t[in]unit_size

Transfer unit size (SL_DMA_CTRL_SIZE_BYTE, SL_DMA_CTRL_SIZE_HALF, or SL_DMA_CTRL_SIZE_WORD).

sl_dma_channel_xfer_descriptor_t *[inout]descriptors

Optional pre-built descriptor pointer array; if NULL, descriptors are allocated and filled. If provided, must point to an array of 3 descriptors.

This function sets up a continuous triple-buffered transfer from a peripheral register cycling through three destination buffers. The transfer loops indefinitely, cycling through the three destination buffers until the channel is disabled.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if size is 0, if the transfer size (in bytes) is not a multiple of the unit size (in bytes), if destination buffers are misaligned for the specified unit size, or if size exceeds the maximum single descriptor capacity.

  • SL_STATUS_INVALID_STATE if channel is already in looping mode or has pending transfers.

  • SL_STATUS_ALLOCATION_FAILED if descriptor allocation fails.

Note

  • The transfer loops infinitely until the channel is stopped with sl_dma_channel_abort().

  • This implementation configures the destination to increment. The source does not increment.

  • Buffer alignment requirements: Destination addresses must be aligned according to the unit size. For SL_DMA_CTRL_SIZE_HALF, destinations must be 2-byte aligned. For SL_DMA_CTRL_SIZE_WORD, destinations must be 4-byte aligned. SL_DMA_CTRL_SIZE_BYTE has no alignment requirement.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.

Submits a peripheral to memory triple buffered transfer on given DMA channel.


sl_dma_channel_update_active_transfer#

sl_status_t sl_dma_channel_update_active_transfer (sl_dma_channel_handle_t * handle, size_t new_size)

Updates size of the current transfer.

Parameters
TypeDirectionArgument NameDescription
sl_dma_channel_handle_t *[in]handle

Channel handle.

size_t[in]new_size

New size of the transfer, in bytes.

This function allows updating the size for the active transfer. This is useful in cases where the expected data follows a pattern of a header that specifies a payload size followed by the actual payload. When the header and the payload have to be in separate buffers and zero-copy is desired, the user can parse the header from the channel callback and call this function to update the size matching the information read from the header.

Returns

  • SL_STATUS_OK on success.

  • SL_STATUS_INVALID_PARAMETER if new_size is 0, if new_size is not a multiple of the transfer unit size, if the transfer has already transferred more bytes than new_size, or if new_size in transfer units exceeds the maximum single-descriptor transfer count (SL_DMA_CHANNEL_MAX_XFER_UNIT_COUNT).

  • SL_STATUS_INVALID_STATE if no transfer is currently active.

Note

  • Special care must be taken by the caller to ensure that the active transfer is really the one it aims at modifying.

  • If the current transfer has transferred more bytes than new_size, the call will fail and the transfer will continue with its original size.

  • It is up to the caller to ensure that 'new_size' is not larger than the buffer that was submitted earlier.

  • Invalid arguments (NULL pointers) trigger EFM_ASSERT in debug builds only.