DMADRV to DMA Channel Driver and DMA Manager Migration Guide#

Table of Contents#


1. Overview#

Why Migrate?#

DMADRV was a monolithic, all-in-one DMA driver from the EMDRV (Energy Micro Driver) family. While it served well for basic DMA operations, it combined resource management and transfer operations into a single component, limiting flexibility and extensibility.

The new architecture separates DMA functionality into two focused, independent components:

  • DMA Manager — System-level DMA resource management (initialization, channel allocation, SYNC bit management, round-robin configuration)

  • DMA Channel Driver — Per-channel transfer operations (transfer submission, ping-pong, triple-buffered, transfer lists, suspend/resume/abort, status query)

This separation provides a cleaner architecture, better error handling, new transfer modes, and a consistent API style aligned with the modern Silicon Labs platform SDK conventions.

Benefits of Migration#

Benefit

Description

Improved error handling

Callbacks receive explicit error and aborted flags. DMA errors no longer cause an infinite loop — the application can recover gracefully.

New transfer modes

Triple-buffered looping transfers, linked transfer lists with auto-segmentation, and dynamic transfer size updates are now available.

Consistent API style

Uses standard sl_status_t return codes and follows Silicon Labs naming conventions, consistent with other platform SDK components.

Automatic initialization

DMA Manager initializes automatically through SL Main — no manual Init() call required.

Auto-segmentation

Transfers larger than the hardware descriptor limit are automatically segmented into linked descriptors.

Better descriptor management

Descriptors are auto-allocated when passing NULL, or can be pre-allocated for deterministic memory usage.

Handle-based API

Channel handles provide type safety and encapsulate channel state, replacing raw integer channel IDs.

Deprecation Timeline#

Milestone

Release

Description

New components available

2026.6.0

DMA Manager and DMA Channel Driver released as production-quality replacements

DMADRV deprecated

2026.6.0

DMADRV marked as deprecated; no new features will be added

DMADRV removed

2027.6.0

DMADRV completely removed from the SDK

Important: You have a one-year migration window from 2026.6.0 to 2027.6.0. During this period, both DMADRV and the new components coexist in the SDK, and existing DMADRV code continues to work without changes. However, Silicon Labs strongly recommends migrating early to take advantage of improved error handling and new capabilities.

Starting with 2026.6.0, all SiSDK components use the new DMA Manager and DMA Channel Driver. Keeping DMADRV in your application increases code size because the application still pulls in DMADRV in addition to the new DMA components already used by the rest of the SDK.

Migration Effort Estimate#

Project Size

Estimated Effort

Description

Small (< 5 DMA channels, basic transfers only)

1–2 hours

Straightforward API replacement

Medium (5–10 DMA channels, mixed transfer types)

2–3 hours

Requires callback refactoring

Large (10+ channels or ping-pong-heavy)

3–4 hours

Ping-pong callback changes require stop-logic review


2. Prerequisites#

SDK Version Requirements#

  • Minimum SDK Version: 2026.6.0

  • Recommended SDK Version: 2026.6.0 or later

Required Components#

The new implementation requires these SLCC components in your .slcp file:

component:
  - id: dma_manager
  - id: dma_channel

The dma_manager_init and dma_descriptor_allocator components are automatically included as dependencies. You do not need to add them explicitly.

Components to Remove#

Remove the legacy DMADRV component from your .slcp file:

# Remove these from your .slcp:
# - id: dmadrv

Tool Requirements#

  • Simplicity Studio 6 (2026.6.0 release or later), or

  • SLC CLI (2026.6.0 release or later)


3. Feature Comparison#

Feature Matrix#

Feature

DMADRV

DMA Manager + DMA Channel Driver

Notes

DMA initialization

DMADRV_Init()

✅ Auto-init via SL Main

No manual init call needed

Channel allocation (any)

Same concept, different API

Channel reservation (specific)

Same concept, different API

Channel free

Requires deinit + free in new API

Memory-to-peripheral transfer

Simplified — no srcInc param

Peripheral-to-memory transfer

Simplified — no dstInc param

Memory-to-memory transfer

✅ (via native LDMA)

✅ (dedicated API)

No longer requires raw LDMA descriptors

Ping-pong transfers

Callback change — callback is still invoked but cannot stop the transfer by returning false

Triple-buffered transfers

New capability

Transfer lists (linked)

❌ (raw LDMA only)

With auto-segmentation

Dynamic transfer size update

New capability

Suspend / Resume

Same behavior

Abort (Stop)

Behavioral change — abort now triggers callbacks

Transfer status query

✅ (multiple functions)

✅ (single status struct)

Unified query

Remaining/completed count

✅ (items remaining)

✅ (bytes completed)

Unit changed

Polled completion

TransferDone()

✅ via get_status()

Inferred from active == false

Callback completion

Signature changed

SYNC bit management

New capability

Channel property allocation

Allocate by priority, interleaving, etc.

New Capabilities#

The new DMA Channel Driver introduces capabilities not available in DMADRV:

  1. Triple-Buffered Transfers

    • Description: Continuous looping transfers across three buffers instead of two

    • Benefit: Reduces buffer underrun risk in high-throughput scenarios by providing an extra buffer slot

  2. Transfer Lists

    • Description: Submit a linked list of heterogeneous transfers that execute sequentially

    • Benefit: Complex multi-step DMA operations without CPU intervention; auto-segmentation handles transfers exceeding the hardware descriptor limit

  3. Dynamic Transfer Size Update

    • Description: Modify the size of an active transfer while it is in progress

    • Benefit: Useful for protocol parsing where the total transfer length is determined from an initial header

  4. SYNC Bit Management

    • Description: Allocate and free LDMA SYNC bits for hardware synchronization

    • Benefit: Proper resource management for SYNC-based DMA coordination

  5. Channel Property Allocation

    • Description: Request channels with specific properties (high priority, round-robin, interleaving, dual-destination)

    • Benefit: Deterministic channel assignment for hardware-constrained features

Removed/Changed Features#

  1. Callback-controlled ping-pong stop

    • Legacy behavior: Returning false from the callback stopped the ping-pong transfer

    • New behavior: The callback is still invoked on each buffer completion, but its return type is void — it cannot stop the transfer

    • Migration path: Call sl_dma_channel_abort() from within the callback or from other application logic to stop the transfer — see Phase 6

  2. sequenceNo in callbacks

    • Legacy behavior: Each callback invocation received an incrementing sequence number

    • Migration path: Maintain an application-level counter if needed

  3. DMADRV_TransferCompletePending()

    • Legacy behavior: Checked if a transfer-complete interrupt is pending (useful when ISRs are disabled)

    • Migration path: Use sl_dma_channel_get_status() or rely on callbacks

  4. DMADRV_DeInit()

    • Legacy behavior: Deinitializes the DMA hardware and disallows further operations

    • Migration path: No global deinit needed. Use sl_dma_channel_deinit() + sl_dma_manager_free_channel() for per-channel cleanup.


