15. DMA Manager Component
15.1. Overview
The DMA Manager component provides a unified resource management layer on top of the low-level DMA driver, responsible for the allocation, configuration, and lifecycle management of DMA channels. It supports multiple DMA instances (HDMA, XDMA, etc.) and offers interrupt callback registration and channel control capabilities. The following are the key features of this component:
Centralized DMA channel resource management
Automatically allocates and releases DMA channels, avoiding manual management and conflicts.
Supports requesting a channel from a specified DMA instance.
Unified channel configuration interface
Encapsulates DMA channel configuration (source/destination address, transfer width, burst size, work mode, etc.) through the
dma_mgr_chn_conf_tstructure, providing a one-time setup APIdma_mgr_setup_channel.
Flexible interrupt callback mechanism
Supports separate registration of transfer complete (TC), half transfer complete (Half TC), error, and abort callbacks.
Supports advanced DMAV2 features
Infinite loop transfer, custom burst size, handshake options, byte order swap, etc.
15.3. API Call Flow Introduction
15.3.1. Initialize DMA Manager
Call the
dma_mgr_initAPI to initialize the DMA manager context. This step must be performed before any DMA operations.Prototype of the
dma_mgr_initAPI:void dma_mgr_init(void);
15.3.2. Request DMA Resource
Call the
dma_mgr_request_resourceAPI to request an available DMA channel. The DMA manager automatically finds an unallocated channel among all DMA instances.Prototype of the
dma_mgr_request_resourceAPI:hpm_stat_t dma_mgr_request_resource(dma_resource_t *resource);
Return Values:
status_success: DMA channel successfully allocated.status_invalid_argument: Theresourceparameter is NULL.status_dma_mgr_no_resource: All DMA channels are already occupied.
If you need to request a DMA channel from a specified DMA instance (e.g., HPM_HDMA or HPM_XDMA), use:
hpm_stat_t dma_mgr_request_specified_resource(dma_resource_t *resource, DMA_Type *base);
Example: Request a DMA channel.
dma_resource_t resource; if (dma_mgr_request_resource(&resource) != status_success) { printf("Failed to request DMA resource\n"); return; } printf("DMA channel allocated: instance=%p, channel=%d\n", resource.base, resource.channel);
15.3.3. Get Default Channel Configuration
Call the
dma_mgr_get_default_chn_configAPI to fill thedma_mgr_chn_conf_tstructure with default values. You can then modify individual fields as needed.Prototype of the
dma_mgr_get_default_chn_configAPI:void dma_mgr_get_default_chn_config(dma_mgr_chn_conf_t *config);
Default values:
DMAMUX disabled, DMAMUX source = 0
Low priority
Source burst size = 1 transfer
Source/Destination work mode = Normal
Source/Destination width = Byte
Source/Destination address control = Increment
Source/Destination address = 0
Transfer size = 0, Linked pointer = 0
All interrupts masked
Infinite loop disabled, burst option = standard size, handshake option = one burst
15.3.4. Setup DMA Channel
Call the
dma_mgr_setup_channelAPI to apply the configuration to the DMA channel. This API writes all the configuration fields to the hardware registers and optionally configures DMAMUX.Prototype of the
dma_mgr_setup_channelAPI:hpm_stat_t dma_mgr_setup_channel(const dma_resource_t *resource, dma_mgr_chn_conf_t *config);
Return Values:
status_success: Channel successfully configured.status_invalid_argument: Invalid parameter.
15.3.5. Install DMA Transfer Complete Callback
Call the
dma_mgr_install_chn_tc_callbackAPI to register a callback for DMA transfer completion. This callback is invoked in the DMA ISR when the transfer is complete.Prototype of the
dma_mgr_install_chn_tc_callbackAPI:hpm_stat_t dma_mgr_install_chn_tc_callback(const dma_resource_t *resource, dma_mgr_chn_cb_t callback, void *user_data);
Return Values:
status_success: Callback successfully installed.status_invalid_argument: Invalid parameter.
Similarly, you can also register callbacks for half transfer complete, error, and abort events:
hpm_stat_t dma_mgr_install_chn_half_tc_callback(const dma_resource_t *resource, dma_mgr_chn_cb_t callback, void *user_data); hpm_stat_t dma_mgr_install_chn_error_callback(const dma_resource_t *resource, dma_mgr_chn_cb_t callback, void *user_data); hpm_stat_t dma_mgr_install_chn_abort_callback(const dma_resource_t *resource, dma_mgr_chn_cb_t callback, void *user_data);
15.3.6. Enable DMA Channel and Start Transfer
Call the
dma_mgr_enable_chn_irqAPI to enable the required interrupt sources for the channel.Prototype of the
dma_mgr_enable_chn_irqAPI:hpm_stat_t dma_mgr_enable_chn_irq(const dma_resource_t *resource, uint32_t irq_mask);
irq_maskcan be a combination ofDMA_MGR_INTERRUPT_MASK_TC,DMA_MGR_INTERRUPT_MASK_HALF_TC,DMA_MGR_INTERRUPT_MASK_ERROR,DMA_MGR_INTERRUPT_MASK_ABORT.
Call the
dma_mgr_enable_dma_irq_with_priorityAPI to enable the global DMA interrupt with a specified priority.Prototype of the
dma_mgr_enable_dma_irq_with_priorityAPI:hpm_stat_t dma_mgr_enable_dma_irq_with_priority(const dma_resource_t *resource, uint32_t priority);
Call the
dma_mgr_enable_channelAPI to start the DMA transfer.Prototype of the
dma_mgr_enable_channelAPI:hpm_stat_t dma_mgr_enable_channel(const dma_resource_t *resource);
Return Values:
status_success: Channel successfully enabled and transfer started.status_invalid_argument: Invalid parameter.
15.3.7. Complete DMA Transfer Example
The following is a typical DMA transfer flow using the DMA Manager component:
#include "hpm_dma_mgr.h"
#include "hpm_uart_drv.h"
ATTR_PLACE_AT_NONCACHEABLE static char tx_buff[256];
static volatile bool tx_dma_complete;
/* DMA transfer complete callback */
static void tx_dma_complete_cb(DMA_Type *base, uint32_t channel, void *user_data)
{
(void)base;
(void)channel;
(void)user_data;
tx_dma_complete = true;
}
void uart_dma_send_example(void)
{
dma_mgr_chn_conf_t chn_config;
dma_resource_t tx_dma_resource;
/* 1. Initialize DMA Manager */
dma_mgr_init();
/* 2. Request a DMA channel */
if (dma_mgr_request_resource(&tx_dma_resource) != status_success) {
printf("Failed to request DMA resource\n");
return;
}
/* 3. Get default channel config */
dma_mgr_get_default_chn_config(&chn_config);
/* 4. Configure DMA channel for UART TX */
chn_config.src_width = DMA_MGR_TRANSFER_WIDTH_BYTE;
chn_config.dst_width = DMA_MGR_TRANSFER_WIDTH_BYTE;
chn_config.src_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)tx_buff);
chn_config.dst_addr = (uint32_t)&HPM_UART0->DATA;
chn_config.src_mode = DMA_MGR_HANDSHAKE_MODE_NORMAL;
chn_config.dst_mode = DMA_MGR_HANDSHAKE_MODE_HANDSHAKE;
chn_config.src_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_INCREMENT;
chn_config.dst_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_FIXED;
chn_config.size_in_byte = sizeof(tx_buff);
chn_config.en_dmamux = true;
chn_config.dmamux_src = HPM_DMA_SRC_UART0_TX;
chn_config.interrupt_mask = DMA_MGR_INTERRUPT_MASK_NONE;
dma_mgr_setup_channel(&tx_dma_resource, &chn_config);
/* 5. Install transfer complete callback */
dma_mgr_install_chn_tc_callback(&tx_dma_resource, tx_dma_complete_cb, NULL);
/* 6. Enable channel interrupt and global DMA interrupt */
dma_mgr_enable_chn_irq(&tx_dma_resource, DMA_MGR_INTERRUPT_MASK_TC);
dma_mgr_enable_dma_irq_with_priority(&tx_dma_resource, 1);
/* 7. Start DMA transfer */
dma_mgr_enable_channel(&tx_dma_resource);
/* 8. Wait for transfer completion */
while (!tx_dma_complete) {
}
printf("UART DMA transfer complete\n");
}
15.3.8. Channel Control APIs
Disable Channel: Stop DMA channel transfer.
hpm_stat_t dma_mgr_disable_channel(const dma_resource_t *resource);
Abort Transfer: Forcefully abort a DMA channel transfer.
hpm_stat_t dma_mgr_abort_chn_transfer(const dma_resource_t *resource);
Check Transfer Status: Query the current status of a DMA channel.
hpm_stat_t dma_mgr_check_chn_transfer_status(const dma_resource_t *resource, uint32_t *status);
Get Remaining Transfer Size: Query the remaining bytes to be transferred.
hpm_stat_t dma_mgr_get_chn_remaining_transize(const dma_resource_t *resource, uint32_t *size);
Set Transfer Size: Modify the transfer size of a channel.
hpm_stat_t dma_mgr_set_chn_transize(const dma_resource_t *resource, uint32_t size);
Release DMA Resource: Release the DMA channel back to the manager.
hpm_stat_t dma_mgr_release_resource(const dma_resource_t *resource);
15.3.9. Per-Field Configuration APIs
If you do not wish to use the one-time dma_mgr_setup_channel, you can also configure each field individually:
dma_mgr_set_chn_src_addr(&resource, src_addr);
dma_mgr_set_chn_dst_addr(&resource, dst_addr);
dma_mgr_set_chn_src_width(&resource, width);
dma_mgr_set_chn_dst_width(&resource, width);
dma_mgr_set_chn_src_work_mode(&resource, mode);
dma_mgr_set_chn_dst_work_mode(&resource, mode);
dma_mgr_set_chn_src_addr_ctrl(&resource, addr_ctrl);
dma_mgr_set_chn_dst_addr_ctrl(&resource, addr_ctrl);
dma_mgr_set_chn_src_burst_size(&resource, burstsize);
dma_mgr_set_chn_transize(&resource, size);
dma_mgr_set_chn_priority(&resource, priority);
dma_mgr_set_chn_infinite_loop_mode(&resource, enable);
dma_mgr_set_chn_handshake_option(&resource, handshake_opt);
Note
The DMA Manager is a foundational component in the SDK, used by the following higher-level components:
components/spi: The SPI component manages SPI DMA transfers via DMA Manager.components/i2c: The I2C component manages I2C DMA transfers via DMA Manager.components/serial_nor: The Serial NOR component manages Flash DMA transfers via DMA Manager.components/i2s_over_spi: The I2S over SPI component manages audio DMA transfers via DMA Manager.