Driver API for ARM CoreLink DMA Controller.
The DMA is a high-performance Direct Memory Access controller that supports multiple independent channels with advanced features including 2D transfers, hardware triggering, and scatter-gather operations.
Features:
- Multiple DMA channels per controller instance
- 1D and 2D memory transfer operations
- Memory-to-memory, memory-to-peripheral, and peripheral-to-memory transfers
- Hardware and software trigger support
- Scatter-gather and linked list operations
- Security and privilege level control
- Interrupt-driven operation with per-channel callbacks
- Automatic error recovery and detailed error reporting
- FIFO depth optimization per channel
- Note
- DMA APIs are divided into two categories:
- High-level APIs: These provide simplified interfaces for common DMA operations such as memory-to-memory copies and peripheral transfers. They are ideal for application-level development.
- Low-level APIs: These provide granular control over the DMA hardware, allowing for fine-tuned configuration of descriptors, triggers, and advanced features. They are suitable for system-level programming and performance optimization.
- Warning
- Mixing high-level and low-level DMA APIs for the same channel is not recommended. Each has different expectations for channel state and resource management. Use only one model per channel to avoid undefined behavior.
Configuration Considerations
To initialize and use the DMA driver:
- Call dma_init to initialize the DMA controller instance.
- Request a channel using dma_channel_request or dma_request_specific_channel.
- Configure the transfer using dma_prepare_transfer. For more complex scatter-gather operations, create and link descriptors using dma_create_descriptor and dma_link_descriptors.
- Start the transfer using dma_start_transfer or dma_start_descriptor_chain.
- Monitor the transfer status using dma_get_status or by providing a callback in the channel configuration.
- Once the transfer is complete, release the channel using dma_free_channel.
dma_init
Initialize the DMA hardware and internal driver structures for the specified DMA instance.
LOG_ERROR(LOG_MOD_DMA, "Init failed.\n");
}
dma_deinit
Deinitializes the DMA hardware and releases any resources held by the driver for the specified DMA instance.
LOG_ERROR(LOG_MOD_DMA, "De-init failed.\n");
}
dma_prepare_transfer
Configures a DMA channel for a specific transfer type. This includes setting source and destination addresses, transfer size, and other parameters.
.config_1d = {
.src_addr = (uint32_t)dma_src_buf,
.dest_addr = (uint32_t)dma_dest_buf,
.transfer_size = DMA_TRANSFER_SIZE,
.src_x_increment = 1,
.dest_x_increment = 1,
.fill_value = 0,
.template_config = { 0 },
.link_addr = 0
},
.priority = 0,
.src_trigger = { 0 },
.dest_trigger = { 0 },
.auto_restart.infinite_restart = 0,
.callback = dma_transfer_callback,
.user_data = NULL
};
LOG_ERROR(LOG_MOD_DMA, "Transfer preparation failed.\n");
}
dma_start_transfer
Initiates a DMA transfer on a pre-configured channel. This is a non-blocking call, and the transfer completion can be monitored via interrupts or polling.
LOG_ERROR(LOG_MOD_DMA, "Enable interrupts failed.\n");
}
LOG_ERROR(LOG_MOD_DMA, "Transfer start failed.\n");
}
dma_create_descriptor
Creates a DMA descriptor for use in scatter-gather operations. The descriptor contains the configuration for a single DMA transfer.
.config_1d = {
.src_addr = (uint32_t)dma_src_buf,
.dest_addr = (uint32_t)dma_dest_buf,
.transfer_size = DMA_TRANSFER_SIZE,
.src_x_increment = 1,
.dest_x_increment = 1,
.fill_value = 0,
.template_config = { 0 },
.link_addr = 0
},
.priority = 0,
.src_trigger = { 0 },
.dest_trigger = { 0 },
.auto_restart.infinite_restart = 0,
.callback = NULL,
.user_data = NULL
};
LOG_ERROR(LOG_MOD_DMA, "Descriptor creation failed.\n");
}
.config_2d = {
.src_addr = (uint32_t)dma_src_2d_buf,
.dest_addr = (uint32_t)dma_dest_2d_buf,
.src_x_size = COLS,
.dest_x_size = COLS,
.src_y_size = ROWS,
.dest_y_size = ROWS,
.src_x_increment = 1,
.dest_x_increment = 1,
.src_y_stride = COLS,
.dest_y_stride = COLS,
.fill_value = 0,
.link_addr = 0
},
.priority = 0,
.src_trigger = { 0 },
.dest_trigger = { 0 },
.auto_restart.infinite_restart = 0,
.callback = NULL,
.user_data = NULL
};
LOG_ERROR(LOG_MOD_DMA, "Descriptor 2 creation failed.\n");
return rc;
}
dma_link_descriptors
Link the two created descriptors. Once the first descriptor is done execting, the descriptor 2 is fetched and run using the Linkaddr.
LOG_ERROR(LOG_MOD_DMA, "Failed to link descriptor 1 -> 2.\n");
return rc;
}
dma_start_descriptor_chain
Starts execution of the descriptor chain by starting the first descriptor in the chain.
LOG_ERROR(LOG_MOD_DMA, "Failed to start descriptor chain.\n");
return rc;
}