4. Breaking Changes#

Summary of Breaking Changes#

Change Type

Count

Impact

API signature changes

All 16 functions

High — every call site needs updating

Behavioral changes

3

High — ping-pong, abort, and error handling

Return type change

1

Medium — Ecode_tsl_status_t throughout

Configuration changes

3

Low — simplified configuration

Return Type Change#

All functions change from Ecode_t to sl_status_t:

Legacy:

Ecode_t result = DMADRV_MemoryPeripheral(ch, signal, dst, src, true, len,
                                          dmadrvDataSize1, callback, user);
if (result != ECODE_EMDRV_DMADRV_OK) {
  // Error
}

New:

sl_status_t status = sl_dma_channel_submit_transfer_m2p(&handle, src, dst, len,
                                                         SL_DMA_CTRL_SIZE_BYTE, NULL);
if (status != SL_STATUS_OK) {
  // Error
}

Callback Signature Change#

Legacy callback:

typedef bool (*DMADRV_Callback_t)(unsigned int channel,
                                   unsigned int sequenceNo,
                                   void *userParam);

New callback:

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

Key differences:

  • Return type changes from bool to void — callbacks are still invoked during ping-pong, but cannot stop it by returning false; call sl_dma_channel_abort() instead

  • channel (integer) replaced by handle (pointer to handle struct)

  • sequenceNo removed — use application-level counter if needed

  • Explicit error and aborted boolean flags added for clear status reporting

  • userParam renamed to user_data

Behavioral Changes#

Legacy Behavior

New Behavior

Migration Action

Ping-pong callback returns bool to continue (true) or stop (false)

Ping-pong callback is void — it is still called on each buffer completion, but cannot return false to stop; call sl_dma_channel_abort() to stop

Change callback return type to void; move stop logic to sl_dma_channel_abort() — see Phase 6

DMADRV_StopTransfer() silently stops the channel; no callbacks

sl_dma_channel_abort() stops the channel and invokes callbacks for each pending descriptor with aborted=true

Add abort handling in callbacks

DMA error causes infinite loop in IRQ handler (while(true))

DMA error invokes callback with error=true and aborted=true; application can recover

Add error handling in callbacks

Transfer Size Unit Change#

DMADRV uses item count (int len). DMA Channel Driver uses byte count (size_t size).

DMADRV Data Size

Byte Multiplier

Conversion Formula

dmadrvDataSize1 (byte)

×1

size = len

dmadrvDataSize2 (halfword)

×2

size = len * 2

dmadrvDataSize4 (word)

×4

size = len * 4

Note: If you always used dmadrvDataSize1 (byte transfers), the numeric value stays the same. For halfword or word transfers, multiply the item count accordingly.

Peripheral Signal Change#

Legacy: Passed as a parameter on every transfer call.

New: Set once via sl_dma_channel_set_peripheral_signal() before submitting transfers.

Legacy Signal

New Signal

Notes

dmadrvPeripheralSignal_USART0_TXBL

SL_DMA_SIGNAL_USART0_TXBL

Naming convention change

dmadrvPeripheralSignal_EUSART0_TXBL

SL_DMA_SIGNAL_EUSART0_TXFL

Name change: TXBLTXFL

dmadrvPeripheralSignal_EUSART0_RXDATAV

SL_DMA_SIGNAL_EUSART0_RXFL

Name change: RXDATAVRXFL

Signal constants are defined in sl_device_dma.h (auto-included). The type also changes from uint32_t (by value) to sl_dma_signal_t (const uint32_t*, by pointer).

Configuration Changes#

Legacy Configuration

New Configuration

Notes

EMDRV_DMADRV_DMA_IRQ_PRIORITY

Removed

Interrupt Manager can be used to change interrupt priority at runtime

EMDRV_DMADRV_DMA_CH_COUNT

Removed

DMA Manager uses all available hardware channels

EMDRV_DMADRV_DMA_CH_PRIORITY

dma_manager_round_robin component + SL_DMA_MANAGER_ROUND_ROBIN_CHANNEL_COUNT config

Add the component; configure the channel count. Applied automatically at init.


5. API Mapping Reference#

Function Mapping#

Initialization / Deinitialization#

Legacy API

New API

Mapping Type

Notes

DMADRV_Init()

Auto-init via SL Main

Removed

DMA Manager initializes automatically through sl_platform_init()sl_dma_manager_instances_init(). Remove the call.

DMADRV_DeInit()

sl_dma_channel_deinit()

Changed

No global deinit. Use per-channel deinit + free instead.

Channel Allocation / Deallocation#

Legacy API

New API

Mapping Type

Notes

DMADRV_AllocateChannel(&channelId, NULL)

sl_dma_manager_allocate_channel(NULL, &channel_nbr)

Direct

Channel type: unsigned intuint8_t

DMADRV_AllocateChannelById(channelId, NULL)

sl_dma_manager_reserve_channel(NULL, channel_nbr)

Renamed

Same behavior

DMADRV_FreeChannel(channelId)

sl_dma_channel_deinit(&handle) + sl_dma_manager_free_channel(NULL, ch)

Split

Deinit the channel driver handle first, then free the channel in DMA Manager

Transfer APIs#

Legacy API

New API

Mapping Type

Notes

DMADRV_MemoryPeripheral()

sl_dma_channel_set_peripheral_signal() + sl_dma_channel_submit_transfer_m2p()

Split

Signal set once; srcInc removed (always increments); size in bytes

DMADRV_PeripheralMemory()

sl_dma_channel_set_peripheral_signal() + sl_dma_channel_submit_transfer_p2m()

Split

Signal set once; dstInc removed (always increments); size in bytes

DMADRV_LdmaStartTransfer()

sl_dma_channel_submit_transfer_m2m() or sl_dma_channel_submit_transfer_list()

Changed

No raw LDMA descriptors needed

DMADRV_MemoryPeripheralPingPong()

sl_dma_channel_set_peripheral_signal() + sl_dma_channel_submit_ping_pong_transfer_m2p()

Split + Behavioral

Callback still invoked per buffer, but void return — cannot stop by returning false

DMADRV_PeripheralMemoryPingPong()

sl_dma_channel_set_peripheral_signal() + sl_dma_channel_submit_ping_pong_transfer_p2m()

Split + Behavioral

Callback still invoked per buffer, but void return — cannot stop by returning false

Transfer Control#

Legacy API

New API

Mapping Type

Notes

DMADRV_PauseTransfer(channelId)

sl_dma_channel_suspend(&handle)

Renamed

Same behavior

DMADRV_ResumeTransfer(channelId)

sl_dma_channel_resume(&handle)

Renamed

Same behavior

DMADRV_StopTransfer(channelId)

sl_dma_channel_abort(&handle)

Changed

Now invokes callbacks with aborted=true

Transfer Status#

Legacy API

New API

Mapping Type

Notes

DMADRV_TransferActive(ch, &active)

sl_dma_channel_get_status(&handle, &status)status.enabled

Changed

Single unified status struct

DMADRV_TransferDone(ch, &done)

sl_dma_channel_get_status(&handle, &status)!status.active

Changed

Infer done from active == false

DMADRV_TransferCompletePending(ch, &pending)

No direct equivalent

Removed

Use sl_dma_channel_get_status() or callbacks

DMADRV_TransferRemainingCount(ch, &remaining)

sl_dma_channel_get_status(&handle, &status)status.bytes_completed

Changed

Returns bytes completed (not items remaining). Calculate remaining as total - bytes_completed.

Mapping Type Legend:

  • Direct — 1:1 replacement with same behavior

  • Renamed — Same function, different name

  • Changed — Signature or behavior changed

  • Split — One legacy function maps to multiple new functions

  • Removed — No longer available/needed

  • Behavioral — Significant behavioral change requires code restructuring

Data Structure Mapping#

Legacy Type

New Type

Notes

Ecode_t

sl_status_t

Standard platform status type

unsigned int channelId

sl_dma_channel_handle_t

Handle-based API; contains channel_number field

DMADRV_DataSize_t

sl_dma_ctrl_size_t

Macro constants instead of enum values

DMADRV_PeripheralSignal_t (uint32_t)

sl_dma_signal_t (const uint32_t*)

Value → pointer type

N/A

sl_dma_channel_status_t

New: {active, enabled, bytes_completed}

N/A

sl_dma_channel_transfer_t

New: transfer list element

Constant/Macro Mapping#

Legacy Constant

New Constant

Notes

dmadrvDataSize1

SL_DMA_CTRL_SIZE_BYTE

Byte transfer

dmadrvDataSize2

SL_DMA_CTRL_SIZE_HALF

Halfword (2-byte) transfer

dmadrvDataSize4

SL_DMA_CTRL_SIZE_WORD

Word (4-byte) transfer

DMADRV_MAX_XFER_COUNT

SL_DMA_CHANNEL_MAX_XFER_UNIT_COUNT

Max units per descriptor. New driver auto-segments larger transfers.

Error Code Mapping#

Legacy DMADRV Error

New sl_status_t

Notes

ECODE_EMDRV_DMADRV_OK

SL_STATUS_OK

Success

ECODE_EMDRV_DMADRV_PARAM_ERROR

SL_STATUS_INVALID_PARAMETER

Invalid parameter

ECODE_EMDRV_DMADRV_NOT_INITIALIZED

N/A

Auto-initialized; asserts used internally

ECODE_EMDRV_DMADRV_ALREADY_INITIALIZED

SL_STATUS_ALREADY_INITIALIZED

DMA Manager

ECODE_EMDRV_DMADRV_CHANNELS_EXHAUSTED

SL_STATUS_NO_MORE_RESOURCE

No channels available

ECODE_EMDRV_DMADRV_IN_USE

SL_STATUS_BUSY

Channel enabled or has active transfers

ECODE_EMDRV_DMADRV_ALREADY_FREED

N/A

Handled gracefully by DMA Manager

ECODE_EMDRV_DMADRV_CH_NOT_ALLOCATED

SL_STATUS_NOT_AVAILABLE

Channel not allocated


6. Step-by-Step Migration#

Phase 1: Preparation#

  1. Inventory your DMADRV usage

    Search your codebase for all DMADRV references:

    • #include "dmadrv.h" — files that use DMADRV

    • DMADRV_ — all API calls

    • ECODE_EMDRV_DMADRV — all error code checks

    • dmadrvDataSize — data size constants

    • dmadrvPeripheralSignal — peripheral signal constants

  2. Identify your transfer patterns

    Classify each DMA usage into one of these categories:

    • Basic M2P/P2MDMADRV_MemoryPeripheral() / DMADRV_PeripheralMemory() → straightforward migration

    • Ping-pongDMADRV_MemoryPeripheralPingPong() / DMADRV_PeripheralMemoryPingPong() → requires behavioral change review

    • Native LDMADMADRV_LdmaStartTransfer() → may require restructuring

    • PolledDMADRV_TransferDone() / DMADRV_TransferRemainingCount() → API change

  3. Assess ping-pong callback complexity

    • Check if any callbacks return false to stop ping-pong — this requires the most significant redesign

    • Check if any callbacks use the sequenceNo parameter — you will need application-level tracking

  4. Note custom configuration

    • Review dmadrv_config.h for any non-default settings, especially EMDRV_DMADRV_DMA_CH_PRIORITY (round-robin)

  5. Backup your project

Phase 2: Component Changes#

  1. Update your .slcp file

    Remove the legacy component and add the new ones:

    # Remove:
    # - id: dmadrv
    
    # Add:
    component:
      - id: dma_manager
      - id: dma_channel
  2. Configure round-robin (if applicable)

    If your dmadrv_config.h had EMDRV_DMADRV_DMA_CH_PRIORITY set to a value less than EMDRV_DMADRV_DMA_CH_COUNT (meaning some channels used round-robin scheduling), add the dma_manager_round_robin component to your .slcp:

    component:
      - id: dma_manager
      - id: dma_manager_round_robin
      - id: dma_channel

    Then set the number of round-robin channels in sl_dma_manager_round_robin_config.h:

    // Number of round-robin channels = EMDRV_DMADRV_DMA_CH_COUNT - EMDRV_DMADRV_DMA_CH_PRIORITY
    #define SL_DMA_MANAGER_ROUND_ROBIN_CHANNEL_COUNT 8

    Round-robin channels are automatically configured during DMA Manager initialization — no runtime API call is needed.

  3. Regenerate your project

    Using Simplicity Studio or SLC CLI:

    slc generate my_project.slcp

Phase 3: Header Changes#

Replace legacy includes with new ones in all affected files:

Remove

Add

#include "dmadrv.h"

#include "sl_dma_manager.h" and #include "sl_dma_channel.h"

