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:
Add the components. Include the
dma_channelanddma_managerSLC components in your.slcp. The DMA Manager is auto-initialized by SL Main; no manualinit()call is required.Allocate (or reserve) a channel. Use
sl_dma_manager_allocate_channel()(any channel) orsl_dma_manager_reserve_channel()(a specific channel number) from the DMA Manager.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.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.Submit transfers. Pick the helper that matches your transfer pattern (see "Transfer modes" below). Pass
NULLas the descriptor argument to let the driver allocate one, or pre-allocate via sl_dma_channel_descriptor_alloc() for deterministic memory use.Handle completions. The callback registered at init time is invoked once per descriptor that requested a callback, with explicit
error/abortedflags. Application code may also poll progress via sl_dma_channel_get_status().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 |
|---|---|---|---|
Memory-to-memory | No | No | |
Memory-to-peripheral | No | Yes | |
Peripheral-to-memory | No | Yes | |
Linked list of heterogeneous transfers | No | When list contains M2P/P2M | |
Two-buffer streaming M2P | Yes | Yes | |
Two-buffer streaming P2M | Yes | Yes | |
Three-buffer streaming M2P | Yes | Yes | |
Three-buffer streaming P2M | Yes | Yes | |
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
Enumerations#
DMA channel state.
DMA channel operating mode.
Typedefs#
Typedef for the user supplied callback function which is called on a transfer complete event.
Functions#
Aborts all pending transfers on a given DMA channel.
Suspends peripheral requests for a given DMA channel.
Resumes peripheral requests for a previously suspended DMA channel.
Gets the status of the given DMA channel.
Allocate a DMA channel handle structure from the heap.
Free a DMA channel handle previously allocated by sl_dma_channel_handle_alloc().
Get the size in bytes of the channel handle structure.
Allocate a DMA channel transfer descriptor from the heap.
Free a DMA channel transfer descriptor previously allocated by sl_dma_channel_descriptor_alloc().
Get the size in bytes of the channel transfer descriptor structure.
Initialize an allocated channel handle with peripheral instance, channel index and user completion callback.
Deinitialize a DMA channel handle.
Set the peripheral signal routed to a DMA channel.
Submit a memory-to-memory transfer on a channel.
Submit a memory-to-peripheral transfer on a channel.
Submit a peripheral-to-memory transfer on a channel.
Submits a list of transfers to the specified DMA channel.
Submits a memory to peripheral ping pong transfer on given DMA channel.
Submits a peripheral to memory ping pong transfer on given DMA channel.
Submits a memory to peripheral triple buffered transfer on given DMA channel.
Submits a peripheral to memory triple buffered transfer on given DMA channel.
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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| N/A | handle | Handle to DMA channel. | |
| N/A | user_data | Pointer to user data that is passed to the tx complete handler function. | |
| N/A | error | Flag that indicates if an error occurred during transfer. | |
| N/A | aborted | 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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=falseandaborted=truefor 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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:
|
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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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().
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| void | N/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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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().
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| void | N/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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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 |
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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| 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.