DMA Manager#
Overview#
The DMA Manager is a platform service module responsible for initializing and enabling the DMA peripheral(s) on the device, managing DMA interrupts, configuring channel prioritization (for example round-robin arbitration), and dynamically allocating DMA channels and sync bits at runtime.
Each DMA peripheral managed by the DMA Manager is associated with an ::sl_dma_handle_t variable. A default handle is provided and can be retrieved through sl_dma_manager_get_default_handle().
The DMA Manager is the single entry point for DMA channel ownership: any application or driver that needs a DMA channel must request it from the DMA Manager rather than touching the DMA peripheral directly. Once a channel has been allocated, the application is free to drive transfers on it through the DMA Channel Driver (its companion higher-level API) or directly through the low level sl_hal_ldma HAL, depending on the level of control needed. In either case the channel itself must always come from the DMA Manager.
Initialization#
When the dma_manager_init component is included in the project, all configured DMA peripheral instances are initialized automatically during system initialization through sl_dma_manager_instances_init(). Applications that do not use the SL Main component to auto-init can call sl_dma_manager_init() directly, passing either a user-allocated handle or NULL to let the DMA Manager allocate one internally.
The following snippet shows a manual initialization of the default DMA peripheral exposed by the HAL, with a caller-allocated handle:
static sl_dma_handle_t my_dma_handle;
sl_status_t status;
// Pass NULL as DMA peripheral to use the device's default DMA peripheral.
status = sl_dma_manager_init(&my_dma_handle, NULL);
if (status != SL_STATUS_OK) {
// Process the error condition.
}
Examples#
Channel Allocation and Release#
The most common pattern is to allocate a channel from the default DMA Manager handle, use it, and release it once the transfer is done. Passing NULL as the DMA handle automatically targets the default handle of the default DMA peripheral:
uint8_t channel_nbr;
sl_status_t status;
status = sl_dma_manager_allocate_channel(NULL, &channel_nbr);
if (status != SL_STATUS_OK) {
// Process the error condition (for example SL_STATUS_NO_MORE_RESOURCE).
}
// Use the channel, e.g. through the DMA Channel Driver or sl_hal_ldma.
// ...
status = sl_dma_manager_free_channel(NULL, channel_nbr);
if (status != SL_STATUS_OK) {
// Process the error condition.
}
If the application needs to operate on an explicit handle (for example to query or share it with another module), the default handle can be retrieved with sl_dma_manager_get_default_handle():
sl_dma_handle_t *dma_handle = NULL;
uint8_t channel_nbr;
sl_status_t status;
status = sl_dma_manager_get_default_handle(&dma_handle);
if (status != SL_STATUS_OK || dma_handle == NULL) {
// Process the error condition (no default handle initialized yet).
}
status = sl_dma_manager_allocate_channel(dma_handle, &channel_nbr);
if (status != SL_STATUS_OK) {
// Process the error condition.
}
// ... use the channel ...
sl_dma_manager_free_channel(dma_handle, channel_nbr);
Channel Allocation with Properties#
sl_dma_manager_allocate_channel_with_properties() lets the caller request specific channel features. The example below requests a high-priority channel that supports interleaved transfers:
uint8_t channel_nbr;
uint32_t properties = SL_DMA_CHANNEL_HIGH_PRIORITY
| SL_DMA_CHANNEL_SUPPORTS_INTERLEAVING;
sl_status_t status;
status = sl_dma_manager_allocate_channel_with_properties(NULL,
properties,
&channel_nbr);
if (status != SL_STATUS_OK) {
// No channel matching the requested properties is available.
}
Note that ::SL_DMA_CHANNEL_HIGH_PRIORITY and ::SL_DMA_CHANNEL_USES_ROUND_ROBIN are mutually exclusive.
Reserving a Specific Channel#
When a deterministic channel number is required (for example to match a fixed peripheral signal mapping), sl_dma_manager_reserve_channel() locks a specific channel out of the dynamic allocation pool. The channel is released with the same sl_dma_manager_free_channel() call as an allocated channel:
sl_status_t status;
status = sl_dma_manager_reserve_channel(NULL, 3);
if (status == SL_STATUS_NOT_AVAILABLE) {
// Channel 3 is already reserved or allocated by someone else.
} else if (status != SL_STATUS_OK) {
// Process the error condition.
}
// ... use channel 3 ...
sl_dma_manager_free_channel(NULL, 3);
SYNC Bit Allocation#
SYNC bits used to synchronize DMA channels with peripheral or software events are managed the same way as channels:
uint8_t sync_nbr;
sl_status_t status;
status = sl_dma_manager_allocate_sync(NULL, &sync_nbr);
if (status != SL_STATUS_OK) {
// Process the error condition (for example SL_STATUS_NO_MORE_RESOURCE).
}
// ... use the SYNC bit ...
sl_dma_manager_free_sync(NULL, sync_nbr);
IRQ Callback and User Data#
When driving a channel directly through the sl_hal_ldma HAL, the application can register a per-channel IRQ callback so the DMA Manager dispatches the IRQ to it on Series 2 (and forwards the registration to the Interrupt Manager on Series 3). A user-data pointer can be associated with the channel and retrieved from inside the callback through sl_dma_manager_retrieve_current_channel_user_data():
static volatile bool transfer_done;
static void my_dma_irq_callback(void)
{
uint8_t channel_nbr;
void *user_data;
if (sl_dma_manager_retrieve_current_channel_user_data(&channel_nbr,
&user_data)
== SL_STATUS_OK) {
// 'user_data' is the pointer registered for 'channel_nbr'.
*((volatile bool *)user_data) = true;
}
}
void start_dma_transfer(void)
{
uint8_t channel_nbr;
sl_dma_manager_allocate_channel(NULL, &channel_nbr);
sl_dma_manager_register_channel_user_data(NULL,
channel_nbr,
(void *)&transfer_done);
sl_dma_manager_register_channel_irq_callback(NULL,
channel_nbr,
my_dma_irq_callback);
// Configure and start the transfer through sl_hal_ldma.
// ...
}
The DMA Channel Driver registers and dispatches its own per-channel callbacks; this flow is therefore only needed for users that drive the channel directly through the sl_hal_ldma HAL.
Modules#
Typedefs#
Functions#
Initializes the DMA Manager for a given DMA peripheral.
Gets the default DMA handle.
Allocates a DMA channel.
Allocates a DMA channel with the requested properties.
Reserves a specific DMA channel.
Frees a previously allocated or reserved DMA channel.
Allocates a DMA SYNC bit.
Frees a previously allocated DMA SYNC bit.
Registers an IRQ callback for a DMA channel.
Registers user data for a DMA channel.
Retrieves the channel number and user data for the DMA channel currently being serviced in the DMA Manager interrupt dispatch context.
Gets the pending error bitmap for a DMA channel.
Clears the pending errors for a DMA channel.
Macros#
Typedef Documentation#
sl_dma_manager_channel_irq_callback_t#
typedef void(* sl_dma_manager_channel_irq_callback_t) (void) )(void)
Function Documentation#
sl_dma_manager_init#
sl_status_t sl_dma_manager_init (sl_dma_handle_t * dma_handle, sl_peripheral_dma_t dma_peripheral)
Initializes the DMA Manager for a given DMA peripheral.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [in] | dma_handle | Pointer to a caller-allocated DMA handle to initialize. If NULL, the DMA Manager allocates the handle internally and uses it as the default handle for the targeted DMA peripheral. |
| sl_peripheral_dma_t | [in] | dma_peripheral | DMA peripheral to associate with the handle. If NULL, the default DMA peripheral exposed by the HAL is used. |
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
sl_dma_manager_get_default_handle#
sl_status_t sl_dma_manager_get_default_handle (sl_dma_handle_t ** dma_handle)
Gets the default DMA handle.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t ** | [out] | dma_handle | Address of a variable that will receive the default DMA handle. Must not be NULL. The variable is set to NULL if no default handle has been initialized yet. |
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
sl_dma_manager_allocate_channel#
sl_status_t sl_dma_manager_allocate_channel (sl_dma_handle_t * dma_handle, uint8_t * channel_nbr)
Allocates a DMA channel.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [in] | dma_handle | Pointer to the DMA handle to allocate from. If NULL, the default handle is used. |
| uint8_t * | [out] | channel_nbr | Pointer to a variable that will receive the allocated channel number. Must not be NULL. |
Selects the next available channel from the targeted DMA peripheral and marks it as allocated. When the round-robin component is enabled, this function delegates to sl_dma_manager_allocate_channel_with_properties() with no requested properties; the lowest priority non round-robin channel available is then returned.
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
sl_dma_manager_allocate_channel_with_properties#
sl_status_t sl_dma_manager_allocate_channel_with_properties (sl_dma_handle_t * dma_handle, uint32_t channel_properties, uint8_t * channel_nbr)
Allocates a DMA channel with the requested properties.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [out] | dma_handle | Pointer to a variable that will receive the allocated channel number. Must not be NULL. |
| uint32_t | [in] | channel_properties | Bitwise OR of the desired channel properties:
|
| uint8_t * | N/A | channel_nbr |
Same as sl_dma_manager_allocate_channel() but lets the caller request specific channel features.
::SL_DMA_CHANNEL_HIGH_PRIORITY and ::SL_DMA_CHANNEL_USES_ROUND_ROBIN are mutually exclusive.
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
sl_dma_manager_reserve_channel#
sl_status_t sl_dma_manager_reserve_channel (sl_dma_handle_t * dma_handle, uint8_t channel_nbr)
Reserves a specific DMA channel.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [in] | dma_handle | Pointer to the DMA handle. If NULL, the default handle is used. |
| uint8_t | [in] | channel_nbr | Channel number to reserve. |
Reserves the channel identified by channel_nbr so that subsequent allocations through sl_dma_manager_allocate_channel() or sl_dma_manager_allocate_channel_with_properties() will not return it.
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise. SL_STATUS_NOT_AVAILABLE is returned when the channel is already reserved or allocated.
sl_dma_manager_free_channel#
sl_status_t sl_dma_manager_free_channel (sl_dma_handle_t * dma_handle, uint8_t channel_nbr)
Frees a previously allocated or reserved DMA channel.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [in] | dma_handle | Pointer to the DMA handle. If NULL, the default handle is used. |
| uint8_t | [in] | channel_nbr | Channel number to free. |
Releases the channel back to the DMA Manager and clears its associated IRQ callback and user data, if any.
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
sl_dma_manager_allocate_sync#
sl_status_t sl_dma_manager_allocate_sync (sl_dma_handle_t * dma_handle, uint8_t * sync_nbr)
Allocates a DMA SYNC bit.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [in] | dma_handle | Pointer to the DMA handle. If NULL, the default handle is used. |
| uint8_t * | [out] | sync_nbr | Pointer to a variable that will receive the allocated SYNC bit number. Must not be NULL. |
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
sl_dma_manager_free_sync#
sl_status_t sl_dma_manager_free_sync (sl_dma_handle_t * dma_handle, uint8_t sync_nbr)
Frees a previously allocated DMA SYNC bit.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [in] | dma_handle | Pointer to the DMA handle. If NULL, the default handle is used. |
| uint8_t | [in] | sync_nbr | SYNC bit number to free. |
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
sl_dma_manager_register_channel_irq_callback#
sl_status_t sl_dma_manager_register_channel_irq_callback (sl_dma_handle_t * dma_handle, uint8_t channel_nbr, sl_dma_manager_channel_irq_callback_t callback)
Registers an IRQ callback for a DMA channel.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [in] | dma_handle | Pointer to the DMA handle. If NULL, the default handle is used. |
| uint8_t | [in] | channel_nbr | Channel number the callback is registered for. |
| sl_dma_manager_channel_irq_callback_t | [in] | callback | Function to be invoked from the DMA channel IRQ context. Pass NULL to remove a previously registered callback. |
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
Note
On Series 2 devices, all DMA channels share a single IRQ line and the DMA Manager owns the central IRQ dispatcher; callbacks must therefore be registered through this function. On Series 3 devices, each channel has its own IRQ line and callbacks should normally be registered directly through the Interrupt Manager. Calling this function on Series 3 simply forwards the registration to the Interrupt Manager.
This function is intended for users that drive the DMA channel directly through the sl_hal_ldma HAL. The DMA Channel Driver registers and dispatches its own per-channel callbacks and does not require this function.
sl_dma_manager_register_channel_user_data#
sl_status_t sl_dma_manager_register_channel_user_data (sl_dma_handle_t * dma_handle, uint8_t channel_nbr, void * user_data)
Registers user data for a DMA channel.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| sl_dma_handle_t * | [in] | dma_handle | Pointer to the DMA handle. If NULL, the default handle is used. |
| uint8_t | [in] | channel_nbr | Channel number the user data is registered for. |
| void * | [in] | user_data | Pointer to user data to associate with the channel. Pass NULL to remove previously registered user data. |
The registered pointer is later returned to the IRQ callback through sl_dma_manager_retrieve_current_channel_user_data(), allowing the callback to share context with the code that allocated the channel.
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise.
sl_dma_manager_retrieve_current_channel_user_data#
sl_status_t sl_dma_manager_retrieve_current_channel_user_data (uint8_t * channel_nbr, void ** user_data)
Retrieves the channel number and user data for the DMA channel currently being serviced in the DMA Manager interrupt dispatch context.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| uint8_t * | [out] | channel_nbr | Pointer to a variable that will receive the channel number currently being serviced. |
| void ** | [out] | user_data | Pointer to a variable that will receive the user data associated with the channel. |
Designed to be called from within a DMA channel IRQ callback registered via sl_dma_manager_register_channel_irq_callback(). The returned user data is the one previously registered through sl_dma_manager_register_channel_user_data() for that channel.
Returns
0 (SL_STATUS_OK) if successful. Error code otherwise. SL_STATUS_INVALID_STATE is returned when called outside the DMA Manager interrupt dispatch context.
sl_dma_manager_get_pending_errors#
uint32_t sl_dma_manager_get_pending_errors (uint8_t channel_nbr)
Gets the pending error bitmap for a DMA channel.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| uint8_t | [in] | channel_nbr | Channel number to query. |
Returns
Bitmap of pending errors for the channel. The exact bit layout is HAL-specific.
sl_dma_manager_clear_pending_errors#
void sl_dma_manager_clear_pending_errors (uint8_t channel_nbr)
Clears the pending errors for a DMA channel.
| Type | Direction | Argument Name | Description |
|---|---|---|---|
| uint8_t | [in] | channel_nbr | Channel number whose pending errors must be cleared. |
The function is idempotent and safe to call multiple times.