#include "dmadrv_config.h"

Removed — round-robin is configured via the dma_manager_round_robin component and sl_dma_manager_round_robin_config.h

#include "ecode.h"

#include "sl_status.h"

Phase 4: Initialization Migration#

  1. Remove DMADRV_Init() calls

    DMA Manager is auto-initialized by SL Main via sl_platform_init()sl_dma_manager_instances_init(). Simply delete all DMADRV_Init() calls and any associated error checking.

  2. Remove DMADRV_DeInit() calls

    There is no global deinit equivalent. If you need per-channel cleanup, use sl_dma_channel_deinit() followed by sl_dma_manager_free_channel().

  3. Add channel handle declarations

    For each DMA channel your code uses, declare a handle:

    static sl_dma_channel_handle_t my_dma_handle;
  4. Initialize channel handles after allocation

    Immediately after allocating a channel, initialize the DMA Channel Driver handle:

    uint8_t channel;
    sl_status_t status;
    
    status = sl_dma_manager_allocate_channel(NULL, &channel);
    if (status != SL_STATUS_OK) {
      // Handle error
      return status;
    }
    
    status = sl_dma_channel_init(&my_dma_handle, NULL, channel,
                                  my_callback, my_user_data);
    if (status != SL_STATUS_OK) {
      sl_dma_manager_free_channel(NULL, channel);
      return status;
    }

Phase 5: API Call Migration#

Work through your code systematically, replacing each DMADRV API call with its new equivalent. Refer to the API Mapping Reference and the Code Transformation Examples for detailed guidance.

General pattern for each call site:

  1. Find the legacy DMADRV API call

  2. Look up the mapping in the API Mapping Reference

  3. Apply the transformation — see Code Transformation Examples

  4. Update error handling from Ecode_t to sl_status_t

  5. Compile and fix any errors

Phase 6: Ping-Pong Migration#

If you do not use ping-pong transfers, skip this phase.

The callback is still invoked on each buffer completion during ping-pong transfers, so buffer processing logic can remain in the callback. The key behavioral change is that the callback return type is void — you can no longer return false to stop the ping-pong. Instead, call sl_dma_channel_abort() to stop.

Migration strategies depending on your legacy usage:

Legacy Pattern

Recommended New Approach

Callback always returns true (infinite ping-pong)

Direct migration — change callback to void, remove return true

Callback processes buffers between iterations

Direct migration — keep buffer processing in the callback, change signature to void

Callback returns false after N iterations

Keep counter and buffer processing in callback; call sl_dma_channel_abort() instead of returning false

Callback returns false based on external condition

Check the condition in callback; call sl_dma_channel_abort() instead of returning false

See Code Transformation Examples — Ping-Pong Transfer for detailed before/after code.

Phase 7: Testing and Validation#

  1. Compile and fix all errors and warnings

  2. Search for remaining legacy symbols — none of these should remain in your code:

    • DMADRV_ — function calls

    • ECODE_EMDRV_DMADRV — error codes

    • dmadrv — includes

    • dmadrvDataSize — data size enums

    • dmadrvPeripheralSignal — peripheral signal constants

  3. Run basic functional tests:

    • Verify DMA auto-initialization succeeds (no manual init call needed)

    • Test basic M2P and P2M transfers

    • Verify callback invocation on transfer completion

    • Test error handling paths (invalid parameters, busy channels)

  4. Validate ping-pong transfers (if applicable):

    • Verify continuous looping operation

    • Verify sl_dma_channel_abort() stops the transfer correctly

    • Verify callback receives aborted=true after abort

  5. Performance validation:

    • Verify transfer throughput is comparable to DMADRV

    • Check interrupt latency if timing-sensitive


7. Code Transformation Examples#

Basic Initialization and Channel Setup#

Before (DMADRV):

#include "dmadrv.h"

static unsigned int dma_channel;

void app_dma_init(void)
{
  Ecode_t result;

  result = DMADRV_Init();
  if (result != ECODE_EMDRV_DMADRV_OK
      && result != ECODE_EMDRV_DMADRV_ALREADY_INITIALIZED) {
    // Handle error
    return;
  }

  result = DMADRV_AllocateChannel(&dma_channel, NULL);
  if (result != ECODE_EMDRV_DMADRV_OK) {
    // Handle error
    return;
  }
}

After (DMA Manager + DMA Channel Driver):

#include "sl_dma_manager.h"
#include "sl_dma_channel.h"

static sl_dma_channel_handle_t dma_handle;
static uint8_t dma_channel;

// Forward declaration
static void dma_callback(sl_dma_channel_handle_t *handle,
                          void *user_data,
                          bool error,
                          bool aborted);

void app_dma_init(void)
{
  sl_status_t status;

  // No DMADRV_Init() needed — DMA Manager auto-initializes via SL Main

  // Allocate a channel
  status = sl_dma_manager_allocate_channel(NULL, &dma_channel);
  if (status != SL_STATUS_OK) {
    // Handle error — e.g., SL_STATUS_NO_MORE_RESOURCE
    return;
  }

  // Initialize the DMA Channel Driver handle
  status = sl_dma_channel_init(&dma_handle, NULL, dma_channel,
                                dma_callback, NULL);
  if (status != SL_STATUS_OK) {
    sl_dma_manager_free_channel(NULL, dma_channel);
    return;
  }
}

Key changes:

  • DMADRV_Init() removed — auto-initialization via SL Main

  • DMADRV_AllocateChannel()sl_dma_manager_allocate_channel() + sl_dma_channel_init()

  • Ecode_tsl_status_t

  • Channel ID (unsigned int) → channel number (uint8_t) + handle (sl_dma_channel_handle_t)

  • Callback is registered during sl_dma_channel_init(), not at transfer time


Memory-to-Peripheral Transfer (UART TX)#

Before (DMADRV):

#include "dmadrv.h"

static bool tx_callback(unsigned int channel,
                         unsigned int sequenceNo,
                         void *userParam)
{
  (void)channel;
  (void)sequenceNo;
  // Signal application that TX is complete
  tx_complete = true;
  return true;
}

void send_data(const uint8_t *data, size_t length)
{
  DMADRV_MemoryPeripheral(dma_channel,
                           dmadrvPeripheralSignal_EUSART0_TXBL,
                           (void *)&(EUSART0->TXDATA),
                           (void *)data,
                           true,            // srcInc
                           (int)length,     // item count
                           dmadrvDataSize1, // byte transfers
                           tx_callback,
                           NULL);
}

After (DMA Manager + DMA Channel Driver):

