Microchip® Advanced Software Framework

Use case #1 - Interrupt for a completed DMA transfer.

This use case shows how to set up an interrupt for when a DMA transfer is completed.

In this use case, the DMA is configured for:

  • Interrupt level: Low
  • Burst length: 1 byte
  • Transfer count: 1024
  • Source: Buffer located in RAM
  • Destination: Buffer located in RAM
  • Source and destination address reload mode: End of transaction
  • Source and destination address direction mode: Increment

In this use case data is copied from the source buffer to the destination buffer in 1-byte bursts, until all data in the block is transferred. This example is analogus to a memcpy(destination, source, sizeof(source)) operation performed in hardware asynchronously to the CPU.

Each time the DMA transfer completes, a user-specified callback function is run to notify the user application.

Setup steps

Prerequisites

For the setup code of this use case to work, the following must be added to the project:

  1. System Clock Manager Service (sysclk)
  2. Sleep Manager Service
  3. PMIC Driver

A callback function, called dma_transfer_done, must also be provided by the user application:

static void dma_transfer_done(enum dma_channel_status status)
{
// ...
}

Example code

Add to application C-file:

#define DMA_CHANNEL 0
#define DMA_BUFFER_SIZE 1024
static uint8_t source[DMA_BUFFER_SIZE];
static uint8_t destination[DMA_BUFFER_SIZE];
static void dma_init(void)
{
struct dma_channel_config dmach_conf;
memset(&dmach_conf, 0, sizeof(dmach_conf));
dma_channel_set_burst_length(&dmach_conf, DMA_CH_BURSTLEN_1BYTE_gc);
dma_channel_set_transfer_count(&dmach_conf, DMA_BUFFER_SIZE);
DMA_CH_SRCRELOAD_TRANSACTION_gc);
DMA_CH_DESTRELOAD_TRANSACTION_gc);
dma_channel_set_src_dir_mode(&dmach_conf, DMA_CH_SRCDIR_INC_gc);
(uint16_t)(uintptr_t)source);
dma_channel_set_dest_dir_mode(&dmach_conf, DMA_CH_DESTDIR_INC_gc);
(uint16_t)(uintptr_t)destination);
dma_set_callback(DMA_CHANNEL, dma_transfer_done);
dma_channel_write_config(DMA_CHANNEL, &dmach_conf);
dma_channel_enable(DMA_CHANNEL);
}

Add to main():

Workflow

  1. Define the DMA channel that will be used for the transfer for convenience:
    • #define DMA_CHANNEL 0
  2. Define the array length that will be the used for the source and destination buffers located in RAM:
    • #define DMA_BUFFER_SIZE 1024
  3. Create a pair of global arrays that will hold the source and destination data copied by the DMA controller channel when it is triggered:
    • static uint8_t source[DMA_BUFFER_SIZE];
      static uint8_t destination[DMA_BUFFER_SIZE];
  4. Create a function dma_init() to intialize the DMA:
    • static void dma_init(void)
      {
      // ...
      }
  5. Create config struct for DMA channel:
  6. Make sure the configuration structure is zeroed out to ensure that all values are reset to their defaults before writing new values:
    • memset(&dmach_conf, 0, sizeof(dmach_conf));
  7. Configure the DMA channel for single byte bursts, with a transfer length equal to the size of the source and destination buffers:
  8. Configure the DMA channel to reset the source and destination addresses at the end of the complete transaction (i.e. after DMA_BUFFER_SIZE bytes copied):
  9. Configure the DMA channel to increment the source and destination addresses after each byte transferred:
  10. Configure the DMA channel source and destination addresses:
  11. Enable the DMA module so that channels can be configured in it:
    • Attention
      Calling dma_enable() will result in a soft-reset of the entire DMA module, clearing all channel configurations. If more than one DMA channel is to be configured, this function should be called only once in the application initialization procedure only.
  12. Set up the DMA channel interrupt to run at low interrupt priority, and link it to the user created dma_transfer_done() function:
  13. Write the DMA channel configuration to the DMA and enable it so that it can be triggered to start the transfer:
  14. Initialize the clock system, PMIC driver and Sleep Manager service:
  15. Call our DMA init function:
    • dma_init();
  16. Enable global processing of interrupts:

Usage steps

Example code

Add to, e.g., main loop in application C-file:

Workflow

  1. Start the DMA transfer:
  2. Sleep while waiting for the transfer to complete: