This driver for Atmel® | SMART ARMĀ®-based microcontrollers provides an interface for the configuration and management of the Direct Memory Access Controller(DMAC) module within the device.
The DMAC can transfer data between memories and peripherals, and thus off-load these tasks from the CPU. The module supports peripheral to peripheral, peripheral to memory, memory to peripheral, and memory to memory transfers.
The following peripheral is used by the DMAC Driver:
The following devices can use this module:
The outline of this documentation is as follows:
There are no prerequisites for this module.
SAM devices with DMAC enables high data transfer rates with minimum CPU intervention and frees up CPU time. With access to all peripherals, the DMAC can handle automatic transfer of data to/from modules. It supports static and incremental addressing for both source and destination.
The DMAC when used with Event System or peripheral triggers, provides a considerable advantage by reducing the power consumption and performing data transfer in the background. For example, if the ADC is configured to generate an event, it can trigger the DMAC to transfer the data into another peripheral or SRAM. The CPU can remain in sleep during this time to reduce the power consumption.
Device | Dma channel number |
---|---|
SAM D21/R21/C20/C21 | 12 |
SAM D09/D10/D11 | 6 |
SAM L21,SAMR30/R34/R35 | 16 |
SAM R34/R35 | 12 |
The DMA channel operation can be suspended at any time by software, by events from event system, or after selectable descriptor execution. The operation can be resumed by software or by events from the event system. The DMAC driver for SAM supports four types of transfers such as peripheral to peripheral, peripheral to memory, memory to peripheral, and memory to memory.
The basic transfer unit is a beat, which is defined as a single bus access. There can be multiple beats in a single block transfer and multiple block transfers in a DMA transaction. DMA transfer is based on descriptors, which holds transfer properties such as the source and destination addresses, transfer counter, and other additional transfer control information. The descriptors can be static or linked. When static, a single block transfer is performed. When linked, a number of transfer descriptors can be used to enable multiple block transfers within a single DMA transaction.
The implementation of the DMA driver is based on the idea that the DMA channel is a finite resource of entities with the same abilities. A DMA channel resource is able to move a defined set of data from a source address to destination address triggered by a transfer trigger. On the SAM devices there are 12 DMA resources available for allocation. Each of these DMA resources can trigger interrupt callback routines and peripheral events. The other main features are:
A simplified block diagram of the DMA Resource can be seen in the figure below.
Driver Feature Macro | Supported devices |
---|---|
FEATURE_DMA_CHANNEL_STANDBY | SAM L21/L22/C20/C21/R30/R34/R35 |
Name | Description |
---|---|
Beat | It is a single bus access by the DMAC. Configurable as 8-bit, 16-bit, or 32-bit. |
Burst | It is a transfer of n-beats (n=1,4,8,16). For the DMAC module in SAM, the burst size is one beat. Arbitration takes place each time a burst transfer is completed. |
Block transfer | A single block transfer is a configurable number of (1 to 64k) beat transfers |
The DMAC in each device consists of several DMA channels, which along with the transfer descriptors defines the data transfer properties.
With a successful DMA resource allocation, a dedicated DMA channel will be assigned. The channel will be occupied until the DMA resource is freed. A DMA resource handle is used to identify the specific DMA resource. When there are multiple channels with active requests, the arbiter prioritizes the channels requesting access to the bus.
DMA transfer can be started only when a DMA transfer request is acknowledged/granted by the arbiter. A transfer request can be triggered from software, peripheral, or an event. There are dedicated source trigger selections for each DMA channel usage.
The transfer descriptor resides in the SRAM and defines these channel properties.
Field name | Field width |
---|---|
Descriptor Next Address | 32 bits |
Destination Address | 32 bits |
Source Address | 32 bits |
Block Transfer Counter | 16 bits |
Block Transfer Control | 16 bits |
Before starting a transfer, at least one descriptor should be configured. After a successful allocation of a DMA channel, the transfer descriptor can be added with a call to dma_add_descriptor(). If there is a transfer descriptor already allocated to the DMA resource, the descriptor will be linked to the next descriptor address.
Both an interrupt callback and an peripheral event can be triggered by the DMA transfer. Three types of callbacks are supported by the DMA driver: transfer complete, channel suspend, and transfer error. Each of these callback types can be registered and enabled for each channel independently through the DMA driver API.
The DMAC module can also generate events on transfer complete. Event generation is enabled through the DMA channel, event channel configuration, and event user multiplexing is done through the events driver.
The DMAC can generate events in the below cases:
There are no special considerations for this module.
For extra information, see Extra Information for DMAC Driver. This includes:
For a list of examples related to this driver, see Examples for DMAC Driver.
Data Structures | |
struct | dma_descriptor_config |
DMA transfer descriptor configuration. More... | |
struct | dma_events_config |
Configurations for DMA events. More... | |
struct | dma_resource |
Structure for DMA transfer resource. More... | |
struct | dma_resource_config |
DMA configurations for transfer. More... | |
Macros | |
#define | DMA_INVALID_CHANNEL 0xff |
DMA invalid channel number. More... | |
Typedefs | |
typedef void(* | dma_callback_t )(struct dma_resource *const resource) |
Type definition for a DMA resource callback function. More... | |
Functions | |
void | dma_abort_job (struct dma_resource *resource) |
Abort a DMA transfer. More... | |
enum status_code | dma_add_descriptor (struct dma_resource *resource, DmacDescriptor *descriptor) |
Add a DMA transfer descriptor to a DMA resource. More... | |
enum status_code | dma_allocate (struct dma_resource *resource, struct dma_resource_config *config) |
Allocate a DMA with configurations. More... | |
void | dma_descriptor_create (DmacDescriptor *descriptor, struct dma_descriptor_config *config) |
Create a DMA transfer descriptor with configurations. More... | |
static void | dma_descriptor_get_config_defaults (struct dma_descriptor_config *config) |
Initializes DMA transfer configuration with predefined default values. More... | |
static void | dma_disable_callback (struct dma_resource *resource, enum dma_callback_type type) |
Disable a callback function for a dedicated DMA resource. More... | |
static void | dma_enable_callback (struct dma_resource *resource, enum dma_callback_type type) |
Enable a callback function for a dedicated DMA resource. More... | |
enum status_code | dma_free (struct dma_resource *resource) |
Free an allocated DMA resource. More... | |
void | dma_get_config_defaults (struct dma_resource_config *config) |
Initializes config with predefined default values. More... | |
static enum status_code | dma_get_job_status (struct dma_resource *resource) |
Get DMA resource status. More... | |
static bool | dma_is_busy (struct dma_resource *resource) |
Check if the given DMA resource is busy. More... | |
static void | dma_register_callback (struct dma_resource *resource, dma_callback_t callback, enum dma_callback_type type) |
Register a callback function for a dedicated DMA resource. More... | |
static void | dma_reset_descriptor (struct dma_resource *resource) |
Reset DMA descriptor. More... | |
void | dma_resume_job (struct dma_resource *resource) |
Resume a suspended DMA transfer. More... | |
enum status_code | dma_start_transfer_job (struct dma_resource *resource) |
Start a DMA transfer. More... | |
void | dma_suspend_job (struct dma_resource *resource) |
Suspend a DMA transfer. More... | |
static void | dma_trigger_transfer (struct dma_resource *resource) |
Will set a software trigger for resource. More... | |
static void | dma_unregister_callback (struct dma_resource *resource, enum dma_callback_type type) |
Unregister a callback function for a dedicated DMA resource. More... | |
static void | dma_update_descriptor (struct dma_resource *resource, DmacDescriptor *descriptor) |
Update DMA descriptor. More... | |
Variables | |
DmacDescriptor | descriptor_section [CONF_MAX_USED_CHANNEL_NUM] |
ExInitial description section. More... | |
uint8_t | g_chan_interrupt_flag [CONF_MAX_USED_CHANNEL_NUM] |
#define DMA_INVALID_CHANNEL 0xff |
DMA invalid channel number.
Referenced by _dma_find_first_free_channel_and_allocate(), dma_abort_job(), dma_allocate(), dma_free(), dma_resume_job(), dma_start_transfer_job(), and dma_suspend_job().
typedef void(* dma_callback_t)(struct dma_resource *const resource) |
Type definition for a DMA resource callback function.
Address increment step size.
These bits select the address increment step size. The setting apply to source or destination address, depending on STEPSEL setting.
enum dma_beat_size |
enum dma_block_action |
Block action definitions.
enum dma_callback_type |
Callback types for DMA callback driver.
DMA input actions.
enum dma_priority_level |
enum dma_step_selection |
void dma_abort_job | ( | struct dma_resource * | resource | ) |
Abort a DMA transfer.
This function will abort a DMA transfer. The DMA channel used for the DMA resource will be disabled. The block transfer count will also be calculated and written to the DMA resource structure.
[in,out] | resource | Pointer to the DMA resource |
References Assert, dma_resource::channel_id, descriptor_section, DMA_INVALID_CHANNEL, dma_resource::job_status, STATUS_ABORTED, system_interrupt_enter_critical_section(), system_interrupt_leave_critical_section(), and dma_resource::transfered_size.
enum status_code dma_add_descriptor | ( | struct dma_resource * | resource, |
DmacDescriptor * | descriptor | ||
) |
Add a DMA transfer descriptor to a DMA resource.
This function will add a DMA transfer descriptor to a DMA resource. If there was a transfer descriptor already allocated to the DMA resource, the descriptor will be linked to the next descriptor address.
[in] | resource | Pointer to the DMA resource |
[in] | descriptor | Pointer to the transfer descriptor |
STATUS_OK | The descriptor is added to the DMA resource |
STATUS_BUSY | The DMA resource was busy and the descriptor is not added |
References dma_resource::descriptor, dma_resource::job_status, STATUS_BUSY, and STATUS_OK.
Referenced by configure_dma_aes_rd(), and configure_dma_aes_wr().
enum status_code dma_allocate | ( | struct dma_resource * | resource, |
struct dma_resource_config * | config | ||
) |
Allocate a DMA with configurations.
This function will allocate a proper channel for a DMA transfer request.
[in,out] | dma_resource | Pointer to a DMA resource instance |
[in] | transfer_config | Configurations of the DMA transfer |
STATUS_OK | The DMA resource was allocated successfully |
STATUS_ERR_NOT_FOUND | DMA resource allocation failed |
Perform a reset for the allocated channel
Configure the DMA control,channel registers and descriptors here
References _dma_active_resource, _dma_find_first_free_channel_and_allocate(), _dma_module::_dma_init, _dma_set_config(), Assert, dma_resource::channel_id, dma_resource::descriptor, descriptor_section, DMA_INVALID_CHANNEL, STATUS_ERR_NOT_FOUND, STATUS_OK, system_ahb_clock_set_mask(), system_apb_clock_set_mask(), SYSTEM_CLOCK_APB_APBB, system_interrupt_enter_critical_section(), and system_interrupt_leave_critical_section().
Referenced by configure_dma_aes_rd(), and configure_dma_aes_wr().
void dma_descriptor_create | ( | DmacDescriptor * | descriptor, |
struct dma_descriptor_config * | config | ||
) |
Create a DMA transfer descriptor with configurations.
This function will set the transfer configurations to the DMA transfer descriptor.
[in] | descriptor | Pointer to the DMA transfer descriptor |
[in] | config | Pointer to the descriptor configuration structure |
References dma_descriptor_config::beat_size, dma_descriptor_config::block_action, dma_descriptor_config::block_transfer_count, dma_descriptor_config::descriptor_valid, dma_descriptor_config::destination_address, dma_descriptor_config::dst_increment_enable, dma_descriptor_config::event_output_selection, dma_descriptor_config::next_descriptor_address, dma_descriptor_config::source_address, dma_descriptor_config::src_increment_enable, dma_descriptor_config::step_selection, and dma_descriptor_config::step_size.
Referenced by configure_dma_aes_rd(), and configure_dma_aes_wr().
|
inlinestatic |
Initializes DMA transfer configuration with predefined default values.
This function will initialize a given DMA descriptor configuration structure to a set of known default values. This function should be called on any new instance of the configuration structure before being modified by the user application.
The default configuration is as follows:
[out] | config | Pointer to the configuration |
Next descriptor address set to 0
References Assert, dma_descriptor_config::beat_size, dma_descriptor_config::block_action, dma_descriptor_config::block_transfer_count, dma_descriptor_config::descriptor_valid, dma_descriptor_config::destination_address, DMA_ADDRESS_INCREMENT_STEP_SIZE_1, DMA_BEAT_SIZE_BYTE, DMA_BLOCK_ACTION_NOACT, DMA_EVENT_OUTPUT_DISABLE, DMA_STEPSEL_DST, dma_descriptor_config::dst_increment_enable, dma_descriptor_config::event_output_selection, dma_descriptor_config::next_descriptor_address, dma_descriptor_config::source_address, dma_descriptor_config::src_increment_enable, dma_descriptor_config::step_selection, and dma_descriptor_config::step_size.
Referenced by configure_dma_aes_rd(), and configure_dma_aes_wr().
|
inlinestatic |
Disable a callback function for a dedicated DMA resource.
[in] | resource | Pointer to the DMA resource |
[in] | type | Callback function type |
References Assert, dma_resource::callback_enable, and dma_resource::channel_id.
|
inlinestatic |
Enable a callback function for a dedicated DMA resource.
[in] | resource | Pointer to the DMA resource |
[in] | type | Callback function type |
References Assert, dma_resource::callback_enable, and dma_resource::channel_id.
enum status_code dma_free | ( | struct dma_resource * | resource | ) |
Free an allocated DMA resource.
This function will free an allocated DMA resource.
[in,out] | resource | Pointer to the DMA resource |
STATUS_OK | The DMA resource was freed successfully |
STATUS_BUSY | The DMA resource was busy and can't be freed |
STATUS_ERR_NOT_INITIALIZED | DMA resource was not initialized |
References _dma_active_resource, _dma_release_channel(), _dma_module::allocated_channels, Assert, dma_resource::channel_id, DMA_INVALID_CHANNEL, dma_is_busy(), STATUS_BUSY, STATUS_ERR_NOT_INITIALIZED, STATUS_OK, system_interrupt_enter_critical_section(), and system_interrupt_leave_critical_section().
void dma_get_config_defaults | ( | struct dma_resource_config * | config | ) |
Initializes config with predefined default values.
This function will initialize a given DMA configuration structure to a set of known default values. This function should be called on any new instance of the configuration structure before being modified by the user application.
The default configuration is as follows:
[out] | config | Pointer to the configuration |
References Assert, DMA_EVENT_INPUT_NOACT, DMA_PRIORITY_LEVEL_0, DMA_TRIGGER_ACTION_TRANSACTION, dma_resource_config::event_config, dma_events_config::event_output_enable, dma_events_config::input_action, dma_resource_config::peripheral_trigger, dma_resource_config::priority, and dma_resource_config::trigger_action.
Referenced by configure_dma_aes_rd(), and configure_dma_aes_wr().
|
inlinestatic |
Get DMA resource status.
[in] | resource | Pointer to the DMA resource |
References Assert, and dma_resource::job_status.
|
inlinestatic |
Check if the given DMA resource is busy.
[in] | resource | Pointer to the DMA resource |
true | The DMA resource has an on-going transfer |
false | The DMA resource is not busy |
References Assert, dma_resource::job_status, and STATUS_BUSY.
Referenced by dma_free().
|
inlinestatic |
Register a callback function for a dedicated DMA resource.
There are three types of callback functions, which can be registered:
[in] | resource | Pointer to the DMA resource |
[in] | callback | Pointer to the callback function |
[in] | type | Callback function type |
References Assert, and dma_resource::callback.
|
inlinestatic |
Reset DMA descriptor.
This function will clear the DESCADDR register of an allocated DMA resource.
References Assert, and dma_resource::descriptor.
void dma_resume_job | ( | struct dma_resource * | resource | ) |
Resume a suspended DMA transfer.
This function try to resume a suspended transfer of a DMA resource.
[in] | resource | Pointer to the DMA resource |
References Assert, dma_resource::channel_id, DMA_INVALID_CHANNEL, dma_resource::job_status, MAX_JOB_RESUME_COUNT, STATUS_BUSY, STATUS_ERR_TIMEOUT, STATUS_SUSPEND, system_interrupt_enter_critical_section(), and system_interrupt_leave_critical_section().
enum status_code dma_start_transfer_job | ( | struct dma_resource * | resource | ) |
Start a DMA transfer.
This function will start a DMA transfer through an allocated DMA resource.
[in,out] | resource | Pointer to the DMA resource |
STATUS_OK | The transfer was started successfully |
STATUS_BUSY | The DMA resource was busy and the transfer was not started |
STATUS_ERR_INVALID_ARG | Transfer size is 0 and transfer was not started |
References Assert, dma_resource::channel_id, dma_resource::descriptor, descriptor_section, DMA_INVALID_CHANNEL, g_chan_interrupt_flag, dma_resource::job_status, STATUS_BUSY, STATUS_ERR_INVALID_ARG, STATUS_OK, system_interrupt_enable(), system_interrupt_enter_critical_section(), system_interrupt_leave_critical_section(), and SYSTEM_INTERRUPT_MODULE_DMA.
Referenced by run_ecb_mode_test_dma().
void dma_suspend_job | ( | struct dma_resource * | resource | ) |
Suspend a DMA transfer.
This function will request to suspend the transfer of the DMA resource. The channel is kept enabled, can receive transfer triggers (the transfer pending bit will be set), but will be removed from the arbitration scheme. The channel operation can be resumed by calling dma_resume_job().
[in] | resource | Pointer to the DMA resource |
References Assert, dma_resource::channel_id, DMA_INVALID_CHANNEL, system_interrupt_enter_critical_section(), and system_interrupt_leave_critical_section().
|
inlinestatic |
Will set a software trigger for resource.
This function is used to set a software trigger on the DMA channel associated with resource. If a trigger is already pending no new trigger will be generated for the channel.
[in] | resource | Pointer to the DMA resource |
References Assert, and dma_resource::channel_id.
|
inlinestatic |
Unregister a callback function for a dedicated DMA resource.
There are three types of callback functions:
The application can unregister any of the callback functions which are already registered and are no longer needed.
[in] | resource | Pointer to the DMA resource |
[in] | type | Callback function type |
References Assert, and dma_resource::callback.
|
inlinestatic |
Update DMA descriptor.
This function can update the descriptor of an allocated DMA resource.
References Assert, and dma_resource::descriptor.
DmacDescriptor descriptor_section[CONF_MAX_USED_CHANNEL_NUM] |
ExInitial description section.
Referenced by dma_abort_job(), dma_allocate(), dma_start_transfer_job(), and DMAC_Handler().
uint8_t g_chan_interrupt_flag[CONF_MAX_USED_CHANNEL_NUM] |
Referenced by dma_start_transfer_job().