#include "sl_dma_manager.h"
#include "sl_dma_channel.h"

static void tx_callback(sl_dma_channel_handle_t *handle,
                         void *user_data,
                         bool error,
                         bool aborted)
{
  (void)handle;
  (void)user_data;

  if (!error && !aborted) {
    // Signal application that TX is complete
    tx_complete = true;
  } else if (error) {
    // Handle DMA error — new capability: recoverable error handling
    tx_error = true;
  }
}

void send_data(const uint8_t *data, size_t length)
{
  // Set peripheral signal once (can be done during init if signal doesn't change)
  sl_dma_channel_set_peripheral_signal(&dma_handle,
                                        SL_DMA_SIGNAL_EUSART0_TXFL);

  // Submit transfer — callback registered at init time
  sl_status_t status;
  status = sl_dma_channel_submit_transfer_m2p(&dma_handle,
                                               (void *)data,
                                               (void *)&(EUSART0->TXDATA),
                                               length,  // bytes (same value for byte transfers)
                                               SL_DMA_CTRL_SIZE_BYTE,
                                               NULL);   // auto-allocate descriptor
  if (status != SL_STATUS_OK) {
    // Handle submission error
  }
}

Key changes:

  • Callback: bool return → void; add error/aborted checks

  • Peripheral signal: passed per-call → set once via sl_dma_channel_set_peripheral_signal()

  • Signal name: dmadrvPeripheralSignal_EUSART0_TXBLSL_DMA_SIGNAL_EUSART0_TXFL

  • srcInc parameter removed — M2P always increments source

  • Transfer size already in bytes (for dmadrvDataSize1), so value stays the same

  • Callback/user not passed at transfer time — registered during sl_dma_channel_init()

  • Pass NULL as descriptor → auto-allocated by driver


Peripheral-to-Memory Transfer (UART RX)#

Before (DMADRV):

void receive_data(uint8_t *buffer, size_t length)
{
  DMADRV_PeripheralMemory(dma_channel,
                           dmadrvPeripheralSignal_EUSART0_RXDATAV,
                           (void *)buffer,
                           (void *)&(EUSART0->RXDATA),
                           true,            // dstInc
                           (int)length,
                           dmadrvDataSize1,
                           rx_callback,
                           NULL);
}

After (DMA Manager + DMA Channel Driver):

void receive_data(uint8_t *buffer, size_t length)
{
  sl_dma_channel_set_peripheral_signal(&dma_handle,
                                        SL_DMA_SIGNAL_EUSART0_RXFL);

  sl_status_t status;
  status = sl_dma_channel_submit_transfer_p2m(&dma_handle,
                                               (void *)&(EUSART0->RXDATA),
                                               (void *)buffer,
                                               length,
                                               SL_DMA_CTRL_SIZE_BYTE,
                                               NULL);
  if (status != SL_STATUS_OK) {
    // Handle error
  }
}

Key changes:

  • Signal: dmadrvPeripheralSignal_EUSART0_RXDATAVSL_DMA_SIGNAL_EUSART0_RXFL

  • dstInc parameter removed — P2M always increments destination

  • Parameter order: in DMADRV it was (dst, src); in new API it is (reg, destination) — note the order


Memory-to-Memory Transfer#

Before (DMADRV):

#include "dmadrv.h"

void copy_memory(void *dst, const void *src, size_t length)
{
  LDMA_TransferCfg_t xfer_cfg = LDMA_TRANSFER_CFG_MEMORY();
  LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_M2M_BYTE(src, dst, length);

  DMADRV_LdmaStartTransfer(dma_channel, &xfer_cfg, &desc,
                             m2m_callback, NULL);
}

After (DMA Manager + DMA Channel Driver):

#include "sl_dma_channel.h"

void copy_memory(void *dst, const void *src, size_t length)
{
  sl_status_t status;
  status = sl_dma_channel_submit_transfer_m2m(&dma_handle,
                                               (void *)src,
                                               dst,
                                               length,  // bytes
                                               NULL);   // auto-allocate descriptor
  if (status != SL_STATUS_OK) {
    // Handle error
  }
}

Key changes:

  • No raw LDMA descriptors (LDMA_TransferCfg_t, LDMA_Descriptor_t) needed

  • M2M auto-selects optimal unit size based on source/destination alignment

  • No unit_size parameter for M2M (auto-detected)

  • Auto-segmentation handles transfers larger than the hardware descriptor limit


Ping-Pong Transfer#

The callback is still invoked on each buffer completion during ping-pong, so buffer processing logic stays in the callback. The main change is that the callback returns void instead of bool — to stop, call sl_dma_channel_abort() instead of returning false.

Before (DMADRV) — Callback returns bool to control ping-pong:

#include "dmadrv.h"

static uint8_t rx_buf0[BUFFER_SIZE];
static uint8_t rx_buf1[BUFFER_SIZE];
static volatile uint32_t buffers_received = 0;

static bool pingpong_callback(unsigned int channel,
                               unsigned int sequenceNo,
                               void *userParam)
{
  (void)channel;
  (void)userParam;

  // Process the completed buffer
  if (sequenceNo % 2 == 0) {
    process_buffer(rx_buf0, BUFFER_SIZE);
  } else {
    process_buffer(rx_buf1, BUFFER_SIZE);
  }

  buffers_received++;

  // Stop after receiving 10 buffers
  if (buffers_received >= 10) {
    return false;  // Stop ping-pong
  }
  return true;     // Continue ping-pong
}

void start_continuous_rx(void)
{
  DMADRV_PeripheralMemoryPingPong(dma_channel,
                                   dmadrvPeripheralSignal_EUSART0_RXDATAV,
                                   rx_buf0,
                                   rx_buf1,
                                   (void *)&(EUSART0->RXDATA),
                                   true,
                                   BUFFER_SIZE,
                                   dmadrvDataSize1,
                                   pingpong_callback,
                                   NULL);
}

After (DMA Manager + DMA Channel Driver) — Callback is void, abort to stop:

#include "sl_dma_manager.h"
#include "sl_dma_channel.h"

static uint8_t rx_buf0[BUFFER_SIZE];
static uint8_t rx_buf1[BUFFER_SIZE];
static volatile uint32_t buffers_received = 0;
static volatile bool current_buffer = false;  // Track which buffer completed

