Microchip® Advanced Software Framework

Quick Start Guide for Memory to Memory Data Transfer Using DMAC

The supported board list:

  • SAM D21 Xplained Pro
  • SAM R21 Xplained Pro
  • SAM D11 Xplained Pro
  • SAM L21 Xplained Pro
  • SAM L22 Xplained Pro
  • SAM DA1 Xplained Pro
  • SAM HA1G16A Xplained Pro

In this use case, the DMAC is configured for:

  • Moving data from memory to memory
  • Using software trigger
  • Using DMA priority level 0
  • Transaction as DMA trigger action
  • No action on input events
  • Output event not enabled

Setup

Prerequisites

There are no special setup requirements for this use-case.

Code

Copy-paste the following setup code to your user application:

#define DATA_LENGTH (512)
static uint8_t source_memory[DATA_LENGTH];
static uint8_t destination_memory[DATA_LENGTH];
static volatile bool transfer_is_done = false;
DmacDescriptor example_descriptor SECTION_DMAC_DESCRIPTOR;
static void transfer_done(struct dma_resource* const resource )
{
transfer_is_done = true;
}
static void configure_dma_resource(struct dma_resource *resource)
{
struct dma_resource_config config;
dma_allocate(resource, &config);
}
static void setup_transfer_descriptor(DmacDescriptor *descriptor )
{
struct dma_descriptor_config descriptor_config;
descriptor_config.block_transfer_count = sizeof(source_memory);
descriptor_config.source_address = (uint32_t)source_memory +
sizeof(source_memory);
descriptor_config.destination_address = (uint32_t)destination_memory +
sizeof(source_memory);
dma_descriptor_create(descriptor, &descriptor_config);
}

Add the below section to user application initialization (typically the start of main()):

configure_dma_resource(&example_resource);
setup_transfer_descriptor(&example_descriptor);
dma_add_descriptor(&example_resource, &example_descriptor);
dma_register_callback(&example_resource, transfer_done,
for (uint32_t i = 0; i < DATA_LENGTH; i++) {
source_memory[i] = i;
}

Workflow

  1. Create a DMA resource configuration structure, which can be filled out to adjust the configuration of a single DMA transfer.
    struct dma_resource_config config;
  2. Initialize the DMA resource configuration struct with the module's default values.
    Note
    This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
  3. Allocate a DMA resource with the configurations.
    dma_allocate(resource, &config);
  4. Declare a DMA transfer descriptor configuration structure, which can be filled out to adjust the configuration of a single DMA transfer.
    struct dma_descriptor_config descriptor_config;
  5. Initialize the DMA transfer descriptor configuration struct with the module's default values.
    Note
    This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
  6. Set the specific parameters for a DMA transfer with transfer size, source address, and destination address. In this example, we have enabled the source and destination address increment. The source and destination addresses to be stored into descriptor_config must correspond to the end of the transfer.

    descriptor_config.block_transfer_count = sizeof(source_memory);
    descriptor_config.source_address = (uint32_t)source_memory +
    sizeof(source_memory);
    descriptor_config.destination_address = (uint32_t)destination_memory +
    sizeof(source_memory);
  7. Create the DMA transfer descriptor.
    dma_descriptor_create(descriptor, &descriptor_config);
  8. Add the DMA transfer descriptor to the allocated DMA resource.
    dma_add_descriptor(&example_resource, &example_descriptor);
  9. Register a callback to indicate transfer status.
    dma_register_callback(&example_resource, transfer_done,
  10. Set the transfer done flag in the registered callback function.
    static void transfer_done(struct dma_resource* const resource )
    {
    transfer_is_done = true;
    }
  11. Enable the registered callbacks.

Use Case

Code

Add the following code at the start of main():

struct dma_resource example_resource;

Copy the following code to your user application:

dma_start_transfer_job(&example_resource);
dma_trigger_transfer(&example_resource);
while (!transfer_is_done) {
/* Wait for transfer done */
}
while (true) {
/* Nothing to do */
}

Workflow

  1. Start the DMA transfer job with the allocated DMA resource and transfer descriptor.
    dma_start_transfer_job(&example_resource);
  2. Set the software trigger for the DMA channel. This can be done before or after the DMA job is started. Note that all transfers needs a trigger to start.
    dma_trigger_transfer(&example_resource);
  3. Waiting for the setting of the transfer done flag.
    while (!transfer_is_done) {
    /* Wait for transfer done */
    }