static void pingpong_callback(sl_dma_channel_handle_t *handle,
                               void *user_data,
                               bool error,
                               bool aborted)
{
  (void)user_data;

  if (error) {
    // Handle DMA error — new capability: recoverable error handling
    return;
  }

  if (aborted) {
    // Ping-pong was stopped via sl_dma_channel_abort()
    return;
  }

  // Callback IS invoked on each buffer completion — process the buffer
  // (no sequenceNo, use application-level tracking instead)
  if (current_buffer) {
    process_buffer(rx_buf1, BUFFER_SIZE);
  } else {
    process_buffer(rx_buf0, BUFFER_SIZE);
  }
  current_buffer = !current_buffer;

  buffers_received++;

  // Stop after receiving 10 buffers — call abort instead of returning false
  if (buffers_received >= 10) {
    sl_dma_channel_abort(handle);  // Replaces "return false"
  }
}

void start_continuous_rx(void)
{
  sl_dma_channel_set_peripheral_signal(&dma_handle,
                                        SL_DMA_SIGNAL_EUSART0_RXFL);

  sl_status_t status;
  status = sl_dma_channel_submit_ping_pong_transfer_p2m(
               &dma_handle,
               (void *)&(EUSART0->RXDATA),
               rx_buf0,
               rx_buf1,
               BUFFER_SIZE,          // bytes
               SL_DMA_CTRL_SIZE_BYTE,
               NULL);                // auto-allocate descriptors

  if (status != SL_STATUS_OK) {
    // Handle error
  }
}

Key changes:

  • Callback return type: boolvoid; callback is still called on each buffer completion

  • Stop mechanism: return falsesl_dma_channel_abort(handle) from within the callback

  • sequenceNo removed — use application-level tracking (current_buffer toggle) to determine which buffer completed

  • Buffer processing stays in the callback — no need to move it to a separate monitoring mechanism

  • Explicit error and aborted flag handling added

  • Signal name: RXDATAVRXFL; set once before transfer

  • dstInc parameter removed

Alternative approach for finite-count transfers: If you only needed a fixed number of ping-pong iterations (like the 10-buffer example above), consider using sl_dma_channel_submit_transfer_list() with a linear list of transfers instead.


Polled Transfer Completion#

Before (DMADRV):

DMADRV_MemoryPeripheral(channel, signal, dst, src, true, len,
                         dmadrvDataSize1, NULL, NULL);

bool done;
do {
  DMADRV_TransferDone(channel, &done);
} while (!done);

int remaining;
DMADRV_TransferRemainingCount(channel, &remaining);

After (DMA Manager + DMA Channel Driver):

sl_dma_channel_submit_transfer_m2p(&handle, src, dst, len,
                                    SL_DMA_CTRL_SIZE_BYTE, NULL);

sl_dma_channel_status_t status;
do {
  sl_dma_channel_get_status(&handle, &status);
} while (status.active);

// Bytes completed (not items remaining)
uint32_t completed = status.bytes_completed;
uint32_t remaining_bytes = len - completed;

Key changes:

  • TransferDone() → check !status.active from get_status()

  • TransferRemainingCount() → compute from bytes_completed

  • Units: items remaining → bytes completed


Transfer Control (Pause/Resume/Stop)#

Before (DMADRV):

DMADRV_PauseTransfer(channel);
// ... do something ...
DMADRV_ResumeTransfer(channel);
// ... later ...
DMADRV_StopTransfer(channel);

After (DMA Manager + DMA Channel Driver):

sl_dma_channel_suspend(&handle);
// ... do something ...
sl_dma_channel_resume(&handle);
// ... later ...
sl_dma_channel_abort(&handle);
// Note: abort triggers callback with aborted=true for each pending descriptor

Key change: sl_dma_channel_abort() triggers callbacks — make sure your callback handles the aborted=true case.


Channel Cleanup and Deallocation#

Before (DMADRV):

DMADRV_FreeChannel(channel);
DMADRV_DeInit();

After (DMA Manager + DMA Channel Driver):

// Abort any active transfer first (if needed)
sl_dma_channel_abort(&handle);

// Deinit the DMA Channel Driver handle
sl_dma_channel_deinit(&handle);

// Free the channel in DMA Manager
sl_dma_manager_free_channel(NULL, dma_channel);

// No DeInit needed — DMA Manager stays initialized

Key changes:

  • Must deinit the DMA Channel Driver handle before freeing the channel

  • No global DeInit() — DMA Manager persists for the lifetime of the application


Error Handling#

Before (DMADRV):

Ecode_t result;

result = DMADRV_AllocateChannel(&channel, NULL);
if (result == ECODE_EMDRV_DMADRV_CHANNELS_EXHAUSTED) {
  // No channels available
} else if (result == ECODE_EMDRV_DMADRV_NOT_INITIALIZED) {
  // Not initialized
} else if (result != ECODE_EMDRV_DMADRV_OK) {
  // Other error
}

After (DMA Manager + DMA Channel Driver):

sl_status_t status;

status = sl_dma_manager_allocate_channel(NULL, &channel);
switch (status) {
  case SL_STATUS_OK:
    // Success
    break;
  case SL_STATUS_NO_MORE_RESOURCE:
    // No channels available
    break;
  case SL_STATUS_NOT_INITIALIZED:
    // Not initialized (should not happen with auto-init)
    break;
  default:
    // Other error
    break;
}

Key change: Use standard sl_status_t codes — consistent with all other Silicon Labs platform components.


Halfword Transfer (Size Conversion Example)#

Before (DMADRV):

// Transfer 100 halfword (16-bit) items from memory to peripheral
DMADRV_MemoryPeripheral(channel, signal, dst, src, true,
                         100,              // 100 items
                         dmadrvDataSize2,  // halfword
                         callback, user);

After (DMA Manager + DMA Channel Driver):

// Transfer 200 bytes (100 halfwords × 2 bytes each)
sl_dma_channel_submit_transfer_m2p(&handle, src, dst,
                                    200,                  // 100 * 2 = 200 bytes
                                    SL_DMA_CTRL_SIZE_HALF,
                                    NULL);

Key change: Convert item count to byte count: 200 = 100 items × 2 bytes/halfword.


Complete Application Example#

Before (DMADRV) — UART TX/RX with DMA:

#include "dmadrv.h"

static unsigned int tx_channel;
static unsigned int rx_channel;
static volatile bool tx_done = false;
static volatile bool rx_done = false;

static bool tx_cb(unsigned int ch, unsigned int seq, void *user)
{
  (void)ch; (void)seq; (void)user;
  tx_done = true;
  return true;
}

static bool rx_cb(unsigned int ch, unsigned int seq, void *user)
{
  (void)ch; (void)seq; (void)user;
  rx_done = true;
  return true;
}

void uart_dma_init(void)
{
  DMADRV_Init();
  DMADRV_AllocateChannel(&tx_channel, NULL);
  DMADRV_AllocateChannel(&rx_channel, NULL);
}

void uart_dma_send(const uint8_t *data, size_t len)
{
  tx_done = false;
  DMADRV_MemoryPeripheral(tx_channel,
                           dmadrvPeripheralSignal_EUSART0_TXBL,
                           (void *)&EUSART0->TXDATA,
                           (void *)data, true, (int)len,
                           dmadrvDataSize1, tx_cb, NULL);
}

void uart_dma_receive(uint8_t *buf, size_t len)
{
  rx_done = false;
  DMADRV_PeripheralMemory(rx_channel,
                           dmadrvPeripheralSignal_EUSART0_RXDATAV,
                           (void *)buf,
                           (void *)&EUSART0->RXDATA,
                           true, (int)len,
                           dmadrvDataSize1, rx_cb, NULL);
}

void uart_dma_cleanup(void)
{
  DMADRV_FreeChannel(tx_channel);
  DMADRV_FreeChannel(rx_channel);
  DMADRV_DeInit();
}

After (DMA Manager + DMA Channel Driver) — UART TX/RX with DMA:

#include "sl_dma_manager.h"
#include "sl_dma_channel.h"

static sl_dma_channel_handle_t tx_handle;
static sl_dma_channel_handle_t rx_handle;
static uint8_t tx_channel;
static uint8_t rx_channel;
static volatile bool tx_done = false;
static volatile bool rx_done = false;
static volatile bool dma_error = false;

static void tx_cb(sl_dma_channel_handle_t *handle, void *user_data,
                   bool error, bool aborted)
{
  (void)handle;
  (void)user_data;

  if (!error && !aborted) {
    tx_done = true;
  } else {
    dma_error = true;
  }
}

static void rx_cb(sl_dma_channel_handle_t *handle, void *user_data,
                   bool error, bool aborted)
{
  (void)handle;
  (void)user_data;

  if (!error && !aborted) {
    rx_done = true;
  } else {
    dma_error = true;
  }
}

void uart_dma_init(void)
{
  sl_status_t status;

  // No DMADRV_Init() — DMA Manager auto-initialized by SL Main

  // Allocate and initialize TX channel
  status = sl_dma_manager_allocate_channel(NULL, &tx_channel);
  if (status != SL_STATUS_OK) { return; }

  status = sl_dma_channel_init(&tx_handle, NULL, tx_channel, tx_cb, NULL);
  if (status != SL_STATUS_OK) {
    sl_dma_manager_free_channel(NULL, tx_channel);
    return;
  }
  sl_dma_channel_set_peripheral_signal(&tx_handle,
                                        SL_DMA_SIGNAL_EUSART0_TXFL);

  // Allocate and initialize RX channel
  status = sl_dma_manager_allocate_channel(NULL, &rx_channel);
  if (status != SL_STATUS_OK) { return; }

  status = sl_dma_channel_init(&rx_handle, NULL, rx_channel, rx_cb, NULL);
  if (status != SL_STATUS_OK) {
    sl_dma_manager_free_channel(NULL, rx_channel);
    return;
  }
  sl_dma_channel_set_peripheral_signal(&rx_handle,
                                        SL_DMA_SIGNAL_EUSART0_RXFL);
}

void uart_dma_send(const uint8_t *data, size_t len)
{
  tx_done = false;
  sl_status_t status;
  status = sl_dma_channel_submit_transfer_m2p(&tx_handle,
                                               (void *)data,
                                               (void *)&EUSART0->TXDATA,
                                               len,
                                               SL_DMA_CTRL_SIZE_BYTE,
                                               NULL);
  if (status != SL_STATUS_OK) {
    dma_error = true;
  }
}

void uart_dma_receive(uint8_t *buf, size_t len)
{
  rx_done = false;
  sl_status_t status;
  status = sl_dma_channel_submit_transfer_p2m(&rx_handle,
                                               (void *)&EUSART0->RXDATA,
                                               (void *)buf,
                                               len,
                                               SL_DMA_CTRL_SIZE_BYTE,
                                               NULL);
  if (status != SL_STATUS_OK) {
    dma_error = true;
  }
}

void uart_dma_cleanup(void)
{
  // Deinit channel driver handles, then free channels
  sl_dma_channel_deinit(&tx_handle);
  sl_dma_manager_free_channel(NULL, tx_channel);

  sl_dma_channel_deinit(&rx_handle);
  sl_dma_manager_free_channel(NULL, rx_channel);

  // No DMADRV_DeInit() equivalent needed
}

Key changes in the complete example:

  • No DMADRV_Init() / DMADRV_DeInit()

  • Each channel requires: allocate → init handle → set signal (once)

  • Callbacks use void return with error/aborted flags

  • Signal names updated: TXBLTXFL, RXDATAVRXFL

  • Cleanup: deinit handle first, then free channel

  • Full sl_status_t error handling throughout


8. Testing Your Migration#

Migration Validation Checklist#

  • Project compiles without errors or warnings

  • No legacy #include "dmadrv.h" includes remain

  • No DMADRV_ API calls remain in code

  • No ECODE_EMDRV_DMADRV error codes remain

  • No dmadrvDataSize or dmadrvPeripheralSignal constants remain

  • All callbacks use the new void signature with error/aborted parameters

  • Error handling uses sl_status_t

  • Basic M2P and P2M transfers complete successfully

  • Ping-pong transfers operate correctly (if applicable)

  • Abort/stop behavior triggers callbacks as expected

  • Performance (throughput, latency) is acceptable

Test Scenarios#

Test Case

Description

Expected Result

Auto-init

SL Main initializes DMA Manager

No errors on first channel allocation

Channel allocate

Allocate a DMA channel

SL_STATUS_OK; valid channel number returned

Channel allocate (exhausted)

Allocate more channels than available

SL_STATUS_NO_MORE_RESOURCE

Channel reserve (specific)

Reserve a specific channel number

SL_STATUS_OK or SL_STATUS_NOT_AVAILABLE if already taken

M2P transfer

Memory-to-peripheral byte transfer

Transfer completes; callback fires with error=false, aborted=false

P2M transfer

Peripheral-to-memory transfer

Transfer completes; callback fires correctly

M2M transfer

Memory-to-memory copy

Data correctly copied; callback fires

Transfer abort

Abort an active transfer

Channel stops; callback fires with aborted=true

Suspend/Resume

Pause then resume a transfer

Transfer pauses and resumes correctly

Ping-pong start

Start continuous ping-pong

Transfer loops between two buffers

Ping-pong abort

Abort a running ping-pong

Looping stops; callback fires with aborted=true

Error callback

Simulate a DMA error

Callback fires with error=true

Channel cleanup

Deinit handle and free channel

Resources released cleanly

Multiple channels

Two or more channels operating simultaneously

No interference between channels


9. Troubleshooting#

Common Migration Issues#

Issue: Compilation error — undefined reference to DMADRV_*#

Symptom:

undefined reference to `DMADRV_Init'
undefined reference to `DMADRV_AllocateChannel'

Cause: DMADRV component was removed but API calls were not migrated.

Solution: Replace all DMADRV_* calls with their new equivalents — see API Mapping Reference.


Issue: Compilation error — ECODE_EMDRV_DMADRV_OK undeclared#

Symptom:

error: 'ECODE_EMDRV_DMADRV_OK' undeclared

Cause: Legacy error codes are not defined when using the new components.

Solution: Replace with sl_status_t codes — see Error Code Mapping.


Issue: Compilation error — implicit declaration of dmadrvPeripheralSignal_*#

Symptom:

error: 'dmadrvPeripheralSignal_EUSART0_TXBL' undeclared

Cause: Legacy peripheral signal constants no longer exist.

Solution: Use the new SL_DMA_SIGNAL_* constants from sl_device_dma.h. Note the naming changes, especially for EUSART signals (TXBLTXFL, RXDATAVRXFL).


Issue: Ping-pong transfer does not stop when expected#

Symptom: Ping-pong transfer continues running even though the stop condition was reached.

Cause: In DMADRV, you could return false from the callback to stop the ping-pong. In the new DMA Channel Driver, the callback returns void and cannot control the transfer lifecycle.

Solution: Call sl_dma_channel_abort() from within the callback (or from another context) when you want to stop the ping-pong transfer:

void my_callback(sl_dma_channel_handle_t *handle, void *user_data,
                  bool error, bool aborted) {
  if (!error && !aborted) {
    if (should_stop()) {
      sl_dma_channel_abort(handle);  // Replaces "return false"
    }
  }
}

Issue: sl_dma_channel_deinit() returns SL_STATUS_BUSY#

Symptom: Cannot deinit the channel handle.

Cause: The DMA channel is still enabled or has an active transfer.

Solution: Call sl_dma_channel_abort() before sl_dma_channel_deinit():

sl_dma_channel_abort(&handle);       // Stop any active transfer
sl_dma_channel_deinit(&handle);      // Now safe to deinit
sl_dma_manager_free_channel(NULL, ch);

Issue: Transfer size mismatch for halfword/word transfers#

Symptom: Transfer completes but data is truncated or only partially transferred.

Cause: The legacy DMADRV used item count for len, while the new DMA Channel Driver uses byte count for size. If you passed 100 for 100 halfword items, you now need 200 (100 × 2 bytes).

Solution: Convert item count to byte count using the multiplier for the data size:

  • dmadrvDataSize1 (byte): size = len × 1

  • dmadrvDataSize2 (halfword): size = len × 2

  • dmadrvDataSize4 (word): size = len × 4


Issue: Assertion failure during sl_dma_channel_init()#

Symptom: Assertion triggers inside sl_dma_channel_init().

Cause: The channel number passed may not have been allocated, or the handle pointer is NULL.

Solution: Ensure you allocate the channel via sl_dma_manager_allocate_channel() or sl_dma_manager_reserve_channel() before calling sl_dma_channel_init().


Error Code Quick Reference#

Legacy Error

New Error

When It Occurs

ECODE_EMDRV_DMADRV_OK

SL_STATUS_OK

Operation succeeded

ECODE_EMDRV_DMADRV_PARAM_ERROR

SL_STATUS_INVALID_PARAMETER

Invalid argument (NULL pointer, bad alignment, zero size)

ECODE_EMDRV_DMADRV_NOT_INITIALIZED

N/A — auto-initialized

Not applicable with auto-init

ECODE_EMDRV_DMADRV_ALREADY_INITIALIZED

SL_STATUS_ALREADY_INITIALIZED

sl_dma_manager_init() called more than once

ECODE_EMDRV_DMADRV_CHANNELS_EXHAUSTED

SL_STATUS_NO_MORE_RESOURCE

All DMA channels are allocated

ECODE_EMDRV_DMADRV_IN_USE

SL_STATUS_BUSY

Channel is enabled or has active transfers

ECODE_EMDRV_DMADRV_ALREADY_FREED

N/A

Not explicitly returned by DMA Manager

ECODE_EMDRV_DMADRV_CH_NOT_ALLOCATED

SL_STATUS_NOT_AVAILABLE

Trying to free/use an unallocated channel

FAQ#

Q: Can I use both DMADRV and the new DMA Channel Driver simultaneously?

A: It is not recommended to mix the two for the same DMA channel. However, during the deprecation period (2026.6.0–2027.6.0), both components exist in the SDK and can coexist if they operate on different channels. The recommended approach is to migrate all DMADRV usage at once.

Q: Do I need to call sl_dma_manager_init() manually?

A: No. The dma_manager_init component (automatically included when you add dma_manager to your .slcp) contributes sl_dma_manager_instances_init() to the generated sl_platform_init() function, which is called during the SL Main initialization process. The default LDMA peripheral instance is initialized automatically.

Q: What if I used DMADRV_LdmaStartTransfer() with complex linked descriptors?

A: Use sl_dma_channel_submit_transfer_list() which provides a higher-level abstraction. Define your transfers as a linked list of sl_dma_channel_transfer_t structures. The driver handles descriptor allocation and linking automatically. For transfers larger than the hardware descriptor capacity, auto-segmentation splits them into multiple descriptors.

Q: My ping-pong callback processed buffers — how do I replicate this?

A: The callback is still invoked on each buffer completion during ping-pong transfers, so you can keep your buffer processing logic in the callback. The only change is that the callback returns void instead of bool. Use an application-level variable to track which buffer completed (since sequenceNo is no longer provided), and call sl_dma_channel_abort() instead of returning false when you want to stop.

Q: Will my existing dmadrv_config.h settings carry over?

A: Only the round-robin configuration has a new equivalent. Add the dma_manager_round_robin component to your .slcp and set SL_DMA_MANAGER_ROUND_ROBIN_CHANNEL_COUNT in sl_dma_manager_round_robin_config.h. Round-robin channels are configured automatically during DMA Manager initialization — no runtime API call is needed. The IRQ priority and channel count settings are no longer needed.


10. Additional Resources#

Related Documentation#

Support#


Migration guide for DMADRV to DMA Manager + DMA Channel Driver — Silicon Labs Gecko Platform SDK 2026.6.0